/* * Copyright (C) 2017 The Android Open Source Project * * This file is derived in part from code issued under the following license. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.android.dialer.oem; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.support.annotation.VisibleForTesting; import com.android.dialer.common.LogUtil; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; /** * Util class to handle special char sequence and launch corresponding intent based the sequence. */ public class MotorolaHiddenMenuKeySequence { private static final String EXTRA_HIDDEN_MENU_CODE = "HiddenMenuCode"; private static MotorolaHiddenMenuKeySequence instance = null; @VisibleForTesting final List hiddenKeySequences = new ArrayList<>(); @VisibleForTesting final List hiddenKeySequenceIntents = new ArrayList<>(); @VisibleForTesting final List hiddenKeyPatterns = new ArrayList<>(); @VisibleForTesting final List hiddenKeyPatternIntents = new ArrayList<>(); @VisibleForTesting boolean featureHiddenMenuEnabled = false; /** * Handle input char sequence. * * @param context context * @param input input sequence * @return true if the input matches any pattern */ static boolean handleCharSequence(Context context, String input) { if (!getInstance(context).featureHiddenMenuEnabled) { return false; } return handleKeySequence(context, input) || handleKeyPattern(context, input); } /** * Public interface to return the Singleton instance * * @param context the Context * @return the MotorolaHiddenMenuKeySequence singleton instance */ private static synchronized MotorolaHiddenMenuKeySequence getInstance(Context context) { if (null == instance) { instance = new MotorolaHiddenMenuKeySequence(context, new SystemPropertiesAccessor()); } return instance; } @VisibleForTesting MotorolaHiddenMenuKeySequence( Context context, SystemPropertiesAccessor systemPropertiesAccessor) { if (MotorolaUtils.isSupportingHiddenMenu(context)) { Collections.addAll( hiddenKeySequences, context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence)); Collections.addAll( hiddenKeySequenceIntents, context.getResources().getStringArray(R.array.motorola_hidden_menu_key_sequence_intents)); Collections.addAll( hiddenKeyPatterns, context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern)); Collections.addAll( hiddenKeyPatternIntents, context.getResources().getStringArray(R.array.motorola_hidden_menu_key_pattern_intents)); featureHiddenMenuEnabled = true; } if ("tracfone".equals(systemPropertiesAccessor.get("ro.carrier"))) { addHiddenKeySequence("#83865625#", "com.motorola.extensions.TFUnlock"); addHiddenKeySequence("#83782887#", "com.motorola.extensions.TFStatus"); featureHiddenMenuEnabled = true; } if (hiddenKeySequences.size() != hiddenKeySequenceIntents.size() || hiddenKeyPatterns.size() != hiddenKeyPatternIntents.size() || (hiddenKeySequences.isEmpty() && hiddenKeyPatterns.isEmpty())) { LogUtil.e( "MotorolaHiddenMenuKeySequence", "the key sequence array is not matching, turn off feature." + "key sequence: %d != %d, key pattern %d != %d", hiddenKeySequences.size(), hiddenKeySequenceIntents.size(), hiddenKeyPatterns.size(), hiddenKeyPatternIntents.size()); featureHiddenMenuEnabled = false; } } private void addHiddenKeySequence(String keySequence, String intentAction) { hiddenKeySequences.add(keySequence); hiddenKeySequenceIntents.add(intentAction); } private static boolean handleKeyPattern(Context context, String input) { MotorolaHiddenMenuKeySequence instance = getInstance(context); int len = input.length(); if (len <= 3 || instance.hiddenKeyPatterns == null || instance.hiddenKeyPatternIntents == null) { return false; } for (int i = 0; i < instance.hiddenKeyPatterns.size(); i++) { if (Pattern.matches(instance.hiddenKeyPatterns.get(i), input)) { return sendIntent(context, input, instance.hiddenKeyPatternIntents.get(i)); } } return false; } private static boolean handleKeySequence(Context context, String input) { MotorolaHiddenMenuKeySequence instance = getInstance(context); int len = input.length(); if (len <= 3 || instance.hiddenKeySequences == null || instance.hiddenKeySequenceIntents == null) { return false; } for (int i = 0; i < instance.hiddenKeySequences.size(); i++) { if (instance.hiddenKeySequences.get(i).equals(input)) { return sendIntent(context, input, instance.hiddenKeySequenceIntents.get(i)); } } return false; } private static boolean sendIntent( final Context context, final String input, final String action) { LogUtil.d("MotorolaHiddenMenuKeySequence.sendIntent", "input: %s", input); try { Intent intent = new Intent(action); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(EXTRA_HIDDEN_MENU_CODE, input); ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0); if (resolveInfo != null && resolveInfo.activityInfo != null && resolveInfo.activityInfo.enabled) { context.startActivity(intent); return true; } else { LogUtil.w("MotorolaHiddenMenuKeySequence.sendIntent", "not able to resolve the intent"); } } catch (ActivityNotFoundException e) { LogUtil.e( "MotorolaHiddenMenuKeySequence.sendIntent", "handleHiddenMenu Key Pattern Exception", e); } return false; } }