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 com.android.dialer.common.LogUtil; 26 import java.util.regex.Pattern; 27 28 /** 29 * Util class to handle special char sequence and launch corresponding intent based the sequence. 30 */ 31 public class MotorolaHiddenMenuKeySequence { 32 private static final String EXTRA_HIDDEN_MENU_CODE = "HiddenMenuCode"; 33 private static MotorolaHiddenMenuKeySequence instance = null; 34 35 private static String[] hiddenKeySequenceArray = null; 36 private static String[] hiddenKeySequenceIntentArray = null; 37 private static String[] hiddenKeyPatternArray = null; 38 private static String[] hiddenKeyPatternIntentArray = null; 39 private static boolean featureHiddenMenuEnabled = false; 40 41 /** 42 * Handle input char sequence. 43 * 44 * @param context context 45 * @param input input sequence 46 * @return true if the input matches any pattern 47 */ handleCharSequence(Context context, String input)48 static boolean handleCharSequence(Context context, String input) { 49 getInstance(context); 50 if (!featureHiddenMenuEnabled) { 51 return false; 52 } 53 return handleKeySequence(context, input) || handleKeyPattern(context, input); 54 } 55 56 /** 57 * Public interface to return the Singleton instance 58 * 59 * @param context the Context 60 * @return the MotorolaHiddenMenuKeySequence singleton instance 61 */ getInstance(Context context)62 private static synchronized MotorolaHiddenMenuKeySequence getInstance(Context context) { 63 if (null == instance) { 64 instance = new MotorolaHiddenMenuKeySequence(context); 65 } 66 return instance; 67 } 68 MotorolaHiddenMenuKeySequence(Context context)69 private MotorolaHiddenMenuKeySequence(Context context) { 70 featureHiddenMenuEnabled = 71 MotorolaUtils.isSpnMatched(context) 72 && context.getResources().getBoolean(R.bool.motorola_feature_hidden_menu); 73 // In case we do have a SPN from resource we need to match from service; otherwise we are 74 // free to go 75 if (featureHiddenMenuEnabled) { 76 77 hiddenKeySequenceArray = 78 context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence); 79 hiddenKeySequenceIntentArray = 80 context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence_intents); 81 hiddenKeyPatternArray = 82 context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern); 83 hiddenKeyPatternIntentArray = 84 context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern_intents); 85 86 if (hiddenKeySequenceArray.length != hiddenKeySequenceIntentArray.length 87 || hiddenKeyPatternArray.length != hiddenKeyPatternIntentArray.length 88 || (hiddenKeySequenceArray.length == 0 && hiddenKeyPatternArray.length == 0)) { 89 LogUtil.e( 90 "MotorolaHiddenMenuKeySequence", 91 "the key sequence array is not matching, turn off feature." 92 + "key sequence: %d != %d, key pattern %d != %d", 93 hiddenKeySequenceArray.length, 94 hiddenKeySequenceIntentArray.length, 95 hiddenKeyPatternArray.length, 96 hiddenKeyPatternIntentArray.length); 97 featureHiddenMenuEnabled = false; 98 } 99 } 100 } 101 handleKeyPattern(Context context, String input)102 private static boolean handleKeyPattern(Context context, String input) { 103 int len = input.length(); 104 if (len <= 3 || hiddenKeyPatternArray == null || hiddenKeyPatternIntentArray == null) { 105 return false; 106 } 107 108 for (int i = 0; i < hiddenKeyPatternArray.length; i++) { 109 if ((Pattern.compile(hiddenKeyPatternArray[i])).matcher(input).matches()) { 110 return sendIntent(context, input, hiddenKeyPatternIntentArray[i]); 111 } 112 } 113 return false; 114 } 115 handleKeySequence(Context context, String input)116 private static boolean handleKeySequence(Context context, String input) { 117 int len = input.length(); 118 if (len <= 3 || hiddenKeySequenceArray == null || hiddenKeySequenceIntentArray == null) { 119 return false; 120 } 121 122 for (int i = 0; i < hiddenKeySequenceArray.length; i++) { 123 if (hiddenKeySequenceArray[i].equals(input)) { 124 return sendIntent(context, input, hiddenKeySequenceIntentArray[i]); 125 } 126 } 127 return false; 128 } 129 sendIntent( final Context context, final String input, final String action)130 private static boolean sendIntent( 131 final Context context, final String input, final String action) { 132 LogUtil.d("MotorolaHiddenMenuKeySequence.sendIntent", "input: %s", input); 133 try { 134 Intent intent = new Intent(action); 135 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); 136 intent.putExtra(EXTRA_HIDDEN_MENU_CODE, input); 137 138 ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0); 139 140 if (resolveInfo != null 141 && resolveInfo.activityInfo != null 142 && resolveInfo.activityInfo.enabled) { 143 context.startActivity(intent); 144 return true; 145 } else { 146 LogUtil.w("MotorolaHiddenMenuKeySequence.sendIntent", "not able to resolve the intent"); 147 } 148 } catch (ActivityNotFoundException e) { 149 LogUtil.e( 150 "MotorolaHiddenMenuKeySequence.sendIntent", "handleHiddenMenu Key Pattern Exception", e); 151 } 152 return false; 153 } 154 } 155