1 /*
2  * Copyright (C) 2016 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.incallui.answer.impl.hint;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.graphics.drawable.Drawable;
22 import android.os.Build;
23 import android.support.annotation.NonNull;
24 import android.support.annotation.VisibleForTesting;
25 import com.android.dialer.common.Assert;
26 import com.android.dialer.common.LogUtil;
27 import com.android.dialer.configprovider.ConfigProviderComponent;
28 import com.android.dialer.storage.StorageComponent;
29 import com.android.incallui.util.AccessibilityUtil;
30 
31 /**
32  * Selects a AnswerHint to show. If there's no suitable hints {@link EmptyAnswerHint} will be used,
33  * which does nothing.
34  */
35 public class AnswerHintFactory {
36 
37   @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
38   static final String CONFIG_ANSWER_HINT_ANSWERED_THRESHOLD_KEY = "answer_hint_answered_threshold";
39 
40   @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
41   static final String CONFIG_ANSWER_HINT_WHITELISTED_DEVICES_KEY =
42       "answer_hint_whitelisted_devices";
43   // Most popular devices released before NDR1 is whitelisted. Their user are likely to have seen
44   // the legacy UI.
45   private static final String DEFAULT_WHITELISTED_DEVICES_CSV =
46       "/hammerhead//bullhead//angler//shamu//gm4g//gm4g_s//AQ4501//gce_x86_phone//gm4gtkc_s/"
47           + "/Sparkle_V//Mi-498//AQ4502//imobileiq2//A65//H940//m8_google//m0xx//A10//ctih220/"
48           + "/Mi438S//bacon/";
49 
50   @VisibleForTesting
51   static final String ANSWERED_COUNT_PREFERENCE_KEY = "answer_hint_answered_count";
52 
53   private final PawImageLoader pawImageLoader;
54 
AnswerHintFactory(@onNull PawImageLoader pawImageLoader)55   public AnswerHintFactory(@NonNull PawImageLoader pawImageLoader) {
56     this.pawImageLoader = Assert.isNotNull(pawImageLoader);
57   }
58 
59   @NonNull
create(Context context, long puckUpDuration, long puckUpDelay)60   public AnswerHint create(Context context, long puckUpDuration, long puckUpDelay) {
61     if (shouldShowAnswerHint(context, Build.PRODUCT)) {
62       return new DotAnswerHint(context, puckUpDuration, puckUpDelay);
63     }
64 
65     // Display the event answer hint if the payload is available.
66     Drawable eventPayload = pawImageLoader.loadPayload(context);
67     if (eventPayload != null) {
68       return new PawAnswerHint(context, eventPayload, puckUpDuration, puckUpDelay);
69     }
70 
71     return new EmptyAnswerHint();
72   }
73 
increaseAnsweredCount(Context context)74   public static void increaseAnsweredCount(Context context) {
75     SharedPreferences sharedPreferences = StorageComponent.get(context).unencryptedSharedPrefs();
76     int answeredCount = sharedPreferences.getInt(ANSWERED_COUNT_PREFERENCE_KEY, 0);
77     sharedPreferences.edit().putInt(ANSWERED_COUNT_PREFERENCE_KEY, answeredCount + 1).apply();
78   }
79 
80   @VisibleForTesting
shouldShowAnswerHint(Context context, String device)81   static boolean shouldShowAnswerHint(Context context, String device) {
82     if (AccessibilityUtil.isTouchExplorationEnabled(context)) {
83       return false;
84     }
85     // Devices that has the legacy dialer installed are whitelisted as they are likely to go through
86     // a UX change during updates.
87     if (!isDeviceWhitelisted(context, device)) {
88       return false;
89     }
90 
91     // If the user has gone through the process a few times we can assume they have learnt the
92     // method.
93     int answeredCount =
94         StorageComponent.get(context)
95             .unencryptedSharedPrefs()
96             .getInt(ANSWERED_COUNT_PREFERENCE_KEY, 0);
97     long threshold =
98         ConfigProviderComponent.get(context)
99             .getConfigProvider()
100             .getLong(CONFIG_ANSWER_HINT_ANSWERED_THRESHOLD_KEY, 3);
101     LogUtil.i(
102         "AnswerHintFactory.shouldShowAnswerHint",
103         "answerCount: %d, threshold: %d",
104         answeredCount,
105         threshold);
106     return answeredCount < threshold;
107   }
108 
109   /**
110    * @param device should be the value of{@link Build#PRODUCT}.
111    * @param configProvider should provide a list of devices quoted with '/' concatenated to a
112    *     string.
113    */
isDeviceWhitelisted(Context context, String device)114   private static boolean isDeviceWhitelisted(Context context, String device) {
115     return ConfigProviderComponent.get(context)
116         .getConfigProvider()
117         .getString(CONFIG_ANSWER_HINT_WHITELISTED_DEVICES_KEY, DEFAULT_WHITELISTED_DEVICES_CSV)
118         .contains("/" + device + "/");
119   }
120 }
121