• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * This file is derived in part from code issued under the following license.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 package com.android.dialer.oem;
20 
21 import android.content.ActivityNotFoundException;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.ResolveInfo;
25 import android.support.annotation.VisibleForTesting;
26 import com.android.dialer.common.LogUtil;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.List;
30 import java.util.regex.Pattern;
31 
32 /**
33  * Util class to handle special char sequence and launch corresponding intent based the sequence.
34  */
35 public class MotorolaHiddenMenuKeySequence {
36   private static final String EXTRA_HIDDEN_MENU_CODE = "HiddenMenuCode";
37 
38   private static MotorolaHiddenMenuKeySequence instance = null;
39 
40   @VisibleForTesting final List<String> hiddenKeySequences = new ArrayList<>();
41   @VisibleForTesting final List<String> hiddenKeySequenceIntents = new ArrayList<>();
42   @VisibleForTesting final List<String> hiddenKeyPatterns = new ArrayList<>();
43   @VisibleForTesting final List<String> hiddenKeyPatternIntents = new ArrayList<>();
44   @VisibleForTesting boolean featureHiddenMenuEnabled = false;
45 
46   /**
47    * Handle input char sequence.
48    *
49    * @param context context
50    * @param input input sequence
51    * @return true if the input matches any pattern
52    */
handleCharSequence(Context context, String input)53   static boolean handleCharSequence(Context context, String input) {
54     if (!getInstance(context).featureHiddenMenuEnabled) {
55       return false;
56     }
57     return handleKeySequence(context, input) || handleKeyPattern(context, input);
58   }
59 
60   /**
61    * Public interface to return the Singleton instance
62    *
63    * @param context the Context
64    * @return the MotorolaHiddenMenuKeySequence singleton instance
65    */
getInstance(Context context)66   private static synchronized MotorolaHiddenMenuKeySequence getInstance(Context context) {
67     if (null == instance) {
68       instance = new MotorolaHiddenMenuKeySequence(context, new SystemPropertiesAccessor());
69     }
70     return instance;
71   }
72 
73   @VisibleForTesting
MotorolaHiddenMenuKeySequence( Context context, SystemPropertiesAccessor systemPropertiesAccessor)74   MotorolaHiddenMenuKeySequence(
75       Context context, SystemPropertiesAccessor systemPropertiesAccessor) {
76     if (MotorolaUtils.isSupportingHiddenMenu(context)) {
77       Collections.addAll(
78           hiddenKeySequences,
79           context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence));
80       Collections.addAll(
81           hiddenKeySequenceIntents,
82           context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence_intents));
83       Collections.addAll(
84           hiddenKeyPatterns,
85           context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern));
86       Collections.addAll(
87           hiddenKeyPatternIntents,
88           context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern_intents));
89       featureHiddenMenuEnabled = true;
90     }
91 
92     if ("tracfone".equals(systemPropertiesAccessor.get("ro.carrier"))) {
93       addHiddenKeySequence("#83865625#", "com.motorola.extensions.TFUnlock");
94       addHiddenKeySequence("#83782887#", "com.motorola.extensions.TFStatus");
95       featureHiddenMenuEnabled = true;
96     }
97 
98     if (hiddenKeySequences.size() != hiddenKeySequenceIntents.size()
99         || hiddenKeyPatterns.size() != hiddenKeyPatternIntents.size()
100         || (hiddenKeySequences.isEmpty() && hiddenKeyPatterns.isEmpty())) {
101       LogUtil.e(
102           "MotorolaHiddenMenuKeySequence",
103           "the key sequence array is not matching, turn off feature."
104               + "key sequence: %d != %d, key pattern %d != %d",
105           hiddenKeySequences.size(),
106           hiddenKeySequenceIntents.size(),
107           hiddenKeyPatterns.size(),
108           hiddenKeyPatternIntents.size());
109       featureHiddenMenuEnabled = false;
110     }
111   }
112 
addHiddenKeySequence(String keySequence, String intentAction)113   private void addHiddenKeySequence(String keySequence, String intentAction) {
114     hiddenKeySequences.add(keySequence);
115     hiddenKeySequenceIntents.add(intentAction);
116   }
117 
handleKeyPattern(Context context, String input)118   private static boolean handleKeyPattern(Context context, String input) {
119     MotorolaHiddenMenuKeySequence instance = getInstance(context);
120 
121     int len = input.length();
122     if (len <= 3
123         || instance.hiddenKeyPatterns == null
124         || instance.hiddenKeyPatternIntents == null) {
125       return false;
126     }
127 
128     for (int i = 0; i < instance.hiddenKeyPatterns.size(); i++) {
129       if (Pattern.matches(instance.hiddenKeyPatterns.get(i), input)) {
130         return sendIntent(context, input, instance.hiddenKeyPatternIntents.get(i));
131       }
132     }
133     return false;
134   }
135 
handleKeySequence(Context context, String input)136   private static boolean handleKeySequence(Context context, String input) {
137     MotorolaHiddenMenuKeySequence instance = getInstance(context);
138 
139     int len = input.length();
140     if (len <= 3
141         || instance.hiddenKeySequences == null
142         || instance.hiddenKeySequenceIntents == null) {
143       return false;
144     }
145 
146     for (int i = 0; i < instance.hiddenKeySequences.size(); i++) {
147       if (instance.hiddenKeySequences.get(i).equals(input)) {
148         return sendIntent(context, input, instance.hiddenKeySequenceIntents.get(i));
149       }
150     }
151     return false;
152   }
153 
sendIntent( final Context context, final String input, final String action)154   private static boolean sendIntent(
155       final Context context, final String input, final String action) {
156     LogUtil.d("MotorolaHiddenMenuKeySequence.sendIntent", "input: %s", input);
157     try {
158       Intent intent = new Intent(action);
159       intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
160       intent.putExtra(EXTRA_HIDDEN_MENU_CODE, input);
161 
162       ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
163 
164       if (resolveInfo != null
165           && resolveInfo.activityInfo != null
166           && resolveInfo.activityInfo.enabled) {
167         context.startActivity(intent);
168         return true;
169       } else {
170         LogUtil.w("MotorolaHiddenMenuKeySequence.sendIntent", "not able to resolve the intent");
171       }
172     } catch (ActivityNotFoundException e) {
173       LogUtil.e(
174           "MotorolaHiddenMenuKeySequence.sendIntent", "handleHiddenMenu Key Pattern Exception", e);
175     }
176     return false;
177   }
178 }
179