• 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
setInstanceForTest(MotorolaHiddenMenuKeySequence instance)74   static void setInstanceForTest(MotorolaHiddenMenuKeySequence instance) {
75     MotorolaHiddenMenuKeySequence.instance = instance;
76   }
77 
78   @VisibleForTesting
MotorolaHiddenMenuKeySequence( Context context, SystemPropertiesAccessor systemPropertiesAccessor)79   MotorolaHiddenMenuKeySequence(
80       Context context, SystemPropertiesAccessor systemPropertiesAccessor) {
81     if (MotorolaUtils.isSupportingHiddenMenu(context)) {
82       Collections.addAll(
83           hiddenKeySequences,
84           context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence));
85       Collections.addAll(
86           hiddenKeySequenceIntents,
87           context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence_intents));
88       Collections.addAll(
89           hiddenKeyPatterns,
90           context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern));
91       Collections.addAll(
92           hiddenKeyPatternIntents,
93           context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern_intents));
94       featureHiddenMenuEnabled = true;
95     }
96 
97     if ("tracfone".equals(systemPropertiesAccessor.get("ro.carrier"))) {
98       addHiddenKeySequence("#83865625#", "com.motorola.extensions.TFUnlock");
99       addHiddenKeySequence("#83782887#", "com.motorola.extensions.TFStatus");
100       featureHiddenMenuEnabled = true;
101     }
102 
103     if (hiddenKeySequences.size() != hiddenKeySequenceIntents.size()
104         || hiddenKeyPatterns.size() != hiddenKeyPatternIntents.size()
105         || (hiddenKeySequences.isEmpty() && hiddenKeyPatterns.isEmpty())) {
106       LogUtil.e(
107           "MotorolaHiddenMenuKeySequence",
108           "the key sequence array is not matching, turn off feature."
109               + "key sequence: %d != %d, key pattern %d != %d",
110           hiddenKeySequences.size(),
111           hiddenKeySequenceIntents.size(),
112           hiddenKeyPatterns.size(),
113           hiddenKeyPatternIntents.size());
114       featureHiddenMenuEnabled = false;
115     }
116   }
117 
addHiddenKeySequence(String keySequence, String intentAction)118   private void addHiddenKeySequence(String keySequence, String intentAction) {
119     hiddenKeySequences.add(keySequence);
120     hiddenKeySequenceIntents.add(intentAction);
121   }
122 
handleKeyPattern(Context context, String input)123   private static boolean handleKeyPattern(Context context, String input) {
124     MotorolaHiddenMenuKeySequence instance = getInstance(context);
125 
126     int len = input.length();
127     if (len <= 3
128         || instance.hiddenKeyPatterns == null
129         || instance.hiddenKeyPatternIntents == null) {
130       return false;
131     }
132 
133     for (int i = 0; i < instance.hiddenKeyPatterns.size(); i++) {
134       if (Pattern.matches(instance.hiddenKeyPatterns.get(i), input)) {
135         return sendIntent(context, input, instance.hiddenKeyPatternIntents.get(i));
136       }
137     }
138     return false;
139   }
140 
handleKeySequence(Context context, String input)141   private static boolean handleKeySequence(Context context, String input) {
142     MotorolaHiddenMenuKeySequence instance = getInstance(context);
143 
144     int len = input.length();
145     if (len <= 3
146         || instance.hiddenKeySequences == null
147         || instance.hiddenKeySequenceIntents == null) {
148       return false;
149     }
150 
151     for (int i = 0; i < instance.hiddenKeySequences.size(); i++) {
152       if (instance.hiddenKeySequences.get(i).equals(input)) {
153         return sendIntent(context, input, instance.hiddenKeySequenceIntents.get(i));
154       }
155     }
156     return false;
157   }
158 
sendIntent( final Context context, final String input, final String action)159   private static boolean sendIntent(
160       final Context context, final String input, final String action) {
161     LogUtil.d("MotorolaHiddenMenuKeySequence.sendIntent", "input: %s", input);
162     try {
163       Intent intent = new Intent(action);
164       intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
165       intent.putExtra(EXTRA_HIDDEN_MENU_CODE, input);
166 
167       ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
168 
169       if (resolveInfo != null
170           && resolveInfo.activityInfo != null
171           && resolveInfo.activityInfo.enabled) {
172         context.startActivity(intent);
173         return true;
174       } else {
175         LogUtil.w("MotorolaHiddenMenuKeySequence.sendIntent", "not able to resolve the intent");
176       }
177     } catch (ActivityNotFoundException e) {
178       LogUtil.e(
179           "MotorolaHiddenMenuKeySequence.sendIntent", "handleHiddenMenu Key Pattern Exception", e);
180     }
181     return false;
182   }
183 }
184