1a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka/* 2a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * Copyright (C) 2014 The Android Open Source Project 3a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * 4a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 5a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * you may not use this file except in compliance with the License. 6a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * You may obtain a copy of the License at 7a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * 8a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 9a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * 10a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 11a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 12a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * See the License for the specific language governing permissions and 14a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka * limitations under the License. 15a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka */ 16a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 17a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaokapackage com.android.inputmethod.latin.utils; 18a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 19a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaokaimport android.content.Context; 20a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaokaimport android.content.SharedPreferences; 21a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaokaimport android.provider.Settings; 22a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaokaimport android.provider.Settings.SettingNotFoundException; 23f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaokaimport android.text.TextUtils; 24a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaokaimport android.util.Log; 25a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 26be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting; 275b8ffad26c9f6996fda127d0a4ddd40fb0689f0fTadashi G. Takaokaimport com.android.inputmethod.latin.R; 285b8ffad26c9f6996fda127d0a4ddd40fb0689f0fTadashi G. Takaoka 29be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaokaimport java.util.concurrent.TimeUnit; 30be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka 31a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaokapublic final class ImportantNoticeUtils { 32a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka private static final String TAG = ImportantNoticeUtils.class.getSimpleName(); 33a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 34a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka // {@link SharedPreferences} name to save the last important notice version that has been 35a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka // displayed to users. 361672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka private static final String PREFERENCE_NAME = "important_notice_pref"; 37be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka @UsedForTesting 38be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version"; 39be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka @UsedForTesting 40be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka static final String KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE = 41be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka "timestamp_of_first_important_notice"; 42be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka @UsedForTesting 43be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka static final long TIMEOUT_OF_IMPORTANT_NOTICE = TimeUnit.HOURS.toMillis(23); 441672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka public static final int VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS = 1; 45a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 46a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka // Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key. 47a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka // The value is zero until each multiuser completes system setup wizard. 48a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka // Caveat: This is a hidden API. 49a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka private static final String Settings_Secure_USER_SETUP_COMPLETE = "user_setup_complete"; 50a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka private static final int USER_SETUP_IS_NOT_COMPLETE = 0; 51a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 52a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka private ImportantNoticeUtils() { 53a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka // This utility class is not publicly instantiable. 54a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka } 55a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 568adedbf47c7ac150d4ac7e6cdbee3ece38f346e7Jean Chalard private static boolean isInSystemSetupWizard(final Context context) { 57a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka try { 58a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka final int userSetupComplete = Settings.Secure.getInt( 59a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka context.getContentResolver(), Settings_Secure_USER_SETUP_COMPLETE); 60a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka return userSetupComplete == USER_SETUP_IS_NOT_COMPLETE; 61a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka } catch (final SettingNotFoundException e) { 62a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka Log.w(TAG, "Can't find settings in Settings.Secure: key=" 63a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka + Settings_Secure_USER_SETUP_COMPLETE); 64a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka return false; 65a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka } 66a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka } 67a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 68be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka @UsedForTesting 69be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka static SharedPreferences getImportantNoticePreferences(final Context context) { 70a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); 71a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka } 72a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 73be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka @UsedForTesting 74be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka static int getCurrentImportantNoticeVersion(final Context context) { 755b8ffad26c9f6996fda127d0a4ddd40fb0689f0fTadashi G. Takaoka return context.getResources().getInteger(R.integer.config_important_notice_version); 765b8ffad26c9f6996fda127d0a4ddd40fb0689f0fTadashi G. Takaoka } 775b8ffad26c9f6996fda127d0a4ddd40fb0689f0fTadashi G. Takaoka 78be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka @UsedForTesting 79be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka static int getLastImportantNoticeVersion(final Context context) { 801672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka return getImportantNoticePreferences(context).getInt(KEY_IMPORTANT_NOTICE_VERSION, 0); 811672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka } 821672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka 83fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka public static int getNextImportantNoticeVersion(final Context context) { 841672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka return getLastImportantNoticeVersion(context) + 1; 851672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka } 861672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka 87ce78a2d8ab7630cff509c2b21b4b11abd8db4795Tadashi G. Takaoka private static boolean hasNewImportantNotice(final Context context) { 881672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka final int lastVersion = getLastImportantNoticeVersion(context); 89ce78a2d8ab7630cff509c2b21b4b11abd8db4795Tadashi G. Takaoka return getCurrentImportantNoticeVersion(context) > lastVersion; 90ce78a2d8ab7630cff509c2b21b4b11abd8db4795Tadashi G. Takaoka } 91ce78a2d8ab7630cff509c2b21b4b11abd8db4795Tadashi G. Takaoka 92be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka @UsedForTesting 93be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka static boolean hasTimeoutPassed(final Context context, final long currentTimeInMillis) { 94be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka final SharedPreferences prefs = getImportantNoticePreferences(context); 95be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka if (!prefs.contains(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE)) { 96be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka prefs.edit() 97be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka .putLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, currentTimeInMillis) 98be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka .apply(); 99be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka } 100be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka final long firstDisplayTimeInMillis = prefs.getLong( 101be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, currentTimeInMillis); 102be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis; 103be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE; 104be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka } 105be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka 106987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka public static boolean shouldShowImportantNotice(final Context context) { 107f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaoka if (!hasNewImportantNotice(context)) { 108f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaoka return false; 109f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaoka } 110f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaoka final String importantNoticeTitle = getNextImportantNoticeTitle(context); 111f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaoka if (TextUtils.isEmpty(importantNoticeTitle)) { 112f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaoka return false; 113f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaoka } 114987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka if (isInSystemSetupWizard(context)) { 115987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka return false; 116987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka } 117be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka if (hasTimeoutPassed(context, System.currentTimeMillis())) { 118be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka updateLastImportantNoticeVersion(context); 119be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka return false; 120be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka } 121f96bffa69e5fa01b0bf53fb3af8c8b3539852322Tadashi G. Takaoka return true; 122a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka } 123a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka 124a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka public static void updateLastImportantNoticeVersion(final Context context) { 1251672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka getImportantNoticePreferences(context) 1261672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka .edit() 1271672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka .putInt(KEY_IMPORTANT_NOTICE_VERSION, getNextImportantNoticeVersion(context)) 128be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka .remove(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE) 129a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka .apply(); 130a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka } 1316abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka 1321672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka public static String getNextImportantNoticeTitle(final Context context) { 133be4e0d0e3921af3d575f745cb356704974362bafTadashi G. Takaoka final int nextVersion = getNextImportantNoticeVersion(context); 134fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka final String[] importantNoticeTitleArray = context.getResources().getStringArray( 135fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka R.array.important_notice_title_array); 136fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka if (nextVersion > 0 && nextVersion < importantNoticeTitleArray.length) { 137fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka return importantNoticeTitleArray[nextVersion]; 1386abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka } 139fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka return null; 1406abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka } 1416abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka 1421672ccbbb6167f434842093feaadc2bcd5634eabTadashi G. Takaoka public static String getNextImportantNoticeContents(final Context context) { 143fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka final int nextVersion = getNextImportantNoticeVersion(context); 144fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka final String[] importantNoticeContentsArray = context.getResources().getStringArray( 145fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka R.array.important_notice_contents_array); 146fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka if (nextVersion > 0 && nextVersion < importantNoticeContentsArray.length) { 147fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka return importantNoticeContentsArray[nextVersion]; 1486abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka } 149fe39d576dcd515d7fcd678a2ed6a621185cc69e3Tadashi G. Takaoka return null; 1506abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka } 151a14ddfb5fffff0e41620c6c00a37fb26888a95ecTadashi G. Takaoka} 152