am 1c47b2d8: am 992144a8: am 60415866: [LatinIME] Support MNC permissions.

* commit '1c47b2d83dc23fb56f4d7dbd7711d828850d8882':
  [LatinIME] Support MNC permissions.
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index f58c401..8882cde 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -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"
diff --git a/java/res/values/donottranslate-config-important-notice.xml b/java/res/values/donottranslate-config-important-notice.xml
deleted file mode 100644
index 7c6527c..0000000
--- a/java/res/values/donottranslate-config-important-notice.xml
+++ /dev/null
@@ -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>
diff --git a/java/res/values/important_notice_strings.xml b/java/res/values/important_notice_strings.xml
new file mode 100644
index 0000000..b1f3fc1
--- /dev/null
+++ b/java/res/values/important_notice_strings.xml
@@ -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>
\ No newline at end of file
diff --git a/java/res/values/strings-config-important-notice.xml b/java/res/values/strings-config-important-notice.xml
deleted file mode 100644
index aa3cd10..0000000
--- a/java/res/values/strings-config-important-notice.xml
+++ /dev/null
@@ -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>
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 15a14e5..dbd639f 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -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 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 @@
      * 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);
diff --git a/java/src/com/android/inputmethod/latin/ContactsContentObserver.java b/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
index 872e4c8..6103a82 100644
--- a/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
+++ b/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
@@ -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 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 @@
  */
 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 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 @@
 
     @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 @@
             }
             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) {
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
index c7115c9..b435de8 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
@@ -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.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 @@
         // 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) {
diff --git a/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java b/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java
deleted file mode 100644
index 567087c..0000000
--- a/java/src/com/android/inputmethod/latin/ImportantNoticeDialog.java
+++ /dev/null
@@ -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();
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 089670e..1f2b6f2 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -20,6 +20,7 @@
 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.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 @@
 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 @@
     // 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();
     }
 
diff --git a/java/src/com/android/inputmethod/latin/permissions/PermissionsActivity.java b/java/src/com/android/inputmethod/latin/permissions/PermissionsActivity.java
new file mode 100644
index 0000000..bdd63fa
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/permissions/PermissionsActivity.java
@@ -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();
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/permissions/PermissionsManager.java b/java/src/com/android/inputmethod/latin/permissions/PermissionsManager.java
new file mode 100644
index 0000000..08c623a
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/permissions/PermissionsManager.java
@@ -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);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/permissions/PermissionsUtil.java b/java/src/com/android/inputmethod/latin/permissions/PermissionsUtil.java
new file mode 100644
index 0000000..747f64f
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/permissions/PermissionsUtil.java
@@ -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;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java
index d28e703..dfe899e 100644
--- a/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java
@@ -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 @@
  * - 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 @@
         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 @@
             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);
+        }
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java b/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
index 9975277..a7d157a 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
@@ -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.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 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);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 7dd0f03..c1d1fad 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -220,7 +220,7 @@
         if (getWidth() <= 0) {
             return false;
         }
-        final String importantNoticeTitle = ImportantNoticeUtils.getNextImportantNoticeTitle(
+        final String importantNoticeTitle = ImportantNoticeUtils.getSuggestContactsNoticeTitle(
                 getContext());
         if (TextUtils.isEmpty(importantNoticeTitle)) {
             return false;
diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
index df0cd84..cea263b 100644
--- a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
@@ -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 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 @@
     // {@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 @@
     }
 
     @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) {
+    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();
+        }
+        final long firstDisplayTimeInMillis = prefs.getLong(
+                KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis);
+        final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis;
+        return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE;
+    }
+
+    public static void updateContactsNoticeShown(final Context context) {
         getImportantNoticePreferences(context)
                 .edit()
-                .putInt(KEY_IMPORTANT_NOTICE_VERSION, getNextImportantNoticeVersion(context))
-                .remove(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE)
+                .putBoolean(KEY_SUGGEST_CONTACTS_NOTICE, true)
+                .remove(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)
                 .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;
-    }
-
-    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;
-    }
 }
diff --git a/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
index e361c77..df01807 100644
--- a/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
@@ -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 @@
 
 @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 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 @@
         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();