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
17package com.android.inputmethod.latin.utils;
18
19import android.Manifest;
20import android.content.Context;
21import android.content.SharedPreferences;
22import android.provider.Settings;
23import android.provider.Settings.SettingNotFoundException;
24import android.text.TextUtils;
25import android.util.Log;
26
27import com.android.inputmethod.annotations.UsedForTesting;
28import com.android.inputmethod.latin.R;
29import com.android.inputmethod.latin.permissions.PermissionsUtil;
30import com.android.inputmethod.latin.settings.SettingsValues;
31
32import java.util.concurrent.TimeUnit;
33
34public 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