• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 package com.android.launcher3.util;
17 
18 import android.content.SharedPreferences;
19 import android.util.ArrayMap;
20 
21 import androidx.annotation.StringDef;
22 
23 import com.android.launcher3.views.ActivityContext;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.util.Collections;
28 import java.util.Map;
29 
30 /**
31  * Stores and retrieves onboarding-related data via SharedPreferences.
32  *
33  * @param <T> Context which owns these preferences.
34  */
35 public class OnboardingPrefs<T extends ActivityContext> {
36 
37     public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
38     public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
39     public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
40     public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
41     public static final String SEARCH_KEYBOARD_EDU_SEEN = "launcher.search_edu_seen";
42     public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
43     public static final String SEARCH_ONBOARDING_COUNT = "launcher.search_onboarding_count";
44     public static final String TASKBAR_EDU_SEEN = "launcher.taskbar_edu_seen2";
45     public static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
46     public static final String QSB_SEARCH_ONBOARDING_CARD_DISMISSED = "launcher.qsb_edu_dismiss";
47     public static final String TASKBAR_EDU_TOOLTIP_STEP = "launcher.taskbar_edu_tooltip_step";
48     // When adding a new key, add it here as well, to be able to reset it from Developer Options.
49     public static final Map<String, String[]> ALL_PREF_KEYS = Map.of(
50             "All Apps Bounce", new String[] { HOME_BOUNCE_SEEN, HOME_BOUNCE_COUNT },
51             "Hybrid Hotseat Education", new String[] { HOTSEAT_DISCOVERY_TIP_COUNT,
52                     HOTSEAT_LONGPRESS_TIP_SEEN },
53             "Search Education", new String[] { SEARCH_KEYBOARD_EDU_SEEN, SEARCH_SNACKBAR_COUNT,
54                     SEARCH_ONBOARDING_COUNT, QSB_SEARCH_ONBOARDING_CARD_DISMISSED},
55             "Taskbar Education", new String[] { TASKBAR_EDU_SEEN, TASKBAR_EDU_TOOLTIP_STEP },
56             "All Apps Visited Count", new String[] {ALL_APPS_VISITED_COUNT}
57     );
58 
59     /**
60      * Events that either have happened or have not (booleans).
61      */
62     @StringDef(value = {
63             HOME_BOUNCE_SEEN,
64             HOTSEAT_LONGPRESS_TIP_SEEN,
65             SEARCH_KEYBOARD_EDU_SEEN,
66             TASKBAR_EDU_SEEN,
67             QSB_SEARCH_ONBOARDING_CARD_DISMISSED
68     })
69     @Retention(RetentionPolicy.SOURCE)
70     public @interface EventBoolKey {}
71 
72     /**
73      * Events that occur multiple times, which we count up to a max defined in {@link #MAX_COUNTS}.
74      */
75     @StringDef(value = {
76             HOME_BOUNCE_COUNT,
77             HOTSEAT_DISCOVERY_TIP_COUNT,
78             SEARCH_SNACKBAR_COUNT,
79             SEARCH_ONBOARDING_COUNT,
80             ALL_APPS_VISITED_COUNT,
81             TASKBAR_EDU_TOOLTIP_STEP,
82     })
83     @Retention(RetentionPolicy.SOURCE)
84     public @interface EventCountKey {}
85 
86     private static final Map<String, Integer> MAX_COUNTS;
87 
88     static {
89         Map<String, Integer> maxCounts = new ArrayMap<>(5);
maxCounts.put(HOME_BOUNCE_COUNT, 3)90         maxCounts.put(HOME_BOUNCE_COUNT, 3);
maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5)91         maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
maxCounts.put(SEARCH_SNACKBAR_COUNT, 3)92         maxCounts.put(SEARCH_SNACKBAR_COUNT, 3);
93         // This is the sum of all onboarding cards. Currently there is only 1 card shown 3 times.
maxCounts.put(SEARCH_ONBOARDING_COUNT, 3)94         maxCounts.put(SEARCH_ONBOARDING_COUNT, 3);
maxCounts.put(ALL_APPS_VISITED_COUNT, 20)95         maxCounts.put(ALL_APPS_VISITED_COUNT, 20);
maxCounts.put(TASKBAR_EDU_TOOLTIP_STEP, 2)96         maxCounts.put(TASKBAR_EDU_TOOLTIP_STEP, 2);
97         MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
98     }
99 
100     protected final T mLauncher;
101     protected final SharedPreferences mSharedPrefs;
102 
OnboardingPrefs(T launcher, SharedPreferences sharedPrefs)103     public OnboardingPrefs(T launcher, SharedPreferences sharedPrefs) {
104         mLauncher = launcher;
105         mSharedPrefs = sharedPrefs;
106     }
107 
108     /** @return The number of times we have seen the given event. */
getCount(@ventCountKey String key)109     public int getCount(@EventCountKey String key) {
110         return mSharedPrefs.getInt(key, 0);
111     }
112 
113     /** @return Whether we have seen this event enough times, as defined by {@link #MAX_COUNTS}. */
hasReachedMaxCount(@ventCountKey String eventKey)114     public boolean hasReachedMaxCount(@EventCountKey String eventKey) {
115         return hasReachedMaxCount(getCount(eventKey), eventKey);
116     }
117 
hasReachedMaxCount(int count, @EventCountKey String eventKey)118     private boolean hasReachedMaxCount(int count, @EventCountKey String eventKey) {
119         return count >= MAX_COUNTS.get(eventKey);
120     }
121 
122     /** @return Whether we have seen the given event. */
getBoolean(@ventBoolKey String key)123     public boolean getBoolean(@EventBoolKey String key) {
124         return mSharedPrefs.getBoolean(key, false);
125     }
126 
127     /**
128      * Marks on-boarding preference boolean at true
129      */
markChecked(String flag)130     public void markChecked(String flag) {
131         mSharedPrefs.edit().putBoolean(flag, true).apply();
132     }
133 
134     /**
135      * Add 1 to the given event count, if we haven't already reached the max count.
136      *
137      * @return Whether we have now reached the max count.
138      */
incrementEventCount(@ventCountKey String eventKey)139     public boolean incrementEventCount(@EventCountKey String eventKey) {
140         int count = getCount(eventKey);
141         if (hasReachedMaxCount(count, eventKey)) {
142             return true;
143         }
144         count++;
145         mSharedPrefs.edit().putInt(eventKey, count).apply();
146         return hasReachedMaxCount(count, eventKey);
147     }
148 
149     /**
150      * Sets the event count to the given value.
151      *
152      * @return Whether we have now reached the max count.
153      */
setEventCount(int count, @EventCountKey String eventKey)154     public boolean setEventCount(int count, @EventCountKey String eventKey) {
155         mSharedPrefs.edit().putInt(eventKey, count).apply();
156         return hasReachedMaxCount(count, eventKey);
157     }
158 }
159