am 60415866: [LatinIME] Support MNC permissions.
* commit '604158669b407a40cd0f23538fad4dce5d738f24': [LatinIME] Support MNC permissions.main
commit
992144a8c2
|
@ -18,7 +18,7 @@
|
|||
coreApp="true"
|
||||
package="com.android.inputmethod.latin">
|
||||
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
||||
|
@ -77,6 +77,13 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".permissions.PermissionsActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:exported="false"
|
||||
android:taskAffinity="" >
|
||||
</activity>
|
||||
|
||||
<activity android:name=".setup.SetupWizardActivity"
|
||||
android:theme="@style/platformActivityTheme"
|
||||
android:label="@string/english_ime_name"
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
**
|
||||
** Copyright 2014, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- The array of the text of the important notices displayed on the suggestion strip. -->
|
||||
<string-array name="important_notice_title_array" translatable="false">
|
||||
<!-- empty -->
|
||||
</string-array>
|
||||
<!-- The array of the contents of the important notices. -->
|
||||
<string-array name="important_notice_contents_array" translatable="false">
|
||||
<!-- empty -->
|
||||
</string-array>
|
||||
</resources>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2015 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- The text shown on the suggestion bar to request the contacts permission info. -->
|
||||
<string name="important_notice_suggest_contact_names">Suggest contact names? Touch for info.</string>
|
||||
</resources>
|
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
**
|
||||
** Copyright 2014, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<integer name="config_important_notice_version">0</integer>
|
||||
<!-- Description for option enabling the use by the keyboards of sent/received messages, e-mail and typing history to improve suggestion accuracy [CHAR LIMIT=68] -->
|
||||
<string name="use_personalized_dicts_summary">Learn from your communications and typed data to improve suggestions</string>
|
||||
</resources>
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.inputmethod.latin;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
|
@ -25,6 +26,7 @@ import android.util.Log;
|
|||
import com.android.inputmethod.annotations.ExternallyReferenced;
|
||||
import com.android.inputmethod.latin.ContactsManager.ContactsChangedListener;
|
||||
import com.android.inputmethod.latin.common.StringUtils;
|
||||
import com.android.inputmethod.latin.permissions.PermissionsUtil;
|
||||
import com.android.inputmethod.latin.personalization.AccountUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -108,6 +110,11 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary
|
|||
* Loads data within content providers to the dictionary.
|
||||
*/
|
||||
private void loadDictionaryForUriLocked(final Uri uri) {
|
||||
if (!PermissionsUtil.checkAllPermissionsGranted(
|
||||
mContext, Manifest.permission.READ_CONTACTS)) {
|
||||
Log.i(TAG, "No permission to read contacts. Not loading the Dictionary.");
|
||||
}
|
||||
|
||||
final ArrayList<String> validNames = mContactsManager.getValidNames(uri);
|
||||
for (final String name : validNames) {
|
||||
addNameLocked(name);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.inputmethod.latin;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
|
@ -25,6 +26,7 @@ import android.util.Log;
|
|||
|
||||
import com.android.inputmethod.latin.ContactsManager.ContactsChangedListener;
|
||||
import com.android.inputmethod.latin.define.DebugFlags;
|
||||
import com.android.inputmethod.latin.permissions.PermissionsUtil;
|
||||
import com.android.inputmethod.latin.utils.ExecutorUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -35,10 +37,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
*/
|
||||
public class ContactsContentObserver implements Runnable {
|
||||
private static final String TAG = "ContactsContentObserver";
|
||||
private static AtomicBoolean sRunning = new AtomicBoolean(false);
|
||||
|
||||
private final Context mContext;
|
||||
private final ContactsManager mManager;
|
||||
private final AtomicBoolean mRunning = new AtomicBoolean(false);
|
||||
|
||||
private ContentObserver mContentObserver;
|
||||
private ContactsChangedListener mContactsChangedListener;
|
||||
|
@ -49,6 +51,13 @@ public class ContactsContentObserver implements Runnable {
|
|||
}
|
||||
|
||||
public void registerObserver(final ContactsChangedListener listener) {
|
||||
if (!PermissionsUtil.checkAllPermissionsGranted(
|
||||
mContext, Manifest.permission.READ_CONTACTS)) {
|
||||
Log.i(TAG, "No permission to read contacts. Not registering the observer.");
|
||||
// do nothing if we do not have the permission to read contacts.
|
||||
return;
|
||||
}
|
||||
|
||||
if (DebugFlags.DEBUG_ENABLED) {
|
||||
Log.d(TAG, "registerObserver()");
|
||||
}
|
||||
|
@ -66,7 +75,14 @@ public class ContactsContentObserver implements Runnable {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!sRunning.compareAndSet(false /* expect */, true /* update */)) {
|
||||
if (!PermissionsUtil.checkAllPermissionsGranted(
|
||||
mContext, Manifest.permission.READ_CONTACTS)) {
|
||||
Log.i(TAG, "No permission to read contacts. Not updating the contacts.");
|
||||
unregister();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mRunning.compareAndSet(false /* expect */, true /* update */)) {
|
||||
if (DebugFlags.DEBUG_ENABLED) {
|
||||
Log.d(TAG, "run() : Already running. Don't waste time checking again.");
|
||||
}
|
||||
|
@ -78,10 +94,16 @@ public class ContactsContentObserver implements Runnable {
|
|||
}
|
||||
mContactsChangedListener.onContactsChange();
|
||||
}
|
||||
sRunning.set(false);
|
||||
mRunning.set(false);
|
||||
}
|
||||
|
||||
boolean haveContentsChanged() {
|
||||
if (!PermissionsUtil.checkAllPermissionsGranted(
|
||||
mContext, Manifest.permission.READ_CONTACTS)) {
|
||||
Log.i(TAG, "No permission to read contacts. Marking contacts as not changed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final long startTime = SystemClock.uptimeMillis();
|
||||
final int contactCount = mManager.getContactCount();
|
||||
if (contactCount > ContactsDictionaryConstants.MAX_CONTACTS_PROVIDER_QUERY_LIMIT) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.inputmethod.latin;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
@ -28,6 +29,7 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
|||
import com.android.inputmethod.latin.common.ComposedData;
|
||||
import com.android.inputmethod.latin.common.Constants;
|
||||
import com.android.inputmethod.latin.common.StringUtils;
|
||||
import com.android.inputmethod.latin.permissions.PermissionsUtil;
|
||||
import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
|
||||
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
|
||||
import com.android.inputmethod.latin.utils.ExecutorUtils;
|
||||
|
@ -287,7 +289,11 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
// TODO: Make subDictTypesToUse configurable by resource or a static final list.
|
||||
final HashSet<String> subDictTypesToUse = new HashSet<>();
|
||||
subDictTypesToUse.add(Dictionary.TYPE_USER);
|
||||
if (useContactsDict) {
|
||||
|
||||
// Do not use contacts dictionary if we do not have permissions to read contacts.
|
||||
final boolean contactsPermissionGranted = PermissionsUtil.checkAllPermissionsGranted(
|
||||
context, Manifest.permission.READ_CONTACTS);
|
||||
if (useContactsDict && contactsPermissionGranted) {
|
||||
subDictTypesToUse.add(Dictionary.TYPE_CONTACTS);
|
||||
}
|
||||
if (usePersonalizedDicts) {
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.inputmethod.latin;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
|
||||
import com.android.inputmethod.latin.utils.DialogUtils;
|
||||
import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
|
||||
|
||||
/**
|
||||
* The dialog box that shows the important notice contents.
|
||||
*/
|
||||
public final class ImportantNoticeDialog extends AlertDialog implements OnClickListener {
|
||||
public interface ImportantNoticeDialogListener {
|
||||
public void onUserAcknowledgmentOfImportantNoticeDialog(final int nextVersion);
|
||||
public void onClickSettingsOfImportantNoticeDialog(final int nextVersion);
|
||||
}
|
||||
|
||||
private final ImportantNoticeDialogListener mListener;
|
||||
private final int mNextImportantNoticeVersion;
|
||||
|
||||
public ImportantNoticeDialog(
|
||||
final Context context, final ImportantNoticeDialogListener listener) {
|
||||
super(DialogUtils.getPlatformDialogThemeContext(context));
|
||||
mListener = listener;
|
||||
mNextImportantNoticeVersion = ImportantNoticeUtils.getNextImportantNoticeVersion(context);
|
||||
setMessage(ImportantNoticeUtils.getNextImportantNoticeContents(context));
|
||||
// Create buttons and set listeners.
|
||||
setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok), this);
|
||||
if (shouldHaveSettingsButton()) {
|
||||
setButton(BUTTON_NEGATIVE, context.getString(R.string.go_to_settings), this);
|
||||
}
|
||||
// This dialog is cancelable by pressing back key. See {@link #onBackPress()}.
|
||||
setCancelable(true /* cancelable */);
|
||||
setCanceledOnTouchOutside(false /* cancelable */);
|
||||
}
|
||||
|
||||
private boolean shouldHaveSettingsButton() {
|
||||
return mNextImportantNoticeVersion
|
||||
== ImportantNoticeUtils.VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS;
|
||||
}
|
||||
|
||||
private void userAcknowledged() {
|
||||
ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext());
|
||||
mListener.onUserAcknowledgmentOfImportantNoticeDialog(mNextImportantNoticeVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(final DialogInterface dialog, final int which) {
|
||||
if (shouldHaveSettingsButton() && which == BUTTON_NEGATIVE) {
|
||||
mListener.onClickSettingsOfImportantNoticeDialog(mNextImportantNoticeVersion);
|
||||
}
|
||||
userAcknowledged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
userAcknowledged();
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ import static com.android.inputmethod.latin.common.Constants.ImeOption.FORCE_ASC
|
|||
import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
|
||||
import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
|
@ -73,6 +74,7 @@ import com.android.inputmethod.latin.common.InputPointers;
|
|||
import com.android.inputmethod.latin.define.DebugFlags;
|
||||
import com.android.inputmethod.latin.define.ProductionFlags;
|
||||
import com.android.inputmethod.latin.inputlogic.InputLogic;
|
||||
import com.android.inputmethod.latin.permissions.PermissionsManager;
|
||||
import com.android.inputmethod.latin.personalization.PersonalizationHelper;
|
||||
import com.android.inputmethod.latin.settings.Settings;
|
||||
import com.android.inputmethod.latin.settings.SettingsActivity;
|
||||
|
@ -106,7 +108,7 @@ import javax.annotation.Nonnull;
|
|||
public class LatinIME extends InputMethodService implements KeyboardActionListener,
|
||||
SuggestionStripView.Listener, SuggestionStripViewAccessor,
|
||||
DictionaryFacilitator.DictionaryInitializationListener,
|
||||
ImportantNoticeDialog.ImportantNoticeDialogListener {
|
||||
PermissionsManager.PermissionsResultCallback {
|
||||
static final String TAG = LatinIME.class.getSimpleName();
|
||||
private static final boolean TRACE = false;
|
||||
|
||||
|
@ -1251,18 +1253,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
// pressed.
|
||||
@Override
|
||||
public void showImportantNoticeContents() {
|
||||
showOptionDialog(new ImportantNoticeDialog(this /* context */, this /* listener */));
|
||||
PermissionsManager.get(this).requestPermissions(
|
||||
this /* PermissionsResultCallback */,
|
||||
null /* activity */, permission.READ_CONTACTS);
|
||||
}
|
||||
|
||||
// Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener}
|
||||
@Override
|
||||
public void onClickSettingsOfImportantNoticeDialog(final int nextVersion) {
|
||||
launchSettings(SettingsActivity.EXTRA_ENTRY_VALUE_NOTICE_DIALOG);
|
||||
}
|
||||
|
||||
// Implement {@link ImportantNoticeDialog.ImportantNoticeDialogListener}
|
||||
@Override
|
||||
public void onUserAcknowledgmentOfImportantNoticeDialog(final int nextVersion) {
|
||||
public void onRequestPermissionsResult(boolean allGranted) {
|
||||
ImportantNoticeUtils.updateContactsNoticeShown(this /* context */);
|
||||
setNeutralSuggestionStrip();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.inputmethod.latin.permissions;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
|
||||
/**
|
||||
* An activity to help request permissions. It's used when no other activity is available, e.g. in
|
||||
* InputMethodService. This activity assumes that all permissions are not granted yet.
|
||||
*/
|
||||
public final class PermissionsActivity
|
||||
extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback {
|
||||
|
||||
/**
|
||||
* Key to retrieve requested permissions from the intent.
|
||||
*/
|
||||
public static final String EXTRA_PERMISSION_REQUESTED_PERMISSIONS = "requested_permissions";
|
||||
|
||||
/**
|
||||
* Key to retrieve request code from the intent.
|
||||
*/
|
||||
public static final String EXTRA_PERMISSION_REQUEST_CODE = "request_code";
|
||||
|
||||
private static final int INVALID_REQUEST_CODE = -1;
|
||||
|
||||
private int mPendingRequestCode = INVALID_REQUEST_CODE;
|
||||
|
||||
/**
|
||||
* Starts a PermissionsActivity and checks/requests supplied permissions.
|
||||
*/
|
||||
public static void run(
|
||||
@NonNull Context context, int requestCode, @NonNull String... permissionStrings) {
|
||||
Intent intent = new Intent(context.getApplicationContext(), PermissionsActivity.class);
|
||||
intent.putExtra(EXTRA_PERMISSION_REQUESTED_PERMISSIONS, permissionStrings);
|
||||
intent.putExtra(EXTRA_PERMISSION_REQUEST_CODE, requestCode);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mPendingRequestCode = (savedInstanceState != null)
|
||||
? savedInstanceState.getInt(EXTRA_PERMISSION_REQUEST_CODE, INVALID_REQUEST_CODE)
|
||||
: INVALID_REQUEST_CODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(EXTRA_PERMISSION_REQUEST_CODE, mPendingRequestCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// Only do request when there is no pending request to avoid duplicated requests.
|
||||
if (mPendingRequestCode == INVALID_REQUEST_CODE) {
|
||||
final Bundle extras = getIntent().getExtras();
|
||||
final String[] permissionsToRequest =
|
||||
extras.getStringArray(EXTRA_PERMISSION_REQUESTED_PERMISSIONS);
|
||||
mPendingRequestCode = extras.getInt(EXTRA_PERMISSION_REQUEST_CODE);
|
||||
// Assuming that all supplied permissions are not granted yet, so that we don't need to
|
||||
// check them again.
|
||||
PermissionsUtil.requestPermissions(this, mPendingRequestCode, permissionsToRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(
|
||||
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
mPendingRequestCode = INVALID_REQUEST_CODE;
|
||||
PermissionsManager.get(this).onRequestPermissionsResult(
|
||||
requestCode, permissions, grantResults);
|
||||
finish();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.inputmethod.latin.permissions;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Manager to perform permission related tasks. Always call on the UI thread.
|
||||
*/
|
||||
public class PermissionsManager {
|
||||
|
||||
public interface PermissionsResultCallback {
|
||||
void onRequestPermissionsResult(boolean allGranted);
|
||||
}
|
||||
|
||||
private int mRequestCodeId;
|
||||
|
||||
private final Context mContext;
|
||||
private final Map<Integer, PermissionsResultCallback> mRequestIdToCallback = new HashMap<>();
|
||||
|
||||
private static PermissionsManager sInstance;
|
||||
|
||||
public PermissionsManager(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static synchronized PermissionsManager get(@Nonnull Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new PermissionsManager(context);
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private synchronized int getNextRequestId() {
|
||||
return ++mRequestCodeId;
|
||||
}
|
||||
|
||||
|
||||
public synchronized void requestPermissions(@Nonnull PermissionsResultCallback callback,
|
||||
@Nullable Activity activity,
|
||||
String... permissionsToRequest) {
|
||||
List<String> deniedPermissions = PermissionsUtil.getDeniedPermissions(
|
||||
mContext, permissionsToRequest);
|
||||
if (deniedPermissions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// otherwise request the permissions.
|
||||
int requestId = getNextRequestId();
|
||||
String[] permissionsArray = deniedPermissions.toArray(
|
||||
new String[deniedPermissions.size()]);
|
||||
|
||||
mRequestIdToCallback.put(requestId, callback);
|
||||
if (activity != null) {
|
||||
PermissionsUtil.requestPermissions(activity, requestId, permissionsArray);
|
||||
} else {
|
||||
PermissionsActivity.run(mContext, requestId, permissionsArray);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void onRequestPermissionsResult(
|
||||
int requestCode, String[] permissions, int[] grantResults) {
|
||||
PermissionsResultCallback permissionsResultCallback = mRequestIdToCallback.get(requestCode);
|
||||
mRequestIdToCallback.remove(requestCode);
|
||||
|
||||
boolean allGranted = PermissionsUtil.allGranted(grantResults);
|
||||
permissionsResultCallback.onRequestPermissionsResult(allGranted);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.inputmethod.latin.permissions;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class for permissions.
|
||||
*/
|
||||
public class PermissionsUtil {
|
||||
|
||||
/**
|
||||
* Returns the list of permissions not granted from the given list of permissions.
|
||||
* @param context Context
|
||||
* @param permissions list of permissions to check.
|
||||
* @return the list of permissions that do not have permission to use.
|
||||
*/
|
||||
public static List<String> getDeniedPermissions(Context context,
|
||||
String... permissions) {
|
||||
final List<String> deniedPermissions = new ArrayList<>();
|
||||
for (String permission : permissions) {
|
||||
if (ContextCompat.checkSelfPermission(context, permission)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
deniedPermissions.add(permission);
|
||||
}
|
||||
}
|
||||
return deniedPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given activity and requests the user for permissions.
|
||||
* @param activity activity to use.
|
||||
* @param requestCode request code/id to use.
|
||||
* @param permissions String array of permissions that needs to be requested.
|
||||
*/
|
||||
public static void requestPermissions(Activity activity, int requestCode,
|
||||
String[] permissions) {
|
||||
ActivityCompat.requestPermissions(activity, permissions, requestCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all the permissions are granted.
|
||||
*/
|
||||
public static boolean allGranted(@NonNull int[] grantResults) {
|
||||
for (int result : grantResults) {
|
||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries if al the permissions are granted for the given permission strings.
|
||||
*/
|
||||
public static boolean checkAllPermissionsGranted(Context context, String... permissions) {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
// For all pre-M devices, we should have all the premissions granted on install.
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String permission : permissions) {
|
||||
if (ContextCompat.checkSelfPermission(context, permission)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -16,17 +16,23 @@
|
|||
|
||||
package com.android.inputmethod.latin.settings;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.SwitchPreference;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.inputmethod.dictionarypack.DictionarySettingsActivity;
|
||||
import com.android.inputmethod.latin.R;
|
||||
import com.android.inputmethod.latin.permissions.PermissionsManager;
|
||||
import com.android.inputmethod.latin.permissions.PermissionsUtil;
|
||||
import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
|
||||
import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
|
||||
|
||||
|
@ -45,12 +51,17 @@ import java.util.TreeSet;
|
|||
* - Suggest Contact names
|
||||
* - Next-word suggestions
|
||||
*/
|
||||
public final class CorrectionSettingsFragment extends SubScreenFragment {
|
||||
public final class CorrectionSettingsFragment extends SubScreenFragment
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener,
|
||||
PermissionsManager.PermissionsResultCallback {
|
||||
|
||||
private static final boolean DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS = false;
|
||||
private static final boolean USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS =
|
||||
DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS
|
||||
|| Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2;
|
||||
|
||||
private SwitchPreference mUseContactsPreference;
|
||||
|
||||
@Override
|
||||
public void onCreate(final Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
@ -76,6 +87,9 @@ public final class CorrectionSettingsFragment extends SubScreenFragment {
|
|||
if (ri == null) {
|
||||
overwriteUserDictionaryPreference(editPersonalDictionary);
|
||||
}
|
||||
|
||||
mUseContactsPreference = (SwitchPreference) findPreference(Settings.PREF_KEY_USE_CONTACTS_DICT);
|
||||
turnOffUseContactsIfNoPermission();
|
||||
}
|
||||
|
||||
private void overwriteUserDictionaryPreference(final Preference userDictionaryPreference) {
|
||||
|
@ -101,4 +115,38 @@ public final class CorrectionSettingsFragment extends SubScreenFragment {
|
|||
userDictionaryPreference.setFragment(UserDictionaryList.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) {
|
||||
if (!TextUtils.equals(key, Settings.PREF_KEY_USE_CONTACTS_DICT)) {
|
||||
return;
|
||||
}
|
||||
if (!sharedPreferences.getBoolean(key, false)) {
|
||||
// don't care if the preference is turned off.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for permissions.
|
||||
if (PermissionsUtil.checkAllPermissionsGranted(
|
||||
getActivity() /* context */, Manifest.permission.READ_CONTACTS)) {
|
||||
return; // all permissions granted, no need to request permissions.
|
||||
}
|
||||
|
||||
PermissionsManager.get(getActivity() /* context */).requestPermissions(
|
||||
this /* PermissionsResultCallback */,
|
||||
getActivity() /* activity */,
|
||||
Manifest.permission.READ_CONTACTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(boolean allGranted) {
|
||||
turnOffUseContactsIfNoPermission();
|
||||
}
|
||||
|
||||
private void turnOffUseContactsIfNoPermission() {
|
||||
if (!PermissionsUtil.checkAllPermissionsGranted(
|
||||
getActivity(), Manifest.permission.READ_CONTACTS)) {
|
||||
mUseContactsPreference.setChecked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.inputmethod.latin.settings;
|
||||
|
||||
import com.android.inputmethod.latin.permissions.PermissionsManager;
|
||||
import com.android.inputmethod.latin.utils.FragmentUtils;
|
||||
import com.android.inputmethod.latin.utils.StatsUtils;
|
||||
import com.android.inputmethod.latin.utils.StatsUtilsManager;
|
||||
|
@ -24,9 +25,11 @@ import android.app.ActionBar;
|
|||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.view.MenuItem;
|
||||
|
||||
public final class SettingsActivity extends PreferenceActivity {
|
||||
public final class SettingsActivity extends PreferenceActivity
|
||||
implements ActivityCompat.OnRequestPermissionsResultCallback {
|
||||
private static final String DEFAULT_FRAGMENT = SettingsFragment.class.getName();
|
||||
|
||||
public static final String EXTRA_SHOW_HOME_AS_UP = "show_home_as_up";
|
||||
|
@ -77,4 +80,9 @@ public final class SettingsActivity extends PreferenceActivity {
|
|||
public boolean isValidFragment(final String fragmentName) {
|
||||
return FragmentUtils.isValidFragment(fragmentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
PermissionsManager.get(this).onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,7 +220,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
|
|||
if (getWidth() <= 0) {
|
||||
return false;
|
||||
}
|
||||
final String importantNoticeTitle = ImportantNoticeUtils.getNextImportantNoticeTitle(
|
||||
final String importantNoticeTitle = ImportantNoticeUtils.getSuggestContactsNoticeTitle(
|
||||
getContext());
|
||||
if (TextUtils.isEmpty(importantNoticeTitle)) {
|
||||
return false;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.android.inputmethod.latin.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.provider.Settings;
|
||||
|
@ -25,6 +26,7 @@ import android.util.Log;
|
|||
|
||||
import com.android.inputmethod.annotations.UsedForTesting;
|
||||
import com.android.inputmethod.latin.R;
|
||||
import com.android.inputmethod.latin.permissions.PermissionsUtil;
|
||||
import com.android.inputmethod.latin.settings.SettingsValues;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -35,14 +37,14 @@ public final class ImportantNoticeUtils {
|
|||
// {@link SharedPreferences} name to save the last important notice version that has been
|
||||
// displayed to users.
|
||||
private static final String PREFERENCE_NAME = "important_notice_pref";
|
||||
|
||||
private static final String KEY_SUGGEST_CONTACTS_NOTICE = "important_notice_suggest_contacts";
|
||||
|
||||
@UsedForTesting
|
||||
static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version";
|
||||
@UsedForTesting
|
||||
static final String KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE =
|
||||
"timestamp_of_first_important_notice";
|
||||
static final String KEY_TIMESTAMP_OF_CONTACTS_NOTICE = "timestamp_of_suggest_contacts_notice";
|
||||
|
||||
@UsedForTesting
|
||||
static final long TIMEOUT_OF_IMPORTANT_NOTICE = TimeUnit.HOURS.toMillis(23);
|
||||
public static final int VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS = 1;
|
||||
|
||||
// Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key.
|
||||
// The value is zero until each multiuser completes system setup wizard.
|
||||
|
@ -73,87 +75,66 @@ public final class ImportantNoticeUtils {
|
|||
}
|
||||
|
||||
@UsedForTesting
|
||||
static int getCurrentImportantNoticeVersion(final Context context) {
|
||||
return context.getResources().getInteger(R.integer.config_important_notice_version);
|
||||
}
|
||||
|
||||
@UsedForTesting
|
||||
static int getLastImportantNoticeVersion(final Context context) {
|
||||
return getImportantNoticePreferences(context).getInt(KEY_IMPORTANT_NOTICE_VERSION, 0);
|
||||
}
|
||||
|
||||
public static int getNextImportantNoticeVersion(final Context context) {
|
||||
return getLastImportantNoticeVersion(context) + 1;
|
||||
}
|
||||
|
||||
@UsedForTesting
|
||||
static boolean hasNewImportantNotice(final Context context) {
|
||||
final int lastVersion = getLastImportantNoticeVersion(context);
|
||||
return getCurrentImportantNoticeVersion(context) > lastVersion;
|
||||
}
|
||||
|
||||
@UsedForTesting
|
||||
static boolean hasTimeoutPassed(final Context context, final long currentTimeInMillis) {
|
||||
final SharedPreferences prefs = getImportantNoticePreferences(context);
|
||||
if (!prefs.contains(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE)) {
|
||||
prefs.edit()
|
||||
.putLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, currentTimeInMillis)
|
||||
.apply();
|
||||
}
|
||||
final long firstDisplayTimeInMillis = prefs.getLong(
|
||||
KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, currentTimeInMillis);
|
||||
final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis;
|
||||
return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE;
|
||||
static boolean hasContactsNoticeShown(final Context context) {
|
||||
return getImportantNoticePreferences(context).getBoolean(
|
||||
KEY_SUGGEST_CONTACTS_NOTICE, false);
|
||||
}
|
||||
|
||||
public static boolean shouldShowImportantNotice(final Context context,
|
||||
final SettingsValues settingsValues) {
|
||||
// Check to see whether personalization is enabled by the user.
|
||||
if (!settingsValues.isPersonalizationEnabled()) {
|
||||
// Check to see whether "Use Contacts" is enabled by the user.
|
||||
if (!settingsValues.mUseContactsDict) {
|
||||
return false;
|
||||
}
|
||||
if (!hasNewImportantNotice(context)) {
|
||||
|
||||
if (hasContactsNoticeShown(context)) {
|
||||
return false;
|
||||
}
|
||||
final String importantNoticeTitle = getNextImportantNoticeTitle(context);
|
||||
|
||||
// Don't show the dialog if we have all the permissions.
|
||||
if (PermissionsUtil.checkAllPermissionsGranted(
|
||||
context, Manifest.permission.READ_CONTACTS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String importantNoticeTitle = getSuggestContactsNoticeTitle(context);
|
||||
if (TextUtils.isEmpty(importantNoticeTitle)) {
|
||||
return false;
|
||||
}
|
||||
if (isInSystemSetupWizard(context)) {
|
||||
return false;
|
||||
}
|
||||
if (hasTimeoutPassed(context, System.currentTimeMillis())) {
|
||||
updateLastImportantNoticeVersion(context);
|
||||
if (hasContactsNoticeTimeoutPassed(context, System.currentTimeMillis())) {
|
||||
updateContactsNoticeShown(context);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void updateLastImportantNoticeVersion(final Context context) {
|
||||
getImportantNoticePreferences(context)
|
||||
.edit()
|
||||
.putInt(KEY_IMPORTANT_NOTICE_VERSION, getNextImportantNoticeVersion(context))
|
||||
.remove(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE)
|
||||
public static String getSuggestContactsNoticeTitle(final Context context) {
|
||||
return context.getResources().getString(R.string.important_notice_suggest_contact_names);
|
||||
}
|
||||
|
||||
@UsedForTesting
|
||||
static boolean hasContactsNoticeTimeoutPassed(
|
||||
final Context context, final long currentTimeInMillis) {
|
||||
final SharedPreferences prefs = getImportantNoticePreferences(context);
|
||||
if (!prefs.contains(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)) {
|
||||
prefs.edit()
|
||||
.putLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static String getNextImportantNoticeTitle(final Context context) {
|
||||
final int nextVersion = getNextImportantNoticeVersion(context);
|
||||
final String[] importantNoticeTitleArray = context.getResources().getStringArray(
|
||||
R.array.important_notice_title_array);
|
||||
if (nextVersion > 0 && nextVersion < importantNoticeTitleArray.length) {
|
||||
return importantNoticeTitleArray[nextVersion];
|
||||
}
|
||||
return null;
|
||||
final long firstDisplayTimeInMillis = prefs.getLong(
|
||||
KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis);
|
||||
final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis;
|
||||
return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE;
|
||||
}
|
||||
|
||||
public static String getNextImportantNoticeContents(final Context context) {
|
||||
final int nextVersion = getNextImportantNoticeVersion(context);
|
||||
final String[] importantNoticeContentsArray = context.getResources().getStringArray(
|
||||
R.array.important_notice_contents_array);
|
||||
if (nextVersion > 0 && nextVersion < importantNoticeContentsArray.length) {
|
||||
return importantNoticeContentsArray[nextVersion];
|
||||
}
|
||||
return null;
|
||||
public static void updateContactsNoticeShown(final Context context) {
|
||||
getImportantNoticePreferences(context)
|
||||
.edit()
|
||||
.putBoolean(KEY_SUGGEST_CONTACTS_NOTICE, true)
|
||||
.remove(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
|
||||
package com.android.inputmethod.latin.utils;
|
||||
|
||||
import static com.android.inputmethod.latin.utils.ImportantNoticeUtils.KEY_IMPORTANT_NOTICE_VERSION;
|
||||
import static com.android.inputmethod.latin.utils.ImportantNoticeUtils.KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE;
|
||||
import static com.android.inputmethod.latin.utils.ImportantNoticeUtils.KEY_TIMESTAMP_OF_CONTACTS_NOTICE;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -35,8 +34,6 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
@MediumTest
|
||||
public class ImportantNoticeUtilsTests extends AndroidTestCase {
|
||||
// This should be aligned with R.integer.config_important_notice_version.
|
||||
private static final int CURRENT_IMPORTANT_NOTICE_VERSION = 1;
|
||||
|
||||
private ImportantNoticePreferences mImportantNoticePreferences;
|
||||
|
||||
|
@ -87,18 +84,15 @@ public class ImportantNoticeUtilsTests extends AndroidTestCase {
|
|||
}
|
||||
|
||||
public void save() {
|
||||
mVersion = getInt(KEY_IMPORTANT_NOTICE_VERSION);
|
||||
mLastTime = getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE);
|
||||
mLastTime = getLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE);
|
||||
}
|
||||
|
||||
public void restore() {
|
||||
putInt(KEY_IMPORTANT_NOTICE_VERSION, mVersion);
|
||||
putLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, mLastTime);
|
||||
putLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE, mLastTime);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
removePreference(KEY_IMPORTANT_NOTICE_VERSION);
|
||||
removePreference(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE);
|
||||
removePreference(KEY_TIMESTAMP_OF_CONTACTS_NOTICE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,141 +111,6 @@ public class ImportantNoticeUtilsTests extends AndroidTestCase {
|
|||
mImportantNoticePreferences.restore();
|
||||
}
|
||||
|
||||
public void testCurrentVersion() {
|
||||
assertEquals("Current version", CURRENT_IMPORTANT_NOTICE_VERSION,
|
||||
ImportantNoticeUtils.getCurrentImportantNoticeVersion(getContext()));
|
||||
}
|
||||
|
||||
public void testStateAfterFreshInstall() {
|
||||
mImportantNoticePreferences.clear();
|
||||
|
||||
// Check internal state of {@link ImportantNoticeUtils.shouldShowImportantNotice(Context)}
|
||||
// after fresh install.
|
||||
assertEquals("Has new important notice after fresh install", true,
|
||||
ImportantNoticeUtils.hasNewImportantNotice(getContext()));
|
||||
assertEquals("Next important notice title after fresh install", false, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
|
||||
assertEquals("Is in system setup wizard after fresh install", false,
|
||||
ImportantNoticeUtils.isInSystemSetupWizard(getContext()));
|
||||
final long currentTimeMillis = System.currentTimeMillis();
|
||||
assertEquals("Has timeout passed after fresh install", false,
|
||||
ImportantNoticeUtils.hasTimeoutPassed(getContext(), currentTimeMillis));
|
||||
assertEquals("Timestamp of first important notice after fresh install",
|
||||
(Long)currentTimeMillis,
|
||||
mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
|
||||
|
||||
assertEquals("Current boolean before update", true,
|
||||
ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
|
||||
}
|
||||
|
||||
public void testUpdateVersion() {
|
||||
mImportantNoticePreferences.clear();
|
||||
|
||||
assertEquals("Current boolean before update", true,
|
||||
ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
|
||||
assertEquals("Last version before update", 0,
|
||||
ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
|
||||
assertEquals("Next version before update ", 1,
|
||||
ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
|
||||
assertEquals("Current title before update", false, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
|
||||
assertEquals("Current contents before update", false, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
|
||||
|
||||
ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext());
|
||||
|
||||
assertEquals("Current boolean after update", false,
|
||||
ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
|
||||
assertEquals("Last version after update", 1,
|
||||
ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
|
||||
assertEquals("Next version after update", 2,
|
||||
ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
|
||||
assertEquals("Current title after update", true, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
|
||||
assertEquals("Current contents after update", true, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
|
||||
}
|
||||
|
||||
private static void sleep(final long millseconds) {
|
||||
try { Thread.sleep(millseconds); } catch (final Exception e) { /* ignore */ }
|
||||
}
|
||||
|
||||
public void testTimeout() {
|
||||
final long lastTime = System.currentTimeMillis()
|
||||
- ImportantNoticeUtils.TIMEOUT_OF_IMPORTANT_NOTICE
|
||||
+ TimeUnit.MILLISECONDS.toMillis(1000);
|
||||
mImportantNoticePreferences.clear();
|
||||
assertEquals("Before set last time", null,
|
||||
mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
|
||||
assertEquals("Set last time", false,
|
||||
ImportantNoticeUtils.hasTimeoutPassed(getContext(), lastTime));
|
||||
assertEquals("After set last time", (Long)lastTime,
|
||||
mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
|
||||
|
||||
// Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} before timeout.
|
||||
assertEquals("Current boolean before timeout 1", true,
|
||||
ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
|
||||
assertEquals("Last version before timeout 1", 0,
|
||||
ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
|
||||
assertEquals("Next version before timeout 1", 1,
|
||||
ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
|
||||
assertEquals("Timestamp of first important notice before timeout 1", (Long)lastTime,
|
||||
mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
|
||||
assertEquals("Current title before timeout 1", false, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
|
||||
assertEquals("Current contents before timeout 1", false, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
|
||||
|
||||
sleep(TimeUnit.MILLISECONDS.toMillis(600));
|
||||
|
||||
// Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} before timeout
|
||||
// again.
|
||||
assertEquals("Current boolean before timeout 2", true,
|
||||
ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
|
||||
assertEquals("Last version before timeout 2", 0,
|
||||
ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
|
||||
assertEquals("Next version before timeout 2", 1,
|
||||
ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
|
||||
assertEquals("Timestamp of first important notice before timeout 2", (Long)lastTime,
|
||||
mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
|
||||
assertEquals("Current title before timeout 2", false, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
|
||||
assertEquals("Current contents before timeout 2", false, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
|
||||
|
||||
sleep(TimeUnit.MILLISECONDS.toMillis(600));
|
||||
|
||||
// Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} after timeout.
|
||||
assertEquals("Current boolean after timeout 1", false,
|
||||
ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
|
||||
assertEquals("Last version after timeout 1", 1,
|
||||
ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
|
||||
assertEquals("Next version after timeout 1", 2,
|
||||
ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
|
||||
assertEquals("Timestamp of first important notice after timeout 1", null,
|
||||
mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
|
||||
assertEquals("Current title after timeout 1", true, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
|
||||
assertEquals("Current contents after timeout 1", true, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
|
||||
|
||||
sleep(TimeUnit.MILLISECONDS.toMillis(600));
|
||||
|
||||
// Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} after timeout again.
|
||||
assertEquals("Current boolean after timeout 2", false,
|
||||
ImportantNoticeUtils.shouldShowImportantNotice(getContext(), mMockSettingsValues));
|
||||
assertEquals("Last version after timeout 2", 1,
|
||||
ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
|
||||
assertEquals("Next version after timeout 2", 2,
|
||||
ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
|
||||
assertEquals("Timestamp of first important notice after timeout 2", null,
|
||||
mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
|
||||
assertEquals("Current title after timeout 2", true, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
|
||||
assertEquals("Current contents after timeout 2", true, TextUtils.isEmpty(
|
||||
ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
|
||||
}
|
||||
|
||||
public void testPersonalizationSetting() {
|
||||
mImportantNoticePreferences.clear();
|
||||
|
||||
|
|
Loading…
Reference in New Issue