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