1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.latin.utils; 18 19 import android.Manifest; 20 import android.content.Context; 21 import android.content.SharedPreferences; 22 import android.provider.Settings; 23 import android.provider.Settings.SettingNotFoundException; 24 import android.text.TextUtils; 25 import android.util.Log; 26 27 import com.android.inputmethod.annotations.UsedForTesting; 28 import com.android.inputmethod.latin.R; 29 import com.android.inputmethod.latin.permissions.PermissionsUtil; 30 import com.android.inputmethod.latin.settings.SettingsValues; 31 32 import java.util.concurrent.TimeUnit; 33 34 public final class ImportantNoticeUtils { 35 private static final String TAG = ImportantNoticeUtils.class.getSimpleName(); 36 37 // {@link SharedPreferences} name to save the last important notice version that has been 38 // displayed to users. 39 private static final String PREFERENCE_NAME = "important_notice_pref"; 40 41 private static final String KEY_SUGGEST_CONTACTS_NOTICE = "important_notice_suggest_contacts"; 42 43 @UsedForTesting 44 static final String KEY_TIMESTAMP_OF_CONTACTS_NOTICE = "timestamp_of_suggest_contacts_notice"; 45 46 @UsedForTesting 47 static final long TIMEOUT_OF_IMPORTANT_NOTICE = TimeUnit.HOURS.toMillis(23); 48 49 // Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key. 50 // The value is zero until each multiuser completes system setup wizard. 51 // Caveat: This is a hidden API. 52 private static final String Settings_Secure_USER_SETUP_COMPLETE = "user_setup_complete"; 53 private static final int USER_SETUP_IS_NOT_COMPLETE = 0; 54 55 private ImportantNoticeUtils() { 56 // This utility class is not publicly instantiable. 57 } 58 59 @UsedForTesting 60 static boolean isInSystemSetupWizard(final Context context) { 61 try { 62 final int userSetupComplete = Settings.Secure.getInt( 63 context.getContentResolver(), Settings_Secure_USER_SETUP_COMPLETE); 64 return userSetupComplete == USER_SETUP_IS_NOT_COMPLETE; 65 } catch (final SettingNotFoundException e) { 66 Log.w(TAG, "Can't find settings in Settings.Secure: key=" 67 + Settings_Secure_USER_SETUP_COMPLETE); 68 return false; 69 } 70 } 71 72 @UsedForTesting 73 static SharedPreferences getImportantNoticePreferences(final Context context) { 74 return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); 75 } 76 77 @UsedForTesting 78 static boolean hasContactsNoticeShown(final Context context) { 79 return getImportantNoticePreferences(context).getBoolean( 80 KEY_SUGGEST_CONTACTS_NOTICE, false); 81 } 82 83 public static boolean shouldShowImportantNotice(final Context context, 84 final SettingsValues settingsValues) { 85 // Check to see whether "Use Contacts" is enabled by the user. 86 if (!settingsValues.mUseContactsDict) { 87 return false; 88 } 89 90 if (hasContactsNoticeShown(context)) { 91 return false; 92 } 93 94 // Don't show the dialog if we have all the permissions. 95 if (PermissionsUtil.checkAllPermissionsGranted( 96 context, Manifest.permission.READ_CONTACTS)) { 97 return false; 98 } 99 100 final String importantNoticeTitle = getSuggestContactsNoticeTitle(context); 101 if (TextUtils.isEmpty(importantNoticeTitle)) { 102 return false; 103 } 104 if (isInSystemSetupWizard(context)) { 105 return false; 106 } 107 if (hasContactsNoticeTimeoutPassed(context, System.currentTimeMillis())) { 108 updateContactsNoticeShown(context); 109 return false; 110 } 111 return true; 112 } 113 114 public static String getSuggestContactsNoticeTitle(final Context context) { 115 return context.getResources().getString(R.string.important_notice_suggest_contact_names); 116 } 117 118 @UsedForTesting 119 static boolean hasContactsNoticeTimeoutPassed( 120 final Context context, final long currentTimeInMillis) { 121 final SharedPreferences prefs = getImportantNoticePreferences(context); 122 if (!prefs.contains(KEY_TIMESTAMP_OF_CONTACTS_NOTICE)) { 123 prefs.edit() 124 .putLong(KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis) 125 .apply(); 126 } 127 final long firstDisplayTimeInMillis = prefs.getLong( 128 KEY_TIMESTAMP_OF_CONTACTS_NOTICE, currentTimeInMillis); 129 final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis; 130 return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE; 131 } 132 133 public static void updateContactsNoticeShown(final Context context) { 134 getImportantNoticePreferences(context) 135 .edit() 136 .putBoolean(KEY_SUGGEST_CONTACTS_NOTICE, true) 137 .remove(KEY_TIMESTAMP_OF_CONTACTS_NOTICE) 138 .apply(); 139 } 140 } 141