summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorqjohn <townex22@gmail.com>2018-06-29 04:26:43 +0700
committerqjohn <townex22@gmail.com>2018-06-29 04:26:43 +0700
commitcbe68b2b01b100c2760f4d2aaad55dd876b53b51 (patch)
tree8de97822f2bcd8257a313e728176d33f5419bdea
parentca0bc0ae505db0576d208ab5652129e3e236e888 (diff)
parent5adcc23120fdb80e5b7e91cb6bb5e0d79a8f4db3 (diff)
Merge branch 'o8.1' of https://github.com/AICP/external_DUtils into o8.1
-rw-r--r--Android.mk27
-rw-r--r--src/com/android/internal/utils/du/ActionConstants.java649
-rw-r--r--src/com/android/internal/utils/du/ActionHandler.java1169
-rw-r--r--src/com/android/internal/utils/du/ActionHolder.java43
-rw-r--r--src/com/android/internal/utils/du/Config.java563
-rw-r--r--src/com/android/internal/utils/du/DUActionUtils.java759
-rw-r--r--src/com/android/internal/utils/du/DUPackageMonitor.java126
-rw-r--r--src/com/android/internal/utils/du/DUSystemReceiver.java68
-rw-r--r--src/com/android/internal/utils/du/ImageHelper.java299
-rw-r--r--src/com/android/internal/utils/du/UserContentObserver.java92
10 files changed, 3778 insertions, 17 deletions
diff --git a/Android.mk b/Android.mk
index d543ba4..97a1333 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,18 +1,11 @@
-#LOCAL_PATH:= $(call my-dir)
-#
-#include $(CLEAR_VARS)
-#
-#LOCAL_JAVA_LIBRARIES := org.dirtyunicorns.utils
-#
-#LOCAL_STATIC_JAVA_LIBRARIES := \
-# trail-drawing \
-# rebound
-#
-#LOCAL_SRC_FILES := $(call all-java-files-under, src)
-#
-#LOCAL_MODULE_TAGS := optional
-#
-#LOCAL_MODULE := org.dirtyunicorns.navigation-static-internal
-#
-#include $(BUILD_STATIC_JAVA_LIBRARY)
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := org.dirtyunicorns.utils
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/src/com/android/internal/utils/du/ActionConstants.java b/src/com/android/internal/utils/du/ActionConstants.java
new file mode 100644
index 0000000..34c58bd
--- /dev/null
+++ b/src/com/android/internal/utils/du/ActionConstants.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2015 TeamEos project
+ * Author Randall Rushing aka bigrushdog, randall.rushing@gmail.com
+ *
+ * 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.
+ *
+ * ActionConstants.java: A helper class to assist Config.java with loading
+ * and assigning default feature configurations. Nested classes implement
+ * the static interface Defaults, which allows Settings and Config.java
+ * to handle configurations in a non-implementation specific way, allowing
+ * for more generalized code structures.
+ *
+ * Of strong importance is the ConfigMap pojo class. Current settings use
+ * a ActionPreference which sets a single action. Therefore, we must have a
+ * way to map individual actions to their associated buttons. ActionPreference
+ * key MUST match the tag associated with the target ConfigMap.
+ *
+ */
+
+package com.android.internal.utils.du;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.android.internal.utils.du.ActionHandler.SystemAction;
+import com.android.internal.utils.du.Config.ActionConfig;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.TypedValue;
+
+public class ActionConstants {
+ public static interface Defaults {
+ public int getConfigType();
+ public String getUri();
+ public String getDefaultConfig();
+ public int getMaxButtons();
+ public Map<String, ConfigMap> getActionMap();
+ public Bundle getConfigs(Context context);
+ }
+
+ public static final String ACTION_DELIMITER = "|";
+ public static final String EMPTY = "empty";
+ public static final int SMARTBAR = 1;
+ public static final int HWKEYS = 2;
+ public static final int FLING = 3;
+ public static final int PIE_PRIMARY = 4;
+ public static final int PIE_SECONDARY = 5;
+
+ private static final Smartbar smartbar = new Smartbar();
+ private static final Hwkeys hwkeys = new Hwkeys();
+ private static final Fling fling = new Fling();
+ private static final PiePrimary pie_primary = new PiePrimary();
+ private static final PieSecond pie_second = new PieSecond();
+
+ public static Defaults getDefaults(int type) {
+ if (type == SMARTBAR) {
+ return smartbar;
+ } else if (type == HWKEYS) {
+ return hwkeys;
+ } else if (type == FLING) {
+ return fling;
+ } else if (type == PIE_PRIMARY){
+ return pie_primary;
+ } else if (type == PIE_SECONDARY) {
+ return pie_second;
+ } else {
+ return null;
+ }
+ }
+
+ public static String dl(String s) {
+ return s + ACTION_DELIMITER;
+ }
+
+ public static class Smartbar implements Defaults {
+ public static final int SMARTBAR_MAX_BUTTONS = 10;
+ public static final String SMARTBAR_DEF_BUTTONS = "3";
+ public static final String BUTTON1_TAG = "smartbar_button_1";
+ public static final String BUTTON2_TAG = "smartbar_button_2";
+ public static final String BUTTON3_TAG = "smartbar_button_3";
+ public static final String BUTTON4_TAG = "smartbar_button_4";
+ public static final String BUTTON5_TAG = "smartbar_button_5";
+ public static final String BUTTON6_TAG = "smartbar_button_6";
+ public static final String BUTTON7_TAG = "smartbar_button_7";
+
+ public static final String SMARTBAR_CONFIG_DEFAULT =
+ dl(SMARTBAR_DEF_BUTTONS) // default number of ButtonConfig
+ + dl(BUTTON1_TAG) // button tag
+ + dl(SystemAction.Back.mAction) + dl(SystemAction.Back.mLabelRes) + dl(EMPTY) // single tap (PRIMARY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // long press (SECOND)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // double tap (THIRD)
+
+ + dl(BUTTON2_TAG)
+ + dl(SystemAction.Home.mAction) + dl(SystemAction.Home.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.GoogleNowOnTap.mAction) + dl(SystemAction.GoogleNowOnTap.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+
+ + dl(BUTTON3_TAG)
+ + dl(SystemAction.Overview.mAction) + dl(SystemAction.Overview.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.SplitScreen.mAction) + dl(SystemAction.SplitScreen.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + EMPTY;
+/*
+ + dl(BUTTON4_TAG)
+ + dl(SystemAction.ExpandedDesktop.mAction) + dl(SystemAction.ExpandedDesktop.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.Flashlight.mAction) + dl(SystemAction.Flashlight.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.PowerMenu.mAction) + dl(SystemAction.PowerMenu.mLabelRes) + dl(EMPTY)
+
+ + dl(BUTTON5_TAG)
+ + dl(SystemAction.Screenrecord.mAction) + dl(SystemAction.Screenrecord.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.KillApp.mAction) + dl(SystemAction.KillApp.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.ScreenOff.mAction) + dl(SystemAction.ScreenOff.mLabelRes) + EMPTY;
+*/
+ @Override
+ public String getUri() {
+ return "smartbar_button_config";
+ }
+
+ @Override
+ public String getDefaultConfig() {
+ return SMARTBAR_CONFIG_DEFAULT;
+ }
+
+ @Override
+ public int getMaxButtons() {
+ return SMARTBAR_MAX_BUTTONS;
+ }
+
+ @Override
+ public int getConfigType() {
+ return SMARTBAR;
+ }
+
+ @Override
+ public Map<String, ConfigMap> getActionMap() {
+ return null;
+ }
+
+ @Override
+ public Bundle getConfigs(Context context) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ }
+
+ public static class Hwkeys implements Defaults {
+ public static final int HWKEY_MAX_BUTTONS = 7;
+ public static final String HWKEY_DEF_BUTTONS = "5";
+ public static final String BACK_BUTTON_TAG = "hwkeys_button_back";
+ public static final String HOME_BUTTON_TAG = "hwkeys_button_home";
+ public static final String OVERVIEW_BUTTON_TAG = "hwkeys_button_overview";
+ public static final String MENU_BUTTON_TAG = "hwkeys_button_menu";
+ public static final String ASSIST_BUTTON_TAG = "hwkeys_button_assist";
+ public static final String EXTRA1_BUTTON_TAG = "hwkeys_button_camera";
+ public static final String EXTRA2_BUTTON_TAG = "hwkeys_button_extra";
+
+ public static final String BACK_BUTTON_SINGLE_TAP_TAG = "hwkeys_button_back_single_tap";
+ public static final String HOME_BUTTON_SINGLE_TAP_TAG = "hwkeys_button_home_single_tap";
+ public static final String OVERVIEW_BUTTON_SINGLE_TAP_TAG = "hwkeys_button_overview_single_tap";
+ public static final String MENU_BUTTON_SINGLE_TAP_TAG = "hwkeys_button_menu_single_tap";
+ public static final String ASSIST_BUTTON_SINGLE_TAP_TAG = "hwkeys_button_assist_single_tap";
+
+ public static final String BACK_BUTTON_LONG_PRESS_TAG = "hwkeys_button_back_long_press";
+ public static final String HOME_BUTTON_LONG_PRESS_TAG = "hwkeys_button_home_long_press";
+ public static final String OVERVIEW_BUTTON_LONG_PRESS_TAG = "hwkeys_button_overview_long_press";
+ public static final String MENU_BUTTON_LONG_PRESS_TAG = "hwkeys_button_menu_long_press";
+ public static final String ASSIST_BUTTON_LONG_PRESS_TAG = "hwkeys_button_assist_long_press";
+
+ public static final String BACK_BUTTON_DOUBLE_TAP_TAG = "hwkeys_button_back_double_tap";
+ public static final String HOME_BUTTON_DOUBLE_TAP_TAG = "hwkeys_button_home_double_tap";
+ public static final String OVERVIEW_BUTTON_DOUBLE_TAP_TAG = "hwkeys_button_overview_double_tap";
+ public static final String MENU_BUTTON_DOUBLE_TAP_TAG = "hwkeys_button_menu_double_tap";
+ public static final String ASSIST_BUTTON_DOUBLE_TAP_TAG = "hwkeys_button_assist_double_tap";
+
+ private static final Map<String, ConfigMap> configMap = new HashMap<String, ConfigMap>();
+
+ static {
+ configMap.put(BACK_BUTTON_SINGLE_TAP_TAG, new ConfigMap(0, ActionConfig.PRIMARY));
+ configMap.put(HOME_BUTTON_SINGLE_TAP_TAG, new ConfigMap(1, ActionConfig.PRIMARY));
+ configMap.put(OVERVIEW_BUTTON_SINGLE_TAP_TAG, new ConfigMap(2, ActionConfig.PRIMARY));
+ configMap.put(MENU_BUTTON_SINGLE_TAP_TAG, new ConfigMap(3, ActionConfig.PRIMARY));
+ configMap.put(ASSIST_BUTTON_SINGLE_TAP_TAG, new ConfigMap(4, ActionConfig.PRIMARY));
+ configMap.put(BACK_BUTTON_LONG_PRESS_TAG, new ConfigMap(0, ActionConfig.SECOND));
+ configMap.put(HOME_BUTTON_LONG_PRESS_TAG, new ConfigMap(1, ActionConfig.SECOND));
+ configMap.put(OVERVIEW_BUTTON_LONG_PRESS_TAG, new ConfigMap(2, ActionConfig.SECOND));
+ configMap.put(MENU_BUTTON_LONG_PRESS_TAG, new ConfigMap(3, ActionConfig.SECOND));
+ configMap.put(ASSIST_BUTTON_LONG_PRESS_TAG, new ConfigMap(4, ActionConfig.SECOND));
+ configMap.put(BACK_BUTTON_DOUBLE_TAP_TAG, new ConfigMap(0, ActionConfig.THIRD));
+ configMap.put(HOME_BUTTON_DOUBLE_TAP_TAG, new ConfigMap(1, ActionConfig.THIRD));
+ configMap.put(OVERVIEW_BUTTON_DOUBLE_TAP_TAG, new ConfigMap(2, ActionConfig.THIRD));
+ configMap.put(MENU_BUTTON_DOUBLE_TAP_TAG, new ConfigMap(3, ActionConfig.THIRD));
+ configMap.put(ASSIST_BUTTON_DOUBLE_TAP_TAG, new ConfigMap(4, ActionConfig.THIRD));
+ }
+
+ public static final String HWKEYS_CONFIG_DEFAULT =
+ dl(HWKEY_DEF_BUTTONS)
+ + dl(BACK_BUTTON_TAG)
+ + dl(SystemAction.Back.mAction) + dl(SystemAction.Back.mLabelRes) + dl(EMPTY) // single tap (PRIMARY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // long press (SECOND)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // double tap (THIRD)
+
+ + dl(HOME_BUTTON_TAG)
+ + dl(SystemAction.Home.mAction) + dl(SystemAction.Home.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.Assistant.mAction) + dl(SystemAction.Assistant.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+
+ + dl(OVERVIEW_BUTTON_TAG)
+ + dl(SystemAction.Overview.mAction) + dl(SystemAction.Overview.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+
+ + dl(MENU_BUTTON_TAG)
+ + dl(SystemAction.Menu.mAction) + dl(SystemAction.Menu.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+
+ + dl(ASSIST_BUTTON_TAG)
+ + dl(SystemAction.Assistant.mAction) + dl(SystemAction.Assistant.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.VoiceSearch.mAction) + dl(SystemAction.VoiceSearch.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + EMPTY;
+
+ @Override
+ public int getConfigType() {
+ return HWKEYS;
+ }
+
+ @Override
+ public String getUri() {
+ //return Settings.System.HWKEY_BUTTON_ACTIONS;
+ return "hwkey_config";
+ }
+
+ @Override
+ public String getDefaultConfig() {
+ return HWKEYS_CONFIG_DEFAULT;
+ }
+
+ @Override
+ public int getMaxButtons() {
+ return HWKEY_MAX_BUTTONS;
+ }
+
+ @Override
+ public Map<String, ConfigMap> getActionMap() {
+ return configMap;
+ }
+
+ @Override
+ public Bundle getConfigs(Context context) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ }
+
+ public static class Fling implements Defaults {
+ public static final int FLING_MAX_BUTTONS = 10;
+ public static final String FLING_DEF_BUTTONS = "5";
+
+ public static final String RIGHT_TAP_TAG = "fling_right_taps";
+ public static final String LEFT_TAP_TAG = "fling_left_taps";
+ public static final String RIGHT_FLING_TAG = "fling_right";
+ public static final String LEFT_FLING = "fling_left";
+ public static final String UP_FLING = "fling_up";
+
+ public static final String SINGLE_LEFT_TAP_TAG = "single_left_tap";
+ public static final String SINGLE_RIGHT_TAP_TAG = "single_right_tap";
+ public static final String DOUBLE_LEFT_TAP_TAG = "double_left_tap";
+ public static final String DOUBLE_RIGHT_TAP_TAG = "double_right_tap";
+ public static final String LONG_LEFT_PRESS_TAG = "long_left_press";
+ public static final String LONG_RIGHT_PRESS_TAG = "long_right_press";
+ public static final String FLING_SHORT_LEFT_TAG = "fling_short_left";
+ public static final String FLING_SHORT_RIGHT_TAG = "fling_short_right";
+ public static final String FLING_LONG_LEFT_TAG = "fling_long_left";
+ public static final String FLING_LONG_RIGHT_TAG = "fling_long_right";
+ public static final String FLING_RIGHT_UP_TAG = "fling_right_up";
+ public static final String FLING_LEFT_UP_TAG = "fling_left_up";
+ public static final String CONFIG_fling_touchslop_increase_factor = "config_fling_touchslop_increase_factor";
+ public static final String CONFIG_FlingLongSwipePortraitLeft = "config_FlingLongSwipePortraitLeft";
+ public static final String CONFIG_FlingLongSwipePortraitRight = "config_FlingLongSwipePortraitRight";
+ public static final String CONFIG_FlingLongSwipeLandscapeLeft = "config_FlingLongSwipeLandscapeLeft";
+ public static final String CONFIG_FlingLongSwipeLandscapeRight = "config_FlingLongSwipeLandscapeRight";
+ public static final String CONFIG_FlingLongSwipeVerticalUp = "config_FlingLongSwipeVerticalUp";
+ public static final String CONFIG_FlingLongSwipeVerticalDown = "config_FlingLongSwipeVerticalDown";
+ public static final String CONFIG_pulsePathEffect_1 = "config_pulsePathEffect_1";
+ public static final String CONFIG_pulsePathEffect_2 = "config_pulsePathEffect_2";
+ public static final String CONFIG_pulsePathStrokeWidth = "config_pulsePathStrokeWidth";
+ public static final String CONFIG_pulseFillColor = "config_pulseFillColor";
+ public static final String CONFIG_pulseDivisions = "config_pulseDivisions";
+ public static final String CONFIG_pulseDbFuzzFactor = "config_pulseDbFuzzFactor";
+ public static final String CONFIG_pulseDbFuzz = "config_pulseDbFuzz";
+
+ private static final Map<String, ConfigHolder> defMap = new HashMap<String, ConfigHolder>();
+
+ static {
+ defMap.put(CONFIG_fling_touchslop_increase_factor, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_fling_touchslop_increase_factor,
+ DUActionUtils.FORMAT_FLOAT, DUActionUtils.DIMEN));
+ defMap.put(CONFIG_FlingLongSwipePortraitLeft, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_FlingLongSwipePortraitLeft,
+ DUActionUtils.FORMAT_FLOAT, DUActionUtils.DIMEN));
+ defMap.put(CONFIG_FlingLongSwipePortraitRight, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_FlingLongSwipePortraitRight,
+ DUActionUtils.FORMAT_FLOAT, DUActionUtils.DIMEN));
+ defMap.put(CONFIG_FlingLongSwipeLandscapeLeft, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_FlingLongSwipeLandscapeLeft,
+ DUActionUtils.FORMAT_FLOAT, DUActionUtils.DIMEN));
+ defMap.put(CONFIG_FlingLongSwipeLandscapeRight, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_FlingLongSwipeLandscapeRight,
+ DUActionUtils.FORMAT_FLOAT, DUActionUtils.DIMEN));
+ defMap.put(CONFIG_FlingLongSwipeVerticalUp, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_FlingLongSwipeVerticalUp,
+ DUActionUtils.FORMAT_FLOAT, DUActionUtils.DIMEN));
+ defMap.put(CONFIG_FlingLongSwipeVerticalDown, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_FlingLongSwipeVerticalDown,
+ DUActionUtils.FORMAT_FLOAT, DUActionUtils.DIMEN));
+ defMap.put(CONFIG_pulsePathEffect_1, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_pulsePathEffect_1, DUActionUtils.DIMEN_PIXEL));
+ defMap.put(CONFIG_pulsePathEffect_2, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_pulsePathEffect_2, DUActionUtils.DIMEN_PIXEL));
+ defMap.put(CONFIG_pulsePathStrokeWidth, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_pulsePathStrokeWidth, DUActionUtils.DIMEN_PIXEL));
+ defMap.put(CONFIG_pulseFillColor, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_pulseFillColor, DUActionUtils.COLOR));
+ defMap.put(CONFIG_pulseDivisions, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_pulseDivisions, DUActionUtils.INT));
+ defMap.put(CONFIG_pulseDbFuzzFactor, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_pulseDbFuzzFactor, DUActionUtils.INT));
+ defMap.put(CONFIG_pulseDbFuzz, new ConfigHolder(
+ DUActionUtils.PACKAGE_SYSTEMUI, CONFIG_pulseDbFuzz, DUActionUtils.INT));
+ }
+
+ private static final Map<String, ConfigMap> configMap = new HashMap<String, ConfigMap>();
+
+ static {
+ configMap.put(SINGLE_LEFT_TAP_TAG, new ConfigMap(1, ActionConfig.PRIMARY));
+ configMap.put(SINGLE_RIGHT_TAP_TAG, new ConfigMap(0, ActionConfig.PRIMARY));
+ configMap.put(DOUBLE_LEFT_TAP_TAG, new ConfigMap(1, ActionConfig.THIRD));
+ configMap.put(DOUBLE_RIGHT_TAP_TAG, new ConfigMap(0, ActionConfig.THIRD));
+ configMap.put(LONG_LEFT_PRESS_TAG, new ConfigMap(1, ActionConfig.SECOND));
+ configMap.put(LONG_RIGHT_PRESS_TAG, new ConfigMap(0, ActionConfig.SECOND));
+ configMap.put(FLING_SHORT_LEFT_TAG, new ConfigMap(3, ActionConfig.PRIMARY));
+ configMap.put(FLING_SHORT_RIGHT_TAG, new ConfigMap(2, ActionConfig.PRIMARY));
+ configMap.put(FLING_LONG_LEFT_TAG, new ConfigMap(3, ActionConfig.SECOND));
+ configMap.put(FLING_LONG_RIGHT_TAG, new ConfigMap(2, ActionConfig.SECOND));
+ configMap.put(FLING_RIGHT_UP_TAG, new ConfigMap(4, ActionConfig.PRIMARY));
+ configMap.put(FLING_LEFT_UP_TAG, new ConfigMap(4, ActionConfig.SECOND));
+ }
+
+ public static final String FLING_CONFIG_DEFAULT =
+ dl(FLING_DEF_BUTTONS)
+ + dl(RIGHT_TAP_TAG)
+ + dl(SystemAction.Home.mAction) + dl(SystemAction.Home.mLabelRes) + dl(EMPTY) // short tap
+ + dl(SystemAction.GoogleNowOnTap.mAction) + dl(SystemAction.GoogleNowOnTap.mLabelRes) + dl(EMPTY) // long press
+ + dl(SystemAction.LastApp.mAction) + dl(SystemAction.LastApp.mLabelRes) + dl(EMPTY) // double tap
+
+ + dl(LEFT_TAP_TAG)
+ + dl(SystemAction.Home.mAction) + dl(SystemAction.Home.mLabelRes) + dl(EMPTY) // short tap
+ + dl(SystemAction.GoogleNowOnTap.mAction) + dl(SystemAction.GoogleNowOnTap.mLabelRes) + dl(EMPTY) // long press
+ + dl(SystemAction.ScreenOff.mAction) + dl(SystemAction.ScreenOff.mLabelRes) + dl(EMPTY) // double tap
+
+ + dl(RIGHT_FLING_TAG)
+ + dl(SystemAction.Overview.mAction) + dl(SystemAction.Overview.mLabelRes) + dl(EMPTY) // short fling
+ + dl(SystemAction.Assistant.mAction) + dl(SystemAction.Assistant.mLabelRes) + dl(EMPTY) // long fling
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // super fling?
+
+ + dl(LEFT_FLING)
+ + dl(SystemAction.Back.mAction) + dl(SystemAction.Back.mLabelRes) + dl(EMPTY) // short fling
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // long fling
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // super fling?
+
+ + dl(UP_FLING)
+ + dl(SystemAction.SplitScreen.mAction) + dl(SystemAction.SplitScreen.mLabelRes) + dl(EMPTY) // right side (short fling only)
+ + dl(SystemAction.SplitScreen.mAction) + dl(SystemAction.SplitScreen.mLabelRes) + dl(EMPTY) // left side (short fling only)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + EMPTY;
+
+ @Override
+ public int getConfigType() {
+ return FLING;
+ }
+
+ @Override
+ public String getUri() {
+ return Settings.Secure.FLING_GESTURE_ACTIONS;
+ }
+
+ @Override
+ public String getDefaultConfig() {
+ return FLING_CONFIG_DEFAULT;
+ }
+
+ @Override
+ public int getMaxButtons() {
+ return FLING_MAX_BUTTONS;
+ }
+
+ @Override
+ public Map<String, ConfigMap> getActionMap() {
+ return configMap;
+ }
+
+ @Override
+ public Bundle getConfigs(Context context) {
+ return loadConfigsFromMap(context, defMap);
+ }
+ }
+
+ public static class PiePrimary implements Defaults {
+ public static final int PIE_PRIMARY_MAX_BUTTONS = 3;
+ public static final String PIE_PRIMARY_DEF_BUTTONS = "3";
+ public static final String PIE_BACK_BUTTON_TAG = "pie_button_back";
+ public static final String PIE_HOME_BUTTON_TAG = "pie_button_home";
+ public static final String PIE_OVERVIEW_BUTTON_TAG = "pie_button_overview";
+
+ public static final String PIE_BACK_BUTTON_SINGLE_TAP_TAG = "pie_button_back_single_tap";
+ public static final String PIE_HOME_BUTTON_SINGLE_TAP_TAG = "pie_button_home_single_tap";
+ public static final String PIE_OVERVIEW_BUTTON_SINGLE_TAP_TAG = "pie_button_overview_single_tap";
+
+ public static final String PIE_BACK_BUTTON_LONG_PRESS_TAG = "pie_button_back_long_press";
+ public static final String PIE_HOME_BUTTON_LONG_PRESS_TAG = "pie_button_home_long_press";
+ public static final String PIE_OVERVIEW_BUTTON_LONG_PRESS_TAG = "pie_button_overview_long_press";
+
+ private static final Map<String, ConfigMap> configMap = new HashMap<String, ConfigMap>();
+
+ static {
+ configMap.put(PIE_BACK_BUTTON_SINGLE_TAP_TAG, new ConfigMap(0, ActionConfig.PRIMARY));
+ configMap.put(PIE_HOME_BUTTON_SINGLE_TAP_TAG, new ConfigMap(1, ActionConfig.PRIMARY));
+ configMap.put(PIE_OVERVIEW_BUTTON_SINGLE_TAP_TAG, new ConfigMap(2, ActionConfig.PRIMARY));
+ configMap.put(PIE_BACK_BUTTON_LONG_PRESS_TAG, new ConfigMap(0, ActionConfig.SECOND));
+ configMap.put(PIE_HOME_BUTTON_LONG_PRESS_TAG, new ConfigMap(1, ActionConfig.SECOND));
+ configMap.put(PIE_OVERVIEW_BUTTON_LONG_PRESS_TAG, new ConfigMap(2, ActionConfig.SECOND));
+ }
+
+ public static final String PIE_PRIMARY_CONFIG_DEFAULT =
+ dl(PIE_PRIMARY_DEF_BUTTONS)
+ + dl(PIE_BACK_BUTTON_TAG)
+ + dl(SystemAction.Back.mAction) + dl(SystemAction.Back.mLabelRes) + dl(EMPTY) // single tap (PRIMARY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // long press (SECOND)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // double tap (NO-OP on Pie)
+
+ + dl(PIE_HOME_BUTTON_TAG)
+ + dl(SystemAction.Home.mAction) + dl(SystemAction.Home.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+
+ + dl(PIE_OVERVIEW_BUTTON_TAG)
+ + dl(SystemAction.Overview.mAction) + dl(SystemAction.Overview.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + EMPTY; // don't delimit final string
+
+
+ @Override
+ public int getConfigType() {
+ return PIE_PRIMARY;
+ }
+
+ @Override
+ public String getUri() {
+ //return Settings.System.PIE_BUTTONS_CONFIG;
+ return "pie_primary_config";
+ }
+
+ @Override
+ public String getDefaultConfig() {
+ return PIE_PRIMARY_CONFIG_DEFAULT;
+ }
+
+ @Override
+ public int getMaxButtons() {
+ return PIE_PRIMARY_MAX_BUTTONS;
+ }
+
+ @Override
+ public Map<String, ConfigMap> getActionMap() {
+ return configMap;
+ }
+
+ @Override
+ public Bundle getConfigs(Context context) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ }
+
+ public static class PieSecond implements Defaults {
+ public static final int PIE_SECOND_MAX_BUTTONS = 7;
+ public static final String PIE_SECOND_DEF_BUTTONS = "5";
+ public static final String PIE_BUTTON1_TAG = "pie_button_1";
+ public static final String PIE_BUTTON2_TAG = "pie_button_2";
+ public static final String PIE_BUTTON3_TAG = "pie_button_3";
+ public static final String PIE_BUTTON4_TAG = "pie_button_4";
+ public static final String PIE_BUTTON5_TAG = "pie_button_5";
+ public static final String PIE_BUTTON6_TAG = "pie_button_6";
+ public static final String PIE_BUTTON7_TAG = "pie_button_7";
+
+ public static final String PIE_SECOND_BUTTON1_SINGLE_TAP_TAG = "pie_second_button_1_single_tap";
+ public static final String PIE_SECOND_BUTTON2_SINGLE_TAP_TAG = "pie_second_button_2_single_tap";
+ public static final String PIE_SECOND_BUTTON3_SINGLE_TAP_TAG = "pie_second_button_3_single_tap";
+ public static final String PIE_SECOND_BUTTON4_SINGLE_TAP_TAG = "pie_second_button_4_single_tap";
+ public static final String PIE_SECOND_BUTTON5_SINGLE_TAP_TAG = "pie_second_button_5_single_tap";
+ public static final String PIE_SECOND_BUTTON6_SINGLE_TAP_TAG = "pie_second_button_6_single_tap";
+ public static final String PIE_SECOND_BUTTON7_SINGLE_TAP_TAG = "pie_second_button_7_single_tap";
+
+ public static final String PIE_SECOND_BUTTON1_LONG_PRESS_TAG = "pie_second_button_1_long_press";
+ public static final String PIE_SECOND_BUTTON2_LONG_PRESS_TAG = "pie_second_button_2_long_press";
+ public static final String PIE_SECOND_BUTTON3_LONG_PRESS_TAG = "pie_second_button_3_long_press";
+ public static final String PIE_SECOND_BUTTON4_LONG_PRESS_TAG = "pie_second_button_4_long_press";
+ public static final String PIE_SECOND_BUTTON5_LONG_PRESS_TAG = "pie_second_button_5_long_press";
+ public static final String PIE_SECOND_BUTTON6_LONG_PRESS_TAG = "pie_second_button_6_long_press";
+ public static final String PIE_SECOND_BUTTON7_LONG_PRESS_TAG = "pie_second_button_7_long_press";
+
+ private static final Map<String, ConfigMap> configMap = new HashMap<String, ConfigMap>();
+
+ static {
+ configMap.put(PIE_SECOND_BUTTON1_SINGLE_TAP_TAG, new ConfigMap(0, ActionConfig.PRIMARY));
+ configMap.put(PIE_SECOND_BUTTON2_SINGLE_TAP_TAG, new ConfigMap(1, ActionConfig.PRIMARY));
+ configMap.put(PIE_SECOND_BUTTON3_SINGLE_TAP_TAG, new ConfigMap(2, ActionConfig.PRIMARY));
+ configMap.put(PIE_SECOND_BUTTON4_SINGLE_TAP_TAG, new ConfigMap(3, ActionConfig.PRIMARY));
+ configMap.put(PIE_SECOND_BUTTON5_SINGLE_TAP_TAG, new ConfigMap(4, ActionConfig.PRIMARY));
+ configMap.put(PIE_SECOND_BUTTON6_SINGLE_TAP_TAG, new ConfigMap(5, ActionConfig.PRIMARY));
+ configMap.put(PIE_SECOND_BUTTON7_SINGLE_TAP_TAG, new ConfigMap(6, ActionConfig.PRIMARY));
+ configMap.put(PIE_SECOND_BUTTON1_LONG_PRESS_TAG, new ConfigMap(0, ActionConfig.SECOND));
+ configMap.put(PIE_SECOND_BUTTON2_LONG_PRESS_TAG, new ConfigMap(1, ActionConfig.SECOND));
+ configMap.put(PIE_SECOND_BUTTON3_LONG_PRESS_TAG, new ConfigMap(2, ActionConfig.SECOND));
+ configMap.put(PIE_SECOND_BUTTON4_LONG_PRESS_TAG, new ConfigMap(3, ActionConfig.SECOND));
+ configMap.put(PIE_SECOND_BUTTON5_LONG_PRESS_TAG, new ConfigMap(4, ActionConfig.SECOND));
+ configMap.put(PIE_SECOND_BUTTON6_LONG_PRESS_TAG, new ConfigMap(5, ActionConfig.SECOND));
+ configMap.put(PIE_SECOND_BUTTON7_LONG_PRESS_TAG, new ConfigMap(6, ActionConfig.SECOND));
+ }
+
+ public static final String PIE_SECOND_CONFIG_DEFAULT =
+ dl(PIE_SECOND_DEF_BUTTONS)
+ + dl(PIE_BUTTON1_TAG)
+ + dl(SystemAction.PowerMenu.mAction) + dl(SystemAction.PowerMenu.mLabelRes) + dl(EMPTY) // single tap (PRIMARY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // long press (SECOND)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY) // double tap (NO-OP on Pie)
+
+ + dl(PIE_BUTTON2_TAG)
+ + dl(SystemAction.NotificationPanel.mAction) + dl(SystemAction.NotificationPanel.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+
+ + dl(PIE_BUTTON3_TAG)
+ + dl(SystemAction.Assistant.mAction) + dl(SystemAction.Assistant.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+
+ + dl(PIE_BUTTON4_TAG)
+ + dl(SystemAction.Screenshot.mAction) + dl(SystemAction.Screenshot.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.RegionScreenshot.mAction) + dl(SystemAction.RegionScreenshot.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+
+ + dl(PIE_BUTTON5_TAG)
+ + dl(SystemAction.LastApp.mAction) + dl(SystemAction.LastApp.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + dl(EMPTY)
+ + dl(SystemAction.NoAction.mAction) + dl(SystemAction.NoAction.mLabelRes) + EMPTY;
+
+ @Override
+ public int getConfigType() {
+ return PIE_SECONDARY;
+ }
+
+ @Override
+ public String getUri() {
+ //return Settings.System.PIE_BUTTONS_CONFIG_SECOND_LAYER;
+ return "pie_second_config";
+ }
+
+ @Override
+ public String getDefaultConfig() {
+ return PIE_SECOND_CONFIG_DEFAULT;
+ }
+
+ @Override
+ public int getMaxButtons() {
+ return PIE_SECOND_MAX_BUTTONS;
+ }
+
+ @Override
+ public Map<String, ConfigMap> getActionMap() {
+ return configMap;
+ }
+
+ @Override
+ public Bundle getConfigs(Context context) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+
+ private static Bundle loadConfigsFromMap(Context ctx, Map<String, ConfigHolder> configMap) {
+ Bundle b = new Bundle();
+ for (Map.Entry<String, ConfigHolder> entry : configMap.entrySet()) {
+ ConfigHolder holder = entry.getValue();
+ Object obj = DUActionUtils.getValue(ctx, holder.name, holder.type, holder.format,
+ holder.pkg);
+ DUActionUtils.putValue(holder.name, obj, holder.type, b);
+ }
+ return b;
+ }
+
+ private static class ConfigHolder {
+ public String pkg;
+ public String name;
+ public String format;
+ public String type;
+
+ public ConfigHolder(String pkg, String name, String type) {
+ this(pkg, name, null, type);
+ }
+
+ public ConfigHolder(String pkg, String name, String format, String type) {
+ this.pkg = pkg;
+ this.name = name;
+ this.format = format;
+ this.type = type;
+ }
+ }
+
+ public static class ConfigMap {
+ public int button = -1;
+ public int action = -1;
+
+ public ConfigMap() {
+ };
+
+ public ConfigMap(int button, int action) {
+ this.button = button;
+ this.action = action;
+ }
+ }
+
+ public static final int PIE_PRIMARY_MAX_BUTTONS = 5;
+ public static final int PIE_SECONDAY_MAX_BUTTONS = 7;
+
+}
diff --git a/src/com/android/internal/utils/du/ActionHandler.java b/src/com/android/internal/utils/du/ActionHandler.java
new file mode 100644
index 0000000..f8c0ad8
--- /dev/null
+++ b/src/com/android/internal/utils/du/ActionHandler.java
@@ -0,0 +1,1169 @@
+/*
+ * Copyright (C) 2015 The TeamEos Project
+ * Copyright (C) 2016-2017 The DirtyUnicorns Project
+ *
+ * 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.
+ *
+ * Launches actions assigned to widgets. Creates bundles of state based
+ * on the type of action passed.
+ *
+ */
+
+package com.android.internal.utils.du;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.app.SearchManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.bluetooth.BluetoothAdapter;
+import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.hardware.input.InputManager;
+import android.media.AudioManager;
+import android.media.ToneGenerator;
+import android.media.session.MediaSessionLegacyHelper;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.service.wallpaper.WallpaperService;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.WindowManagerGlobal;
+//import android.view.WindowManagerPolicyControl;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.utils.du.Config.ActionConfig;
+
+public class ActionHandler {
+ public static String TAG = ActionHandler.class.getSimpleName();
+
+ public static final String SYSTEM_PREFIX = "task";
+ public static final String SYSTEMUI = "com.android.systemui";
+
+ // track and filter special actions
+ public static final String TASK_IME = "task_ime";
+ public static final String TASK_MEDIA = "task_media";
+ public static final String TASK_SOUNDMODE = "task_soundmode";
+
+ public static final String SYSTEMUI_TASK_NO_ACTION = "task_no_action";
+ public static final String SYSTEMUI_TASK_SETTINGS_PANEL = "task_settings_panel";
+ public static final String SYSTEMUI_TASK_NOTIFICATION_PANEL = "task_notification_panel";
+ public static final String SYSTEMUI_TASK_SCREENSHOT = "task_screenshot";
+ public static final String SYSTEMUI_TASK_REGION_SCREENSHOT = "task_region_screenshot";
+ public static final String SYSTEMUI_TASK_SCREENRECORD = "task_screenrecord";
+ // public static final String SYSTEMUI_TASK_AUDIORECORD =
+ // "task_audiorecord";
+ public static final String SYSTEMUI_TASK_EXPANDED_DESKTOP = "task_expanded_desktop";
+ public static final String SYSTEMUI_TASK_SCREENOFF = "task_screenoff";
+ public static final String SYSTEMUI_TASK_KILL_PROCESS = "task_killcurrent";
+ public static final String SYSTEMUI_TASK_ASSIST = "task_assist";
+ public static final String SYSTEMUI_TASK_GOOGLE_NOW_ON_TAP = "task_google_now_on_tap";
+ public static final String SYSTEMUI_TASK_POWER_MENU = "task_powermenu";
+ public static final String SYSTEMUI_TASK_TORCH = "task_torch";
+ public static final String SYSTEMUI_TASK_CAMERA = "task_camera";
+ public static final String SYSTEMUI_TASK_BT = "task_bt";
+ public static final String SYSTEMUI_TASK_WIFI = "task_wifi";
+ public static final String SYSTEMUI_TASK_WIFIAP = "task_wifiap";
+ public static final String SYSTEMUI_TASK_RECENTS = "task_recents";
+ public static final String SYSTEMUI_TASK_LAST_APP = "task_last_app";
+ public static final String SYSTEMUI_TASK_VOICE_SEARCH = "task_voice_search";
+ public static final String SYSTEMUI_TASK_APP_SEARCH = "task_app_search";
+ public static final String SYSTEMUI_TASK_MENU = "task_menu";
+ public static final String SYSTEMUI_TASK_BACK = "task_back";
+ public static final String SYSTEMUI_TASK_HOME = "task_home";
+ public static final String SYSTEMUI_TASK_IME_SWITCHER = "task_ime_switcher";
+ public static final String SYSTEMUI_TASK_IME_NAVIGATION_LEFT = "task_ime_navigation_left";
+ public static final String SYSTEMUI_TASK_IME_NAVIGATION_RIGHT = "task_ime_navigation_right";
+ public static final String SYSTEMUI_TASK_IME_NAVIGATION_UP = "task_ime_navigation_up";
+ public static final String SYSTEMUI_TASK_IME_NAVIGATION_DOWN = "task_ime_navigation_down";
+ public static final String SYSTEMUI_TASK_MEDIA_PREVIOUS = "task_media_previous";
+ public static final String SYSTEMUI_TASK_MEDIA_NEXT = "task_media_next";
+ public static final String SYSTEMUI_TASK_MEDIA_PLAY_PAUSE = "task_media_play_pause";
+ public static final String SYSTEMUI_TASK_SOUNDMODE_VIB = "task_soundmode_vib";
+ public static final String SYSTEMUI_TASK_SOUNDMODE_SILENT = "task_soundmode_silent";
+ public static final String SYSTEMUI_TASK_SOUNDMODE_VIB_SILENT = "task_soundmode_vib_silent";
+ public static final String SYSTEMUI_TASK_WAKE_DEVICE = "task_wake_device";
+ public static final String SYSTEMUI_TASK_STOP_SCREENPINNING = "task_stop_screenpinning";
+ public static final String SYSTEMUI_TASK_CLEAR_NOTIFICATIONS = "task_clear_notifications";
+ public static final String SYSTEMUI_TASK_VOLUME_PANEL = "task_volume_panel";
+ public static final String SYSTEMUI_TASK_EDITING_SMARTBAR = "task_editing_smartbar";
+ public static final String SYSTEMUI_TASK_SPLIT_SCREEN = "task_split_screen";
+ public static final String SYSTEMUI_TASK_ONE_HANDED_MODE_LEFT = "task_one_handed_mode_left";
+ public static final String SYSTEMUI_TASK_ONE_HANDED_MODE_RIGHT = "task_one_handed_mode_right";
+ public static final String SYSTEMUI_TASK_ASSISTANT_SOUND_SEARCH = "task_assistant_sound_search";
+
+ public static final String INTENT_SHOW_POWER_MENU = "action_handler_show_power_menu";
+ public static final String INTENT_TOGGLE_SCREENRECORD = "action_handler_toggle_screenrecord";
+ public static final String INTENT_SCREENSHOT = "action_handler_screenshot";
+ public static final String INTENT_REGION_SCREENSHOT = "action_handler_region_screenshot";
+
+ // remove actions from here as they come back on deck
+ static final Set<String> sDisabledActions = new HashSet<String>();
+ static {
+ sDisabledActions.add(SYSTEMUI_TASK_SCREENRECORD);
+ sDisabledActions.add(SYSTEMUI_TASK_EXPANDED_DESKTOP);
+ sDisabledActions.add(SYSTEMUI_TASK_ONE_HANDED_MODE_LEFT);
+ sDisabledActions.add(SYSTEMUI_TASK_ONE_HANDED_MODE_RIGHT);
+ // we need to make this more reliable when the user tap the partial screenshot button
+ // quickly and more times
+ sDisabledActions.add(SYSTEMUI_TASK_REGION_SCREENSHOT);
+ }
+
+ static enum SystemAction {
+ NoAction(SYSTEMUI_TASK_NO_ACTION, SYSTEMUI, "label_action_no_action", "ic_sysbar_no_action"),
+ SettingsPanel(SYSTEMUI_TASK_SETTINGS_PANEL, SYSTEMUI, "label_action_settings_panel", "ic_sysbar_settings_panel"),
+ NotificationPanel(SYSTEMUI_TASK_NOTIFICATION_PANEL, SYSTEMUI, "label_action_notification_panel", "ic_sysbar_notification_panel"),
+ Screenshot(SYSTEMUI_TASK_SCREENSHOT, SYSTEMUI, "label_action_screenshot", "ic_sysbar_screenshot"),
+ RegionScreenshot(SYSTEMUI_TASK_REGION_SCREENSHOT, SYSTEMUI, "label_action_region_screenshot", "ic_sysbar_region_screenshot"),
+ Screenrecord(SYSTEMUI_TASK_SCREENRECORD, SYSTEMUI, "label_action_screenrecord", "ic_sysbar_record_screen"),
+ ExpandedDesktop(SYSTEMUI_TASK_EXPANDED_DESKTOP, SYSTEMUI, "label_action_expanded_desktop", "ic_sysbar_expanded_desktop"),
+ ScreenOff(SYSTEMUI_TASK_SCREENOFF, SYSTEMUI, "label_action_screen_off", "ic_sysbar_screen_off"),
+ KillApp(SYSTEMUI_TASK_KILL_PROCESS, SYSTEMUI, "label_action_force_close_app", "ic_sysbar_killtask"),
+ Assistant(SYSTEMUI_TASK_ASSIST, SYSTEMUI, "label_action_search_assistant", "ic_sysbar_assist"),
+ GoogleNowOnTap(SYSTEMUI_TASK_GOOGLE_NOW_ON_TAP, SYSTEMUI, "label_action_google_now_on_tap", "ic_sysbar_google_now_on_tap"),
+ VoiceSearch(SYSTEMUI_TASK_VOICE_SEARCH, SYSTEMUI, "label_action_voice_search", "ic_sysbar_search"),
+ InAppSearch(SYSTEMUI_TASK_APP_SEARCH, SYSTEMUI, "label_action_in_app_search", "ic_sysbar_in_app_search"),
+ Flashlight(SYSTEMUI_TASK_TORCH, SYSTEMUI, "label_action_flashlight", "ic_sysbar_torch"),
+ Bluetooth(SYSTEMUI_TASK_BT, SYSTEMUI, "label_action_bluetooth", "ic_sysbar_bt"),
+ WiFi(SYSTEMUI_TASK_WIFI, SYSTEMUI, "label_action_wifi", "ic_sysbar_wifi"),
+ Hotspot(SYSTEMUI_TASK_WIFIAP, SYSTEMUI, "label_action_hotspot", "ic_sysbar_hotspot"),
+ LastApp(SYSTEMUI_TASK_LAST_APP, SYSTEMUI, "label_action_last_app", "ic_sysbar_lastapp"),
+ Overview(SYSTEMUI_TASK_RECENTS, SYSTEMUI, "label_action_overview", "ic_sysbar_recent"),
+ PowerMenu(SYSTEMUI_TASK_POWER_MENU, SYSTEMUI, "label_action_power_menu", "ic_sysbar_power_menu"),
+ Menu(SYSTEMUI_TASK_MENU, SYSTEMUI, "label_action_menu", "ic_sysbar_menu"),
+ Back(SYSTEMUI_TASK_BACK, SYSTEMUI, "label_action_back", "ic_sysbar_back"),
+ Home(SYSTEMUI_TASK_HOME, SYSTEMUI, "label_action_home", "ic_sysbar_home"),
+ Ime(SYSTEMUI_TASK_IME_SWITCHER, SYSTEMUI, "label_action_ime_switcher", "ic_ime_switcher_smartbar"),
+ StopScreenPinning(SYSTEMUI_TASK_STOP_SCREENPINNING, SYSTEMUI, "label_action_stop_screenpinning", "ic_smartbar_screen_pinning_off"),
+ ImeArrowDown(SYSTEMUI_TASK_IME_NAVIGATION_DOWN, SYSTEMUI, "label_action_ime_down", "ic_sysbar_ime_down"),
+ ImeArrowLeft(SYSTEMUI_TASK_IME_NAVIGATION_LEFT, SYSTEMUI, "label_action_ime_left", "ic_sysbar_ime_left"),
+ ImeArrowRight(SYSTEMUI_TASK_IME_NAVIGATION_RIGHT, SYSTEMUI, "label_action_ime_right", "ic_sysbar_ime_right"),
+ ImeArrowUp(SYSTEMUI_TASK_IME_NAVIGATION_UP, SYSTEMUI, "label_action_ime_up", "ic_sysbar_ime_up"),
+ ClearNotifications(SYSTEMUI_TASK_CLEAR_NOTIFICATIONS, SYSTEMUI, "label_action_clear_notifications", "ic_sysbar_clear_notifications"),
+ VolumePanel(SYSTEMUI_TASK_VOLUME_PANEL, SYSTEMUI, "label_action_volume_panel", "ic_sysbar_volume_panel"),
+ EditingSmartbar(SYSTEMUI_TASK_EDITING_SMARTBAR, SYSTEMUI, "label_action_editing_smartbar", "ic_sysbar_editing_smartbar"),
+ SplitScreen(SYSTEMUI_TASK_SPLIT_SCREEN, SYSTEMUI, "label_action_split_screen", "ic_sysbar_docked"),
+ OneHandedModeLeft(SYSTEMUI_TASK_ONE_HANDED_MODE_LEFT, SYSTEMUI, "label_action_one_handed_mode_left", "ic_sysbar_one_handed_mode_left"),
+ OneHandedModeRight(SYSTEMUI_TASK_ONE_HANDED_MODE_RIGHT, SYSTEMUI, "label_action_one_handed_mode_right", "ic_sysbar_one_handed_mode_right"),
+ MediaArrowLeft(SYSTEMUI_TASK_MEDIA_PREVIOUS, SYSTEMUI, "label_action_media_left", "ic_skip_previous"),
+ MediaArrowRight(SYSTEMUI_TASK_MEDIA_NEXT, SYSTEMUI, "label_action_media_right", "ic_skip_next"),
+ AssistantSoundSearch(SYSTEMUI_TASK_ASSISTANT_SOUND_SEARCH, SYSTEMUI, "label_action_assistant_sound_search", "ic_assistant_sound_search");
+
+ String mAction;
+ String mResPackage;
+ String mLabelRes;
+ String mIconRes;
+ String mDarkIconRes;
+
+ private SystemAction(String action, String resPackage, String labelRes, String iconRes) {
+ mAction = action;
+ mResPackage = resPackage;
+ mLabelRes = labelRes;
+ mIconRes = iconRes;
+ mDarkIconRes = iconRes + "_dark";
+ }
+
+ private ActionConfig create(Context ctx) {
+ return new ActionConfig(ctx, mAction);
+ }
+ }
+
+ /*
+ * Enumerated system actions with label and drawable support
+ */
+ static SystemAction[] systemActions = new SystemAction[] {
+ SystemAction.NoAction, SystemAction.SettingsPanel,
+ SystemAction.NotificationPanel, SystemAction.Screenshot,
+ SystemAction.ScreenOff, SystemAction.KillApp,
+ SystemAction.Assistant, SystemAction.GoogleNowOnTap,
+ SystemAction.Flashlight, SystemAction.Bluetooth,
+ SystemAction.WiFi, SystemAction.Hotspot,
+ SystemAction.LastApp, SystemAction.PowerMenu,
+ SystemAction.Overview,SystemAction.Menu,
+ SystemAction.Back, SystemAction.VoiceSearch,
+ SystemAction.Home, SystemAction.ExpandedDesktop,
+ SystemAction.Screenrecord, SystemAction.Ime,
+ SystemAction.StopScreenPinning, SystemAction.ImeArrowDown,
+ SystemAction.ImeArrowLeft, SystemAction.ImeArrowRight,
+ SystemAction.ImeArrowUp, SystemAction.InAppSearch,
+ SystemAction.VolumePanel, SystemAction.ClearNotifications,
+ SystemAction.EditingSmartbar, SystemAction.SplitScreen,
+ SystemAction.RegionScreenshot, SystemAction.OneHandedModeLeft,
+ SystemAction.OneHandedModeRight, SystemAction.MediaArrowLeft,
+ SystemAction.MediaArrowRight, SystemAction.AssistantSoundSearch
+ };
+
+ public static class ActionIconResources {
+ Drawable[] mDrawables;
+ Drawable[] mDarkDrawables;
+ Map<String, Integer> mIndexMap;
+
+ public ActionIconResources(Resources res) {
+ mDrawables = new Drawable[systemActions.length];
+ mDarkDrawables = new Drawable[systemActions.length];
+ mIndexMap = new HashMap<String, Integer>();
+ for (int i = 0; i < systemActions.length; i++) {
+ mIndexMap.put(systemActions[i].mAction, i);
+ mDrawables[i] = DUActionUtils.getDrawable(res, systemActions[i].mIconRes,
+ systemActions[i].mResPackage);
+ mDarkDrawables[i] = DUActionUtils.getDrawable(res, systemActions[i].mDarkIconRes,
+ systemActions[i].mResPackage);
+ }
+ }
+
+ public void updateResources(Resources res) {
+ for (int i = 0; i < mDrawables.length; i++) {
+ mDrawables[i] = DUActionUtils.getDrawable(res, systemActions[i].mIconRes,
+ systemActions[i].mResPackage);
+ mDarkDrawables[i] = DUActionUtils.getDrawable(res, systemActions[i].mDarkIconRes,
+ systemActions[i].mResPackage);
+ }
+ }
+
+ public Drawable getActionDrawable(String action) {
+ return mDrawables[mIndexMap.get(action)];
+ }
+
+ public Drawable getDarkActionDrawable(String action) {
+ return mDarkDrawables[mIndexMap.get(action)];
+ }
+ }
+
+ /*
+ * Default list to display in an action picker
+ * Filter by device capabilities and actions used internally
+ * but we don't really want as assignable
+ */
+ public static ArrayList<ActionConfig> getSystemActions(Context context) {
+ ArrayList<ActionConfig> bundle = new ArrayList<ActionConfig>();
+ for (int i = 0; i < systemActions.length; i++) {
+ ActionConfig c = systemActions[i].create(context);
+ String action = c.getAction();
+ if (sDisabledActions.contains(action)) {
+ continue;
+ }
+ if (TextUtils.equals(action, SYSTEMUI_TASK_STOP_SCREENPINNING)
+ || TextUtils.equals(action, SYSTEMUI_TASK_IME_NAVIGATION_DOWN)
+ || TextUtils.equals(action, SYSTEMUI_TASK_IME_NAVIGATION_LEFT)
+ || TextUtils.equals(action, SYSTEMUI_TASK_IME_NAVIGATION_RIGHT)
+ || TextUtils.equals(action, SYSTEMUI_TASK_IME_NAVIGATION_UP)
+ || TextUtils.equals(action, SYSTEMUI_TASK_IME_SWITCHER)
+ || TextUtils.equals(action, SYSTEMUI_TASK_MEDIA_PREVIOUS)
+ || TextUtils.equals(action, SYSTEMUI_TASK_MEDIA_NEXT)) {
+ continue;
+ } else if (TextUtils.equals(action, SYSTEMUI_TASK_WIFIAP)
+ && !DUActionUtils.deviceSupportsMobileData(context)) {
+ continue;
+ } else if (TextUtils.equals(action, SYSTEMUI_TASK_BT)
+ && !DUActionUtils.deviceSupportsBluetooth()) {
+ continue;
+ } else if (TextUtils.equals(action, SYSTEMUI_TASK_TORCH)
+ && !DUActionUtils.deviceSupportsFlashLight(context)) {
+ continue;
+ } else if (TextUtils.equals(action, SYSTEMUI_TASK_CAMERA)
+ && context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
+ continue;
+ } else if (TextUtils.equals(action, SYSTEMUI_TASK_SCREENRECORD)) {
+ if (!DUActionUtils.getBoolean(context, "config_enableScreenrecordChord",
+ DUActionUtils.PACKAGE_ANDROID)) {
+ continue;
+ }
+ } else if (TextUtils.equals(action, SYSTEMUI_TASK_EDITING_SMARTBAR)) {
+ // don't allow smartbar editor on Fling
+ if (Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.NAVIGATION_BAR_MODE, 0,
+ UserHandle.USER_CURRENT) == 1) {
+ continue;
+ }
+ }
+ bundle.add(c);
+ }
+ Collections.sort(bundle);
+ return bundle;
+ }
+
+ private static final class StatusBarHelper {
+ private static boolean isPreloaded = false;
+ private static IStatusBarService mService = null;
+
+ private static IStatusBarService getStatusBarService() {
+ synchronized (StatusBarHelper.class) {
+ if (mService == null) {
+ try {
+ mService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService("statusbar"));
+ } catch (Exception e) {
+ }
+ }
+ return mService;
+ }
+ }
+
+ private static void dispatchNavigationEditorResult(Intent intent) {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.dispatchNavigationEditorResults(intent);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static void toggleNavigationEditor() {
+ IStatusBarService service = getStatusBarService();
+ try {
+ service.toggleNavigationEditor();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void toggleFlashlight() {
+ IStatusBarService service = getStatusBarService();
+ try {
+ service.toggleFlashlight();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void toggleRecentsApps() {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ sendCloseSystemWindows("recentapps");
+ service.toggleRecentApps();
+ } catch (RemoteException e) {
+ return;
+ }
+ isPreloaded = false;
+ }
+ }
+
+ private static void cancelPreloadRecentApps() {
+ if (isPreloaded == false)
+ return;
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.cancelPreloadRecentApps();
+ } catch (Exception e) {
+ return;
+ }
+ }
+ isPreloaded = false;
+ }
+
+ private static void preloadRecentApps() {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.preloadRecentApps();
+ } catch (RemoteException e) {
+ isPreloaded = false;
+ return;
+ }
+ isPreloaded = true;
+ }
+ }
+
+ private static void expandNotificationPanel() {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.expandNotificationsPanel();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private static void expandSettingsPanel() {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.expandSettingsPanel(null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private static void fireGoogleNowOnTap() {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.startAssist(new Bundle());
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private static void splitScreen() {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.toggleSplitScreen();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+/*
+ private static void fireIntentAfterKeyguard(Intent intent) {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.showCustomIntentAfterKeyguard(intent);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+*/
+ private static void clearAllNotifications() {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.onClearAllNotifications(ActivityManager.getCurrentUser());
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private static void sendSystemKeyToStatusBar(int keyCode) {
+ IStatusBarService service = getStatusBarService();
+ if (service != null) {
+ try {
+ service.handleSystemKey(keyCode);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
+ public static void toggleRecentApps() {
+ StatusBarHelper.toggleRecentsApps();
+ }
+
+ public static void cancelPreloadRecentApps() {
+ StatusBarHelper.cancelPreloadRecentApps();
+ }
+
+ public static void preloadRecentApps() {
+ StatusBarHelper.preloadRecentApps();
+ }
+/*
+ public static void performTaskFromKeyguard(Context ctx, String action) {
+ // null: throw it out
+ if (action == null) {
+ return;
+ }
+ // not a system action, should be intent
+ if (!action.startsWith(SYSTEM_PREFIX)) {
+ Intent intent = DUActionUtils.getIntent(action);
+ if (intent == null) {
+ return;
+ }
+ StatusBarHelper.fireIntentAfterKeyguard(intent);
+ } else {
+ performTask(ctx, action);
+ }
+ }
+*/
+ public static void dispatchNavigationEditorResult(Intent intent) {
+ StatusBarHelper.dispatchNavigationEditorResult(intent);
+ }
+
+ public static void performTask(Context context, String action) {
+ // null: throw it out
+ if (action == null) {
+ return;
+ }
+ if (sDisabledActions.contains(action)) {
+ return;
+ }
+ // not a system action, should be intent
+ if (!action.startsWith(SYSTEM_PREFIX)) {
+ Intent intent = DUActionUtils.getIntent(action);
+ if (intent == null) {
+ return;
+ }
+ launchActivity(context, intent);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_NO_ACTION)) {
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_KILL_PROCESS)) {
+ killProcess(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_SCREENSHOT)) {
+ sendCommandToWindowManager(new Intent(INTENT_SCREENSHOT));
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_REGION_SCREENSHOT)) {
+ sendCommandToWindowManager(new Intent(INTENT_REGION_SCREENSHOT));
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_SCREENRECORD)) {
+ sendCommandToWindowManager(new Intent(INTENT_TOGGLE_SCREENRECORD));
+ return;
+ // } else if (action.equals(SYSTEMUI_TASK_AUDIORECORD)) {
+ // takeAudiorecord();
+ } else if (action.equals(SYSTEMUI_TASK_EXPANDED_DESKTOP)) {
+ // toggleExpandedDesktop(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_SCREENOFF)) {
+ screenOff(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_WAKE_DEVICE)) {
+ PowerManager powerManager =
+ (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ if (!powerManager.isScreenOn()) {
+ powerManager.wakeUp(SystemClock.uptimeMillis());
+ }
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_ASSIST)) {
+ launchAssistAction(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_GOOGLE_NOW_ON_TAP)) {
+ StatusBarHelper.fireGoogleNowOnTap();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_POWER_MENU)) {
+ sendCommandToWindowManager(new Intent(INTENT_SHOW_POWER_MENU));
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_TORCH)) {
+ StatusBarHelper.toggleFlashlight();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_CAMERA)) {
+ launchCamera(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_WIFI)) {
+ toggleWifi(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_WIFIAP)) {
+ toggleWifiAP(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_BT)) {
+ toggleBluetooth();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_RECENTS)) {
+ toggleRecentApps();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_LAST_APP)) {
+ switchToLastApp(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_SETTINGS_PANEL)) {
+ StatusBarHelper.expandSettingsPanel();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_NOTIFICATION_PANEL)) {
+ StatusBarHelper.expandNotificationPanel();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_VOICE_SEARCH)) {
+ launchVoiceSearch(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_APP_SEARCH)) {
+ triggerVirtualKeypress(context, KeyEvent.KEYCODE_SEARCH);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_MENU)) {
+ triggerVirtualKeypress(context, KeyEvent.KEYCODE_MENU);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_BACK)) {
+ triggerVirtualKeypress(context, KeyEvent.KEYCODE_BACK);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_HOME)) {
+ triggerVirtualKeypress(context, KeyEvent.KEYCODE_HOME);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_IME_SWITCHER)) {
+ ((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE))
+ .showInputMethodPicker(true /* showAuxiliarySubtypes */);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_STOP_SCREENPINNING)) {
+ turnOffLockTask();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_IME_NAVIGATION_RIGHT)) {
+ triggerVirtualKeypress(context, KeyEvent.KEYCODE_DPAD_RIGHT);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_IME_NAVIGATION_UP)) {
+ triggerVirtualKeypress(context, KeyEvent.KEYCODE_DPAD_UP);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_IME_NAVIGATION_DOWN)) {
+ triggerVirtualKeypress(context, KeyEvent.KEYCODE_DPAD_DOWN);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_IME_NAVIGATION_LEFT)) {
+ triggerVirtualKeypress(context, KeyEvent.KEYCODE_DPAD_LEFT);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_MEDIA_PREVIOUS)) {
+ StatusBarHelper.sendSystemKeyToStatusBar(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+ //dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PREVIOUS, context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_MEDIA_NEXT)) {
+ StatusBarHelper.sendSystemKeyToStatusBar(KeyEvent.KEYCODE_MEDIA_NEXT);
+ //dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_NEXT, context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_MEDIA_PLAY_PAUSE)) {
+ dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_SOUNDMODE_VIB)) {
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ if (am != null && ActivityManagerNative.isSystemReady()) {
+ if (am.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
+ am.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
+ Vibrator vib = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ if (vib != null) {
+ vib.vibrate(50);
+ }
+ } else {
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ ToneGenerator tg = new ToneGenerator(
+ AudioManager.STREAM_NOTIFICATION,
+ (int) (ToneGenerator.MAX_VOLUME * 0.85));
+ if (tg != null) {
+ tg.startTone(ToneGenerator.TONE_PROP_BEEP);
+ }
+ }
+ }
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_SOUNDMODE_SILENT)) {
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ if (am != null && ActivityManagerNative.isSystemReady()) {
+ if (am.getRingerMode() != AudioManager.RINGER_MODE_SILENT) {
+ am.setRingerMode(AudioManager.RINGER_MODE_SILENT);
+ } else {
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ ToneGenerator tg = new ToneGenerator(
+ AudioManager.STREAM_NOTIFICATION,
+ (int) (ToneGenerator.MAX_VOLUME * 0.85));
+ if (tg != null) {
+ tg.startTone(ToneGenerator.TONE_PROP_BEEP);
+ }
+ }
+ }
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_SOUNDMODE_VIB_SILENT)) {
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ if (am != null && ActivityManagerNative.isSystemReady()) {
+ if (am.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) {
+ am.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
+ Vibrator vib = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ if (vib != null) {
+ vib.vibrate(50);
+ }
+ } else if (am.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
+ am.setRingerMode(AudioManager.RINGER_MODE_SILENT);
+ } else {
+ am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ ToneGenerator tg = new ToneGenerator(
+ AudioManager.STREAM_NOTIFICATION,
+ (int) (ToneGenerator.MAX_VOLUME * 0.85));
+ if (tg != null) {
+ tg.startTone(ToneGenerator.TONE_PROP_BEEP);
+ }
+ }
+ }
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_CLEAR_NOTIFICATIONS)) {
+ StatusBarHelper.clearAllNotifications();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_VOLUME_PANEL)) {
+ volumePanel(context);
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_EDITING_SMARTBAR)) {
+ StatusBarHelper.toggleNavigationEditor();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_SPLIT_SCREEN)) {
+ StatusBarHelper.splitScreen();
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_ONE_HANDED_MODE_LEFT)) {
+// toggleOneHandedMode(context, "left");
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_ONE_HANDED_MODE_RIGHT)) {
+// toggleOneHandedMode(context, "right");
+ return;
+ } else if (action.equals(SYSTEMUI_TASK_ASSISTANT_SOUND_SEARCH)) {
+ startAssistantSoundSearch(context);
+ return;
+ }
+ }
+
+ public static boolean isActionKeyEvent(String action) {
+ if (action.equals(SYSTEMUI_TASK_HOME)
+ || action.equals(SYSTEMUI_TASK_BACK)
+// || action.equals(SYSTEMUI_TASK_SEARCH)
+ || action.equals(SYSTEMUI_TASK_MENU)
+// || action.equals(ActionConstants.ACTION_MENU_BIG)
+ || action.equals(SYSTEMUI_TASK_NO_ACTION)) {
+ return true;
+ }
+ return false;
+ }
+
+ private static void launchActivity(Context context, Intent intent) {
+ try {
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ context.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ } catch (Exception e) {
+ Log.i(TAG, "Unable to launch activity " + e);
+ }
+ }
+
+ private static void switchToLastApp(Context context) {
+ final ActivityManager am =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ ActivityManager.RunningTaskInfo lastTask = getLastTask(context, am);
+
+ if (lastTask != null) {
+ am.moveTaskToFront(lastTask.id, ActivityManager.MOVE_TASK_NO_USER_ACTION,
+ getAnimation(context).toBundle());
+ }
+ cancelPreloadRecentApps();
+ }
+
+ private static ActivityOptions getAnimation(Context context) {
+ return ActivityOptions.makeCustomAnimation(context,
+ com.android.internal.R.anim.du_app_in,
+ com.android.internal.R.anim.du_app_out);
+ }
+
+ private static ActivityManager.RunningTaskInfo getLastTask(Context context,
+ final ActivityManager am) {
+ final List<String> packageNames = getCurrentLauncherPackages(context);
+ final List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(5);
+ for (int i = 1; i < tasks.size(); i++) {
+ String packageName = tasks.get(i).topActivity.getPackageName();
+ if (!packageName.equals(context.getPackageName())
+ && !packageName.equals(SYSTEMUI)
+ && !packageNames.contains(packageName)) {
+ return tasks.get(i);
+ }
+ }
+ return null;
+ }
+
+ private static List<String> getCurrentLauncherPackages(Context context) {
+ final PackageManager pm = context.getPackageManager();
+ final List<ResolveInfo> homeActivities = new ArrayList<>();
+ pm.getHomeActivities(homeActivities);
+ final List<String> packageNames = new ArrayList<>();
+ for (ResolveInfo info : homeActivities) {
+ final String name = info.activityInfo.packageName;
+ if (!name.equals("com.android.settings")) {
+ packageNames.add(name);
+ }
+ }
+ return packageNames;
+ }
+
+ private static void sendCloseSystemWindows(String reason) {
+ if (ActivityManagerNative.isSystemReady()) {
+ try {
+ ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+/*
+ private static void toggleExpandedDesktop(Context context) {
+ ContentResolver cr = context.getContentResolver();
+ String newVal = "";
+ String currentVal = Settings.Global.getString(cr, Settings.Global.POLICY_CONTROL);
+ if (currentVal == null) {
+ currentVal = newVal;
+ }
+ if ("".equals(currentVal)) {
+ newVal = "immersive.full=*";
+ }
+ Settings.Global.putString(cr, Settings.Global.POLICY_CONTROL, newVal);
+ if (newVal.equals("")) {
+ WindowManagerPolicyControl.reloadFromSetting(context);
+ }
+ }
+*/
+ private static void launchVoiceSearch(Context context) {
+ sendCloseSystemWindows("assist");
+ // launch the search activity
+ Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
+ try {
+ // TODO: This only stops the factory-installed search manager.
+ // Need to formalize an API to handle others
+ SearchManager searchManager = (SearchManager) context
+ .getSystemService(Context.SEARCH_SERVICE);
+ if (searchManager != null) {
+ searchManager.stopSearch();
+ }
+ launchActivity(context, intent);
+ } catch (ActivityNotFoundException e) {
+ Slog.w(TAG, "No assist activity installed", e);
+ }
+ }
+
+ private static void dispatchMediaKeyWithWakeLock(int keycode, Context context) {
+ if (ActivityManagerNative.isSystemReady()) {
+ KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(),
+ SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0);
+ MediaSessionLegacyHelper.getHelper(context).sendMediaButtonEvent(event, true);
+ event = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
+ MediaSessionLegacyHelper.getHelper(context).sendMediaButtonEvent(event, true);
+ }
+ }
+
+ private static void triggerVirtualKeypress(Context context, final int keyCode) {
+ final InputManager im = InputManager.getInstance();
+ final long now = SystemClock.uptimeMillis();
+ int downflags = 0;
+
+ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
+ || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
+ || keyCode == KeyEvent.KEYCODE_DPAD_UP
+ || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ downflags = KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE;
+ } else {
+ downflags = KeyEvent.FLAG_FROM_SYSTEM;
+ }
+
+ final KeyEvent downEvent = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
+ keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ downflags, InputDevice.SOURCE_KEYBOARD);
+ final KeyEvent upEvent = KeyEvent.changeAction(downEvent, KeyEvent.ACTION_UP);
+ final Handler handler = new Handler(Looper.getMainLooper());
+
+ final Runnable downRunnable = new Runnable() {
+ @Override
+ public void run() {
+ im.injectInputEvent(downEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ }
+ };
+
+ final Runnable upRunnable = new Runnable() {
+ @Override
+ public void run() {
+ im.injectInputEvent(upEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ }
+ };
+
+ handler.post(downRunnable);
+ handler.postDelayed(upRunnable, 10);
+ }
+
+ private static void launchCamera(Context context) {
+ Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
+ PackageManager pm = context.getPackageManager();
+ final ResolveInfo mInfo = pm.resolveActivity(i, 0);
+ Intent intent = new Intent().setComponent(new ComponentName(mInfo.activityInfo.packageName,
+ mInfo.activityInfo.name));
+ launchActivity(context, intent);
+ }
+
+ private static void toggleWifi(Context context) {
+ WifiManager wfm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ wfm.setWifiEnabled(!wfm.isWifiEnabled());
+ }
+
+ private static void toggleBluetooth() {
+ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ boolean enabled = bluetoothAdapter.isEnabled();
+ if (enabled) {
+ bluetoothAdapter.disable();
+ } else {
+ bluetoothAdapter.enable();
+ }
+ }
+
+ private static void toggleWifiAP(Context context) {
+ final ContentResolver cr = context.getContentResolver();
+ WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ final ConnectivityManager mConnectivityManager;
+ mConnectivityManager = (ConnectivityManager) context.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ int state = wm.getWifiApState();
+ boolean enabled = false;
+ switch (state) {
+ case WifiManager.WIFI_AP_STATE_ENABLING:
+ case WifiManager.WIFI_AP_STATE_ENABLED:
+ enabled = false;
+ break;
+ case WifiManager.WIFI_AP_STATE_DISABLING:
+ case WifiManager.WIFI_AP_STATE_DISABLED:
+ enabled = true;
+ break;
+ }
+
+ // Turn on the Wifi AP
+ if (enabled) {
+ OnStartTetheringCallback callback = new OnStartTetheringCallback();
+ mConnectivityManager.startTethering(
+ ConnectivityManager.TETHERING_WIFI, false, callback);
+ } else {
+ mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ }
+ }
+
+ static final class OnStartTetheringCallback extends
+ ConnectivityManager.OnStartTetheringCallback {
+ @Override
+ public void onTetheringStarted() {}
+ @Override
+ public void onTetheringFailed() {
+ // TODO: Show error.
+ }
+ }
+
+ private static void sendCommandToWindowManager(Intent intent) {
+ IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ try {
+ wm.sendCustomAction(intent);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void killProcess(Context context) {
+ if (context.checkCallingOrSelfPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) == PackageManager.PERMISSION_GRANTED
+ && !isLockTaskOn()) {
+ try {
+ PackageManager packageManager = context.getPackageManager();
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ String defaultHomePackage = "com.android.launcher";
+ intent.addCategory(Intent.CATEGORY_HOME);
+ final ResolveInfo res = packageManager.resolveActivity(intent, 0);
+ if (res.activityInfo != null
+ && !res.activityInfo.packageName.equals("android")) {
+ defaultHomePackage = res.activityInfo.packageName;
+ }
+
+ // Use UsageStats to determine foreground app
+ UsageStatsManager usageStatsManager = (UsageStatsManager)
+ context.getSystemService(Context.USAGE_STATS_SERVICE);
+ long current = System.currentTimeMillis();
+ long past = current - (1000 * 60 * 60); // uses snapshot of usage over past 60 minutes
+
+ // Get the list, then sort it chronilogically so most recent usage is at start of list
+ List<UsageStats> recentApps = usageStatsManager.queryUsageStats(
+ UsageStatsManager.INTERVAL_DAILY, past, current);
+ Collections.sort(recentApps, new Comparator<UsageStats>() {
+ @Override
+ public int compare(UsageStats lhs, UsageStats rhs) {
+ long timeLHS = lhs.getLastTimeUsed();
+ long timeRHS = rhs.getLastTimeUsed();
+ if (timeLHS > timeRHS) {
+ return -1;
+ } else if (timeLHS < timeRHS) {
+ return 1;
+ }
+ return 0;
+ }
+ });
+
+ IActivityManager iam = ActivityManagerNative.getDefault();
+ // this may not be needed due to !isLockTaskOn() in entry if
+ //if (am.getLockTaskModeState() != ActivityManager.LOCK_TASK_MODE_NONE) return;
+
+ // Look for most recent usagestat with lastevent == 1 and grab package name
+ // ...this seems to map to the UsageEvents.Event.MOVE_TO_FOREGROUND
+ String pkg = null;
+ for (int i = 0; i < recentApps.size(); i++) {
+ UsageStats mostRecent = recentApps.get(i);
+ if (mostRecent.mLastEvent == 1) {
+ pkg = mostRecent.mPackageName;
+ break;
+ }
+ }
+
+ if (pkg != null && !pkg.equals("com.android.systemui")
+ && !pkg.equals(defaultHomePackage)) {
+
+ // Restore home screen stack before killing the app
+ Intent home = new Intent(Intent.ACTION_MAIN, null);
+ home.addCategory(Intent.CATEGORY_HOME);
+ home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ context.startActivity(home);
+
+ // Kill the app
+ iam.forceStopPackage(pkg, UserHandle.USER_CURRENT);
+
+ // Remove killed app from Recents
+ final ActivityManager am = (ActivityManager)
+ context.getSystemService(Context.ACTIVITY_SERVICE);
+ final List<ActivityManager.RecentTaskInfo> recentTasks =
+ am.getRecentTasksForUser(ActivityManager.getMaxRecentTasksStatic(),
+ ActivityManager.RECENT_IGNORE_HOME_AND_RECENTS_STACK_TASKS
+ | ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS
+ | ActivityManager.RECENT_IGNORE_UNAVAILABLE
+ | ActivityManager.RECENT_INCLUDE_PROFILES,
+ UserHandle.CURRENT.getIdentifier());
+ final int size = recentTasks.size();
+ for (int i = 0; i < size; i++) {
+ ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+ if (recentInfo.baseIntent.getComponent().getPackageName().equals(pkg)) {
+ int taskid = recentInfo.persistentId;
+ am.removeTask(taskid);
+ }
+ }
+
+ String pkgName;
+ try {
+ pkgName = (String) packageManager.getApplicationLabel(
+ packageManager.getApplicationInfo(pkg, PackageManager.GET_META_DATA));
+ } catch (PackageManager.NameNotFoundException e) {
+ // Just use pkg if issues getting appName
+ pkgName = pkg;
+ }
+
+ Resources systemUIRes = DUActionUtils.getResourcesForPackage(context, DUActionUtils.PACKAGE_SYSTEMUI);
+ int ident = systemUIRes.getIdentifier("app_killed_message", DUActionUtils.STRING, DUActionUtils.PACKAGE_SYSTEMUI);
+ String toastMsg = systemUIRes.getString(ident, pkgName);
+ Context ctx = getPackageContext(context, DUActionUtils.PACKAGE_SYSTEMUI);
+ Toast.makeText(ctx != null ? ctx : context, toastMsg, Toast.LENGTH_SHORT).show();
+ return;
+ } else {
+ // make a "didnt kill anything" toast?
+ return;
+ }
+ } catch (RemoteException remoteException) {
+ Log.d("ActionHandler", "Caller cannot kill processes, aborting");
+ }
+ } else {
+ Log.d("ActionHandler", "Caller cannot kill processes, aborting");
+ }
+ }
+
+
+ public static Context getPackageContext(Context context, String packageName) {
+ Context pkgContext = null;
+ if (context.getPackageName().equals(packageName)) {
+ pkgContext = context;
+ } else {
+ try {
+ pkgContext = context.createPackageContext(packageName,
+ Context.CONTEXT_IGNORE_SECURITY
+ | Context.CONTEXT_INCLUDE_CODE);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ return pkgContext;
+ }
+
+ private static boolean isPackageLiveWalls(Context ctx, String pkg) {
+ if (ctx == null || pkg == null) {
+ return false;
+ }
+ List<ResolveInfo> liveWallsList = ctx.getPackageManager().queryIntentServices(
+ new Intent(WallpaperService.SERVICE_INTERFACE),
+ PackageManager.GET_META_DATA);
+ if (liveWallsList == null) {
+ return false;
+ }
+ for (ResolveInfo info : liveWallsList) {
+ if (info.serviceInfo != null) {
+ String packageName = info.serviceInfo.packageName;
+ if (TextUtils.equals(pkg, packageName)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static void screenOff(Context context) {
+ PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ pm.goToSleep(SystemClock.uptimeMillis());
+ }
+
+ private static void launchAssistAction(Context context) {
+ sendCloseSystemWindows("assist");
+ Intent intent = ((SearchManager) context.getSystemService(Context.SEARCH_SERVICE))
+ .getAssistIntent(true);
+ if (intent != null) {
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ try {
+ context.startActivityAsUser(intent, UserHandle.CURRENT);
+ } catch (ActivityNotFoundException e) {
+ Slog.w(TAG, "No activity to handle assist action.", e);
+ }
+ }
+ }
+
+ public static void turnOffLockTask() {
+ try {
+ ActivityManagerNative.getDefault().stopLockTaskMode();
+ } catch (Exception e) {
+ }
+ }
+
+ public static boolean isLockTaskOn() {
+ try {
+ return ActivityManagerNative.getDefault().isInLockTaskMode();
+ } catch (Exception e) {
+ }
+ return false;
+ }
+
+ public static void volumePanel(Context context) {
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ am.adjustVolume(AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI);
+ }
+
+/*
+ private static void toggleOneHandedMode(Context context, String direction) {
+ String str = Settings.Global.getString(context.getContentResolver(), Settings.Global.SINGLE_HAND_MODE);
+
+ if (TextUtils.isEmpty(str))
+ Settings.Global.putString(context.getContentResolver(), Settings.Global.SINGLE_HAND_MODE, direction);
+ else
+ Settings.Global.putString(context.getContentResolver(), Settings.Global.SINGLE_HAND_MODE, "");
+ }
+ */
+
+ public static void startAssistantSoundSearch(Context context) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setAction("com.google.android.googlequicksearchbox.MUSIC_SEARCH");
+ context.startActivity(intent);
+ }
+}
diff --git a/src/com/android/internal/utils/du/ActionHolder.java b/src/com/android/internal/utils/du/ActionHolder.java
new file mode 100644
index 0000000..6040e8f
--- /dev/null
+++ b/src/com/android/internal/utils/du/ActionHolder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 TeamEos project
+ * Author Randall Rushing aka bigrushdog, randall.rushing@gmail.com
+ *
+ * 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.
+ *
+ * Widgets may implement this interface to interact with action configurations
+ *
+ */
+
+package com.android.internal.utils.du;
+
+import com.android.internal.utils.du.ActionConstants.ConfigMap;
+import com.android.internal.utils.du.ActionConstants.Defaults;
+import com.android.internal.utils.du.Config.ActionConfig;
+import com.android.internal.utils.du.Config.ButtonConfig;
+
+public interface ActionHolder {
+ public String getTag();
+ public void setTag(String tag);
+ public Defaults getDefaults();
+ public void setDefaults(Defaults defaults);
+ public ConfigMap getConfigMap();
+ public void setConfigMap(ConfigMap map);
+ public ButtonConfig getButtonConfig();
+ public void setButtonConfig(ButtonConfig button);
+ public ActionConfig getActionConfig();
+ public void setActionConfig(ActionConfig action);
+ public ButtonConfig getDefaultButtonConfig();
+ public void setDefaultButtonConfig(ButtonConfig button);
+ public ActionConfig getDefaultActionConfig();
+ public void setDefaultActionConfig(ActionConfig action);
+}
diff --git a/src/com/android/internal/utils/du/Config.java b/src/com/android/internal/utils/du/Config.java
new file mode 100644
index 0000000..214d625
--- /dev/null
+++ b/src/com/android/internal/utils/du/Config.java
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2015 TeamEos project
+ * Author Randall Rushing aka bigrushdog, randall.rushing@gmail.com
+ *
+ * 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.
+ *
+ * Config.java: A helper class for loading/setting feature button configurations
+ * to SettingsProvider. We start with defining a "action" in the nested
+ * ActionConfig class. A action holds a raw action string, a label for that action,
+ * and helper functions for loading an associated drawable for that action.
+ *
+ * The nested static class ButtonConfig is a convenience class that holds three
+ * ActionConfig objects. Those ActionConfig objects are labeled as "PRIMARY",
+ * "SECOND", and "THIRD", which will typically refer to a single tap, long press,
+ * and double tap, respectively. However, this is not always the case, thus the
+ * more generalized naming convention.
+ *
+ * ActionConfig and ButtonConfig implement the private Stringable interface to allow
+ * for easy loading and setting
+ *
+ */
+package com.android.internal.utils.du;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.android.internal.utils.du.ActionHandler;
+import com.android.internal.utils.du.ActionConstants.ConfigMap;
+import com.android.internal.utils.du.ActionConstants.Defaults;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+public class Config {
+ private interface Stringable {
+ public String toDelimitedString();
+ public void fromList(Context ctx, List<String> items);
+ }
+
+ /**
+ * For use with action/button based features that don't require a defaut configuration
+ */
+ public static ArrayList<ButtonConfig> getConfig(Context ctx, String uri,
+ boolean fromSecureSettings) {
+ if (ctx == null || uri == null) {
+ return null;
+ }
+ String config;
+ if (fromSecureSettings) {
+ config = Settings.Secure.getStringForUser(
+ ctx.getContentResolver(), uri,
+ UserHandle.USER_CURRENT);
+ } else {
+ config = Settings.System.getStringForUser(
+ ctx.getContentResolver(), uri,
+ UserHandle.USER_CURRENT);
+ }
+ if (TextUtils.isEmpty(config)) {
+ return null;
+ }
+ ArrayList<String> items = new ArrayList<String>();
+ items.addAll(Arrays.asList(config.split("\\|"))); // split string into array elements
+ int numConfigs = Integer.parseInt(items.get(0)); // first element is always the number of
+ // ButtonConfigs to parse
+ items.remove(0); // remove button count for a clean list of buttons
+
+ ArrayList<ButtonConfig> buttonList = new ArrayList<ButtonConfig>();
+ ButtonConfig buttonConfig;
+
+ for (int i = 0; i < numConfigs; i++) {
+ int from = i * ButtonConfig.NUM_ELEMENTS; // (0, 10), (10, 20)...
+ int to = from + ButtonConfig.NUM_ELEMENTS;
+ buttonConfig = new ButtonConfig(ctx);
+ buttonConfig.fromList(ctx, items.subList(from, to)); // initialize button from list
+ // elements
+ buttonList.add(buttonConfig);
+ }
+ return buttonList;
+ }
+
+ public static ArrayList<ButtonConfig> getConfig(Context ctx, Defaults defaults) {
+ if (ctx == null || defaults == null) {
+ return null;
+ }
+ String config = Settings.Secure.getStringForUser(
+ ctx.getContentResolver(), defaults.getUri(),
+ UserHandle.USER_CURRENT);
+ if (TextUtils.isEmpty(config)) {
+ config = defaults.getDefaultConfig();
+ }
+
+ ArrayList<String> items = new ArrayList<String>();
+ items.addAll(Arrays.asList(config.split("\\|"))); // split string into array elements
+ int numConfigs = Integer.parseInt(items.get(0)); // first element is always the number of ButtonConfigs to parse
+ items.remove(0); // remove button count for a clean list of buttons
+
+ ArrayList<ButtonConfig> buttonList = new ArrayList<ButtonConfig>();
+ ButtonConfig buttonConfig;
+
+ for (int i = 0; i < numConfigs; i++) {
+ int from = i * ButtonConfig.NUM_ELEMENTS; // (0, 10), (10, 20)...
+ int to = from + ButtonConfig.NUM_ELEMENTS;
+ buttonConfig = new ButtonConfig(ctx);
+ buttonConfig.fromList(ctx, items.subList(from, to)); // initialize button from list elements
+ buttonList.add(buttonConfig);
+ }
+ return buttonList;
+ }
+
+ public static ArrayList<ButtonConfig> getDefaultConfig(Context ctx, Defaults defaults) {
+ if (ctx == null || defaults == null) {
+ return null;
+ }
+ String config = defaults.getDefaultConfig();
+ ArrayList<String> items = new ArrayList<String>();
+ items.addAll(Arrays.asList(config.split("\\|")));
+ int numConfigs = Integer.parseInt(items.get(0));
+ items.remove(0);
+ ArrayList<ButtonConfig> buttonList = new ArrayList<ButtonConfig>();
+ ButtonConfig buttonConfig;
+
+ for (int i = 0; i < numConfigs; i++) {
+ int from = i * ButtonConfig.NUM_ELEMENTS;
+ int to = from + ButtonConfig.NUM_ELEMENTS;
+ buttonConfig = new ButtonConfig(ctx);
+ buttonConfig.fromList(ctx, items.subList(from, to));
+ buttonList.add(buttonConfig);
+ }
+ return buttonList;
+ }
+
+ public static void setConfig(Context ctx, Defaults defaults, ArrayList<ButtonConfig> config) {
+ if (ctx == null || defaults == null || config == null) {
+ return;
+ }
+ int numConfigs = config.size();
+ if (numConfigs <= 0) {
+ return;
+ }
+ StringBuilder b = new StringBuilder();
+ b.append(String.valueOf(numConfigs));
+ b.append(ActionConstants.ACTION_DELIMITER); // size of list is always first element
+ for (ButtonConfig button : config) {
+ b.append(button.toDelimitedString()); // this is just beautiful ;D
+ }
+ String s = b.toString();
+ if (s.endsWith(ActionConstants.ACTION_DELIMITER)) {
+ s = removeLastChar(s); // trim final delimiter if need be
+ }
+ Settings.Secure.putStringForUser(ctx.getContentResolver(), defaults.getUri(), s,
+ UserHandle.USER_CURRENT);
+ }
+
+ public static ButtonConfig getButtonConfigFromTag(ArrayList<ButtonConfig> configs, String tag) {
+ if (configs == null || tag == null) {
+ return null;
+ }
+ ButtonConfig config = null;
+ for (ButtonConfig b : configs) {
+ if (TextUtils.equals(b.getTag(), tag)) {
+ config = b;
+ break;
+ }
+ }
+ return config;
+ }
+
+ public static ArrayList<ButtonConfig> replaceButtonAtPosition(ArrayList<ButtonConfig> configs,
+ ButtonConfig button, ConfigMap map) {
+ if (configs == null || button == null || map == null) {
+ return null;
+ }
+ configs.remove(map.button);
+ configs.add(map.button, button);
+ return configs;
+ }
+
+ public static String removeLastChar(String s) {
+ if (s == null || s.length() == 0) {
+ return s;
+ }
+ return s.substring(0, s.length() - 1);
+ }
+
+ public static class ButtonConfig implements Stringable, Parcelable {
+ public static final int NUM_ELEMENTS = 10;
+ protected ActionConfig[] configs = new ActionConfig[3];
+ private String tag = ActionConstants.EMPTY;
+
+ // internal use only
+ private ButtonConfig() {
+ }
+
+ public ButtonConfig(Context ctx) {
+ configs[ActionConfig.PRIMARY] = new ActionConfig(ctx);
+ configs[ActionConfig.SECOND] = new ActionConfig(ctx);
+ configs[ActionConfig.THIRD] = new ActionConfig(ctx);
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ public boolean hasCustomIcon() {
+ return configs[ActionConfig.PRIMARY].hasCustomIcon();
+ }
+
+ public void clearCustomIconIconUri() {
+ configs[ActionConfig.PRIMARY].clearCustomIconIconUri();
+ }
+
+ public void setCustomIconUri(String type, String packageName, String iconName) {
+ configs[ActionConfig.PRIMARY].setCustomIconUri(type, packageName, iconName);
+ }
+
+ public void setCustomImageUri(Uri uri) {
+ configs[ActionConfig.PRIMARY].setCustomImageUri(uri);
+ }
+
+ public Drawable getDefaultIcon(Context ctx) {
+ return configs[ActionConfig.PRIMARY].getDefaultIcon(ctx);
+ }
+
+ public Drawable getCurrentIcon(Context ctx) {
+ return configs[ActionConfig.PRIMARY].getCurrentIcon(ctx);
+ }
+
+ public boolean isSystemAction() {
+ return configs[ActionConfig.PRIMARY].isSystemAction();
+ }
+
+ public String getSystemActionIconName() {
+ return configs[ActionConfig.PRIMARY].getSystemActionIconName();
+ }
+
+ public ActionConfig getActionConfig(int which) {
+ if (which < ActionConfig.PRIMARY || which > ActionConfig.THIRD) {
+ return null;
+ }
+ return configs[which];
+ }
+
+ public void setActionConfig(ActionConfig config, int which) {
+ if (which < ActionConfig.PRIMARY || which > ActionConfig.THIRD || config == null) {
+ return;
+ }
+ configs[which] = config;
+ }
+
+ public static void setButton(Context ctx, ButtonConfig button, String uri, boolean isSecure) {
+ StringBuilder b = new StringBuilder();
+ b.append(button.toDelimitedString()); // this is just beautiful ;D
+ String s = b.toString();
+ if (s.endsWith(ActionConstants.ACTION_DELIMITER)) {
+ s = removeLastChar(s); // trim final delimiter if need be
+ }
+
+ if (isSecure) {
+ Settings.Secure.putStringForUser(ctx.getContentResolver(), uri, s,
+ UserHandle.USER_CURRENT);
+ } else {
+ Settings.System.putStringForUser(ctx.getContentResolver(), uri, s,
+ UserHandle.USER_CURRENT);
+ }
+ }
+
+ public static ButtonConfig getButton(Context ctx, String uri, boolean isSecure) {
+ if (ctx == null || TextUtils.isEmpty(uri)) {
+ return null;
+ }
+ String config;
+ if (isSecure) {
+ config = Settings.Secure.getStringForUser(
+ ctx.getContentResolver(), uri,
+ UserHandle.USER_CURRENT);
+ } else {
+ config = Settings.System.getStringForUser(
+ ctx.getContentResolver(), uri,
+ UserHandle.USER_CURRENT);
+ }
+ if (TextUtils.isEmpty(config)) {
+ return new ButtonConfig(ctx);
+ }
+ ArrayList<String> items = new ArrayList<String>();
+ items.addAll(Arrays.asList(config.split("\\|")));
+ ButtonConfig buttonConfig = new ButtonConfig(ctx);
+ buttonConfig.fromList(ctx, items.subList(0, NUM_ELEMENTS)); // initialize button from
+ // list elements
+ return buttonConfig;
+ }
+
+ @Override
+ public String toDelimitedString() {
+ return tag + ActionConstants.ACTION_DELIMITER
+ + configs[ActionConfig.PRIMARY].toDelimitedString()
+ + configs[ActionConfig.SECOND].toDelimitedString()
+ + configs[ActionConfig.THIRD].toDelimitedString();
+ }
+
+ @Override
+ public void fromList(Context ctx, List<String> items) {
+ ArrayList<String> buttons = new ArrayList<String>();
+ buttons.addAll(items);
+ tag = buttons.get(0);
+
+ ActionConfig config = new ActionConfig();
+ config.fromList(ctx, buttons.subList(1, 4));
+ configs[ActionConfig.PRIMARY] = config;
+
+ config = new ActionConfig();
+ config.fromList(ctx, buttons.subList(4, 7));
+ configs[ActionConfig.SECOND] = config;
+
+ config = new ActionConfig();
+ config.fromList(ctx, buttons.subList(7, 10));
+ configs[ActionConfig.THIRD] = config;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(tag);
+ dest.writeParcelable(configs[ActionConfig.PRIMARY], flags);
+ dest.writeParcelable(configs[ActionConfig.SECOND], flags);
+ dest.writeParcelable(configs[ActionConfig.THIRD], flags);
+ }
+
+ public static final Parcelable.Creator<ButtonConfig> CREATOR = new Parcelable.Creator<ButtonConfig>() {
+ public ButtonConfig createFromParcel(Parcel in) {
+ return new ButtonConfig(in);
+ }
+
+ public ButtonConfig[] newArray(int size) {
+ return new ButtonConfig[size];
+ }
+ };
+
+ private ButtonConfig(Parcel in) {
+ tag = in.readString();
+ configs[ActionConfig.PRIMARY] = (ActionConfig) in.readParcelable(Config.ActionConfig.class
+ .getClassLoader());
+ configs[ActionConfig.SECOND] = (ActionConfig) in.readParcelable(Config.ActionConfig.class
+ .getClassLoader());
+ configs[ActionConfig.THIRD] = (ActionConfig) in.readParcelable(Config.ActionConfig.class
+ .getClassLoader());
+ }
+ }
+
+ public static class ActionConfig implements Stringable, Comparable<ActionConfig>, Parcelable {
+ public static final int PRIMARY = 0;
+ public static final int SECOND = 1;
+ public static final int THIRD = 2;
+
+ private String action = ActionHandler.SYSTEMUI_TASK_NO_ACTION;
+ private String label = ActionConstants.EMPTY;
+ private String iconUri = ActionConstants.EMPTY;
+
+ // internal use only
+ private ActionConfig() {
+ }
+
+ public static ActionConfig create(Context ctx) {
+ return new ActionConfig(ctx);
+ }
+
+ public static ActionConfig create(Context ctx, String action) {
+ return new ActionConfig(ctx, action);
+ }
+
+ public static ActionConfig create(Context ctx, String action, String iconUri) {
+ return new ActionConfig(ctx, action, iconUri);
+ }
+
+ public ActionConfig(Context ctx) {
+ label = DUActionUtils.getFriendlyNameForUri(ctx, action);
+ }
+
+ public ActionConfig(Context ctx, String action) {
+ this.action = action;
+ label = DUActionUtils.getFriendlyNameForUri(ctx, action);
+ }
+
+ public ActionConfig(Context ctx, String action, String iconUri) {
+ this(ctx, action);
+ this.iconUri = iconUri;
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public String getIconUri() {
+ if (!hasCustomIcon()) {
+ return action;
+ } else {
+ return iconUri;
+ }
+ }
+
+ public boolean hasCustomIcon() {
+ return !TextUtils.equals(ActionConstants.EMPTY, iconUri);
+ }
+
+ public void clearCustomIconIconUri() {
+ iconUri = ActionConstants.EMPTY;
+ }
+
+ public boolean isSystemAction() {
+ return action.startsWith(ActionHandler.SYSTEM_PREFIX);
+ }
+
+ public String getSystemActionIconName() {
+ if (action.startsWith(ActionHandler.SYSTEM_PREFIX)) {
+ for (int i = 0; i < ActionHandler.systemActions.length; i++) {
+ if (ActionHandler.systemActions[i].mAction.equals(action)) {
+ return ActionHandler.systemActions[i].mIconRes;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void setCustomImageUri(Uri uri) {
+ iconUri = "image$" + uri.toString();
+ }
+
+ public void setCustomIconUri(String type, String packageName, String iconName) {
+ StringBuilder b = new StringBuilder()
+ .append(type)
+ .append("$")
+ .append(packageName)
+ .append("$")
+ .append(iconName);
+ iconUri = b.toString();
+ }
+
+ public Drawable getDefaultIcon(Context ctx) {
+ return DUActionUtils.getDrawableForAction(ctx, action);
+ }
+
+ /**
+ * Returns custom icon (if exists)
+ * @param ctx app's context
+ * @return drawable when custom icon exists, null otherwise
+ */
+ public Drawable getCurrentCustomIcon(Context ctx) {
+ if (hasCustomIcon()) {
+ List<String> items = Arrays.asList(iconUri.split("\\$"));
+ String type = items.get(0);
+ if (type.equals("iconpack") && items.size() == 3) {
+ String packageName = items.get(1);
+ String iconName = items.get(2);
+ return DUActionUtils.getDrawable(ctx, iconName, packageName);
+ } else if (type.equals("image") && items.size() == 2) {
+ String uri = items.get(1);
+ return DUActionUtils.getDrawable(ctx, Uri.parse(uri));
+ }
+ }
+ return null;
+ }
+
+ public Drawable getCurrentIcon(Context ctx) {
+
+ Drawable drawable = getCurrentCustomIcon(ctx);
+
+ //If icon doesn't exist (or is not set) fallback to action one
+ if (drawable == null) {
+ drawable = DUActionUtils.getDrawableForAction(ctx, action);
+ }
+
+ return drawable;
+
+ }
+
+ public boolean hasNoAction() {
+ return TextUtils.equals(action, ActionHandler.SYSTEMUI_TASK_NO_ACTION)
+ || TextUtils.equals(action, ActionConstants.EMPTY);
+ }
+
+ public boolean isActionRecents() {
+ return TextUtils.equals(action, ActionHandler.SYSTEMUI_TASK_RECENTS);
+ }
+
+ @Override
+ public int compareTo(ActionConfig another) {
+ int result = label.toString().compareToIgnoreCase(another.label.toString());
+ return result;
+ }
+
+ @Override
+ public String toDelimitedString() {
+ return action + ActionConstants.ACTION_DELIMITER
+ + label + ActionConstants.ACTION_DELIMITER
+ + iconUri + ActionConstants.ACTION_DELIMITER;
+ }
+
+ @Override
+ public void fromList(Context ctx, List<String> items) {
+ ArrayList<String> actionStrings = new ArrayList<String>();
+ actionStrings.addAll(items);
+ action = items.get(0);
+ label = DUActionUtils.getFriendlyNameForUri(ctx, action);
+ iconUri = items.get(2);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(action);
+ dest.writeString(label);
+ dest.writeString(iconUri);
+ }
+
+ public static final Parcelable.Creator<ActionConfig> CREATOR = new Parcelable.Creator<ActionConfig>() {
+ public ActionConfig createFromParcel(Parcel in) {
+ return new ActionConfig(in);
+ }
+
+ public ActionConfig[] newArray(int size) {
+ return new ActionConfig[size];
+ }
+ };
+
+ private ActionConfig(Parcel in) {
+ action = in.readString();
+ label = in.readString();
+ iconUri = in.readString();
+ }
+ }
+}
diff --git a/src/com/android/internal/utils/du/DUActionUtils.java b/src/com/android/internal/utils/du/DUActionUtils.java
new file mode 100644
index 0000000..12a72e0
--- /dev/null
+++ b/src/com/android/internal/utils/du/DUActionUtils.java
@@ -0,0 +1,759 @@
+/*
+ * Copyright (C) 2014 The TeamEos Project
+ *
+ * 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.
+ *
+ * Helper functions mostly for device configuration and some utilities
+ * including a fun ViewGroup crawler and dpi conversion
+ *
+ */
+
+package com.android.internal.utils.du;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+//import android.content.res.ThemeConfig;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.utils.du.ActionConstants.Defaults;
+import com.android.internal.utils.du.Config.ActionConfig;
+import com.android.internal.utils.du.Config.ButtonConfig;
+
+public final class DUActionUtils {
+ public static final String ANDROIDNS = "http://schemas.android.com/apk/res/android";
+ public static final String PACKAGE_SYSTEMUI = "com.android.systemui";
+ public static final String PACKAGE_ANDROID = "android";
+ public static final String FORMAT_NONE = "none";
+ public static final String FORMAT_FLOAT = "float";
+
+ public static final String ID = "id";
+ public static final String DIMEN = "dimen";
+ public static final String DIMEN_PIXEL = "dimen_pixel";
+ public static final String FLOAT = "float";
+ public static final String INT = "integer";
+ public static final String DRAWABLE = "drawable";
+ public static final String COLOR = "color";
+ public static final String BOOL = "bool";
+ public static final String STRING = "string";
+ public static final String ANIM = "anim";
+
+ public static final int DUI_ICON_MAX_WIDTH = 512;
+ public static final int DUI_ICON_MAX_HEIGHT = 512;
+
+ // 10 inch tablets
+ public static boolean isXLargeScreen() {
+ int screenLayout = Resources.getSystem().getConfiguration().screenLayout &
+ Configuration.SCREENLAYOUT_SIZE_MASK;
+ return screenLayout == Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ }
+
+ // 7 inch "phablets" i.e. grouper
+ public static boolean isLargeScreen() {
+ int screenLayout = Resources.getSystem().getConfiguration().screenLayout &
+ Configuration.SCREENLAYOUT_SIZE_MASK;
+ return screenLayout == Configuration.SCREENLAYOUT_SIZE_LARGE;
+ }
+
+ // normal phones
+ public static boolean isNormalScreen() {
+ int screenLayout = Resources.getSystem().getConfiguration().screenLayout &
+ Configuration.SCREENLAYOUT_SIZE_MASK;
+ return screenLayout == Configuration.SCREENLAYOUT_SIZE_NORMAL;
+ }
+
+ public static boolean isLandscape(Context context) {
+ return Configuration.ORIENTATION_LANDSCAPE
+ == context.getResources().getConfiguration().orientation;
+ }
+
+ public static boolean navigationBarCanMove() {
+ return Resources.getSystem().getConfiguration().smallestScreenWidthDp < 600;
+ }
+
+ public static boolean hasNavbarByDefault(Context context) {
+ boolean needsNav = (Boolean)getValue(context, "config_showNavigationBar", BOOL, PACKAGE_ANDROID);
+ String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+ if ("1".equals(navBarOverride)) {
+ needsNav = false;
+ } else if ("0".equals(navBarOverride)) {
+ needsNav = true;
+ }
+ return needsNav;
+ }
+
+ public static boolean deviceSupportsLte(Context ctx) {
+ final TelephonyManager tm = (TelephonyManager)
+ ctx.getSystemService(Context.TELEPHONY_SERVICE);
+// return (tm.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE)
+// || tm.getLteOnGsmMode() != 0;
+ return tm.getLteOnCdmaMode() == PhoneConstants.LTE_ON_CDMA_TRUE;
+ }
+
+ public static boolean deviceSupportsDdsSupported(Context context) {
+ TelephonyManager tm = (TelephonyManager)
+ context.getSystemService(Context.TELEPHONY_SERVICE);
+ return tm.isMultiSimEnabled()
+ && tm.getMultiSimConfiguration() == TelephonyManager.MultiSimVariants.DSDA;
+ }
+
+ public static boolean deviceSupportsMobileData(Context ctx) {
+ ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ return cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ }
+
+ public static boolean deviceSupportsBluetooth() {
+ return BluetoothAdapter.getDefaultAdapter() != null;
+ }
+
+ public static boolean deviceSupportsNfc(Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ return packageManager.hasSystemFeature(PackageManager.FEATURE_NFC);
+ }
+
+ public static boolean deviceSupportsFlashLight(Context context) {
+ CameraManager cameraManager = (CameraManager) context.getSystemService(
+ Context.CAMERA_SERVICE);
+ try {
+ String[] ids = cameraManager.getCameraIdList();
+ for (String id : ids) {
+ CameraCharacteristics c = cameraManager.getCameraCharacteristics(id);
+ Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
+ Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
+ if (flashAvailable != null
+ && flashAvailable
+ && lensFacing != null
+ && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
+ return true;
+ }
+ }
+ } catch (CameraAccessException | AssertionError e) {
+ // Ignore
+ }
+ return false;
+ }
+
+ public static boolean deviceSupportsCompass(Context context) {
+ SensorManager sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ return sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null
+ && sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null;
+ }
+
+ public static boolean deviceSupportsDoze(Context context) {
+ String name = (String) getValue(context, "config_dozeComponent",
+ STRING, PACKAGE_ANDROID);
+ return !TextUtils.isEmpty(name);
+ }
+
+ /**
+ * This method converts dp unit to equivalent pixels, depending on device
+ * density.
+ *
+ * @param dp A value in dp (density independent pixels) unit. Which we need
+ * to convert into pixels
+ * @param context Context to get resources and device specific display
+ * metrics
+ * @return A float value to represent px equivalent to dp depending on
+ * device density
+ */
+ public static float convertDpToPixel(float dp, Context context) {
+ Resources resources = context.getResources();
+ DisplayMetrics metrics = resources.getDisplayMetrics();
+ float px = dp * (metrics.densityDpi / 160f);
+ return px;
+ }
+
+ public static int ConvertDpToPixelAsInt(float dp, Context context) {
+ float px = convertDpToPixel(dp, context);
+ if (px < 1)
+ px = 1;
+ return Math.round(px);
+ }
+
+ public static int ConvertDpToPixelAsInt(int dp, Context context) {
+ float px = convertDpToPixel((float) dp, context);
+ if (px < 1)
+ px = 1;
+ return Math.round(px);
+ }
+
+ /**
+ * This method converts device specific pixels to density independent
+ * pixels.
+ *
+ * @param px A value in px (pixels) unit. Which we need to convert into db
+ * @param context Context to get resources and device specific display
+ * metrics
+ * @return A float value to represent dp equivalent to px value
+ */
+ public static float convertPixelsToDp(float px, Context context) {
+ Resources resources = context.getResources();
+ DisplayMetrics metrics = resources.getDisplayMetrics();
+ float dp = px / (metrics.densityDpi / 160f);
+ return dp;
+ }
+
+ public static int dpToPx(Context context, int dp) {
+ return (int) ((dp * context.getResources().getDisplayMetrics().density) + 0.5);
+ }
+
+ public static int pxToDp(Context context, int px) {
+ return (int) ((px / context.getResources().getDisplayMetrics().density) + 0.5);
+ }
+
+ /* utility to iterate a viewgroup and return a list of child views */
+ public static ArrayList<View> getAllChildren(View v) {
+
+ if (!(v instanceof ViewGroup)) {
+ ArrayList<View> viewArrayList = new ArrayList<View>();
+ viewArrayList.add(v);
+ return viewArrayList;
+ }
+
+ ArrayList<View> result = new ArrayList<View>();
+
+ ViewGroup vg = (ViewGroup) v;
+ for (int i = 0; i < vg.getChildCount(); i++) {
+
+ View child = vg.getChildAt(i);
+
+ ArrayList<View> viewArrayList = new ArrayList<View>();
+ viewArrayList.add(v);
+ viewArrayList.addAll(getAllChildren(child));
+
+ result.addAll(viewArrayList);
+ }
+ return result;
+ }
+
+ /* utility to iterate a viewgroup and return a list of child views of type */
+ public static <T extends View> ArrayList<T> getAllChildren(View root, Class<T> returnType) {
+ if (!(root instanceof ViewGroup)) {
+ ArrayList<T> viewArrayList = new ArrayList<T>();
+ try {
+ viewArrayList.add(returnType.cast(root));
+ } catch (Exception e) {
+ // handle all exceptions the same and silently fail
+ }
+ return viewArrayList;
+ }
+ ArrayList<T> result = new ArrayList<T>();
+ ViewGroup vg = (ViewGroup) root;
+ for (int i = 0; i < vg.getChildCount(); i++) {
+ View child = vg.getChildAt(i);
+ ArrayList<T> viewArrayList = new ArrayList<T>();
+ try {
+ viewArrayList.add(returnType.cast(root));
+ } catch (Exception e) {
+ // handle all exceptions the same and silently fail
+ }
+ viewArrayList.addAll(getAllChildren(child, returnType));
+ result.addAll(viewArrayList);
+ }
+ return result;
+ }
+
+ public static void resolveAndUpdateButtonActions(Context ctx, Defaults defaults) {
+ if (ctx == null || defaults == null) {
+ return;
+ }
+ boolean configChanged = false;
+ final PackageManager pm = ctx.getPackageManager();
+ ArrayList<ButtonConfig> configs = Config.getConfig(ctx, defaults);
+ ArrayList<ButtonConfig> buttonsToChange = new ArrayList<ButtonConfig>();
+ buttonsToChange.addAll(configs);
+ for (int h = 0; h < configs.size(); h++) {
+ ButtonConfig button = configs.get(h);
+ for (int i = 0; i < 3; i++) {
+ ActionConfig action = button.getActionConfig(i);
+ final String task = action.getAction();
+ if (task.startsWith(ActionHandler.SYSTEM_PREFIX)) {
+ continue;
+ }
+ String resolvedName = getFriendlyNameForUri(ctx, task);
+ if (resolvedName == null || TextUtils.equals(resolvedName, task)) {
+ // if resolved name is null or the full raw intent string is
+ // returned, we were unable to resolve
+ configChanged = true;
+ ActionConfig newAction = new ActionConfig(ctx,
+ ActionHandler.SYSTEMUI_TASK_NO_ACTION, action.getIconUri());
+ ButtonConfig newButton = buttonsToChange.get(h);
+ newButton.setActionConfig(newAction, i);
+ buttonsToChange.remove(h);
+ buttonsToChange.add(h, newButton);
+ }
+ }
+ }
+ if (configChanged) {
+ Config.setConfig(ctx, defaults, buttonsToChange);
+ }
+ }
+
+ public static Intent getIntent(String uri) {
+ if (uri == null || uri.startsWith(ActionHandler.SYSTEM_PREFIX)) {
+ return null;
+ }
+
+ Intent intent = null;
+ try {
+ intent = Intent.parseUri(uri, 0);
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ return intent;
+ }
+
+ public static Object getValue(Context context, String resName, String resType, String pkg) {
+ return getValue(context, resName, resType, null, pkg);
+ }
+
+ public static Object getValue(Context context, String resName, String resType, String format,
+ String pkg) {
+ Resources res = getResourcesForPackage(context, pkg);
+ String tmp;
+ if (resType.equals(DIMEN_PIXEL)) {
+ tmp = DIMEN;
+ } else {
+ tmp = resType;
+ }
+ int id = res.getIdentifier(resName, tmp, pkg);
+ if (format != null) { // standard res
+ TypedValue typedVal = new TypedValue();
+ res.getValue(id, typedVal, true);
+ if (format.equals(FORMAT_FLOAT)) {
+ return Float.valueOf(typedVal.getFloat());
+ }
+ } else { // typed values
+ if (resType.equals(ID)) {
+ return Integer.valueOf(id);
+ } else if (resType.equals(DIMEN)) {
+ return Float.valueOf(res.getDimension(id));
+ } else if (resType.equals(DIMEN_PIXEL)) {
+ return Integer.valueOf(res.getDimensionPixelSize(id));
+ } else if (resType.equals(FLOAT)) {
+ return Float.valueOf(res.getFloat(id));
+ } else if (resType.equals(INT)) {
+ return Integer.valueOf(res.getInteger(id));
+ } else if (resType.equals(COLOR)) {
+ int rawColor = res.getColor(id);
+ return Integer.valueOf(Color.argb(Color.alpha(rawColor), Color.red(rawColor),
+ Color.green(rawColor), Color.blue(rawColor)));
+ } else if (resType.equals(BOOL)) {
+ return Boolean.valueOf(res.getBoolean(id));
+ } else if (resType.equals(STRING)) {
+ return String.valueOf(res.getString(id));
+ } else if (resType.equals(DRAWABLE)) {
+ return getDrawable(context, resName, pkg);
+ }
+ }
+ return null;
+ }
+
+ public static void putValue(String key, Object val, String type, Bundle b) {
+ if (type.equals(ID) || type.equals(DIMEN_PIXEL) || type.equals(INT) || type.equals(COLOR)) {
+ b.putInt(key, (Integer) val);
+ } else if (type.equals(FLOAT) || type.equals(DIMEN)) {
+ b.putFloat(key, (Float) val);
+ } else if (type.equals(BOOL)) {
+ b.putBoolean(key, (Boolean) val);
+ } else if (type.equals(STRING)) {
+ b.putString(key, (String) val);
+ }
+ }
+
+ public static int getIdentifier(Context context, String resName, String resType, String pkg) {
+ try {
+ Resources res = context.getPackageManager()
+ .getResourcesForApplication(pkg);
+ int ident = res.getIdentifier(resName, resType, pkg);
+ return ident;
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
+ public static String getString(Context context, String resName, String pkg) {
+ return (String) getValue(context, resName, STRING, null, pkg);
+ }
+
+ public static boolean getBoolean(Context context, String resName, String pkg) {
+ return (Boolean) getValue(context, resName, BOOL, null, pkg);
+ }
+
+ public static int getInt(Context context, String resName, String pkg) {
+ return (Integer) getValue(context, resName, INT, null, pkg);
+ }
+
+ public static int getColor(Context context, String resName, String pkg) {
+ return (Integer) getValue(context, resName, COLOR, null, pkg);
+ }
+
+ public static int getId(Context context, String resName, String pkg) {
+ return (Integer) getValue(context, resName, ID, null, pkg);
+ }
+
+ public static float getDimen(Context context, String resName, String pkg) {
+ return (Float) getValue(context, resName, DIMEN, null, pkg);
+ }
+
+ public static int getDimenPixelSize(Context context, String resName, String pkg) {
+ return (Integer) getValue(context, resName, DIMEN_PIXEL, null, pkg);
+ }
+
+ public static Drawable getDrawable(Context context, String drawableName, String pkg) {
+ return getDrawable(getResourcesForPackage(context, pkg), drawableName, pkg);
+ }
+
+ public static Drawable getDrawable(Context context, Uri uri) {
+ //set inputs here so we can clean up them in the finally
+ InputStream inputStream = null;
+
+ try {
+ //get the inputstream
+ inputStream = context.getContentResolver().openInputStream(uri);
+
+ //get available bitmapfactory options
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ //query the bitmap to decode the stream but don't allocate pixels in memory yet
+ options.inJustDecodeBounds = true;
+ //decode the bitmap with calculated bounds
+ Bitmap b1 = BitmapFactory.decodeStream(inputStream, null, options);
+ //get raw height and width of the bitmap
+ int rawHeight = options.outHeight;
+ int rawWidth = options.outWidth;
+
+ //check if the bitmap is big and we need to scale the quality to take less memory
+ options.inSampleSize = calculateInSampleSize(options, rawHeight, rawWidth);
+
+ //We need to close and load again the inputstream to avoid null
+ try {
+ inputStream.close();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ inputStream = context.getContentResolver().openInputStream(uri);
+
+ //decode the stream again, with the calculated SampleSize option,
+ //and allocate the memory. Also add some metrics options to take a proper density
+ options.inJustDecodeBounds = false;
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ options.inScreenDensity = metrics.densityDpi;
+ options.inTargetDensity = metrics.densityDpi;
+ options.inDensity = DisplayMetrics.DENSITY_DEFAULT;
+ b1 = BitmapFactory.decodeStream(inputStream, null, options);
+ return new BitmapDrawable(context.getResources(), b1);
+
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ return null;
+ //clean up the system resources
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ //Automate the quality scaling process
+ public static int calculateInSampleSize(BitmapFactory.Options options, int height, int width) {
+ //set default inSampleSize scale factor (no scaling)
+ int inSampleSize = 1;
+
+ //if img size is in 257-512 range, sample scale factor will be 4x
+ if (height > 256 || width > 256) {
+ inSampleSize = 4;
+ return inSampleSize;
+ //if img size is in 129-256 range, sample scale factor will be 2x
+ } else if (height > 128 || width > 128) {
+ inSampleSize = 2;
+ return inSampleSize;
+ }
+ //if img size is in 0-128 range, no need to scale it
+ return inSampleSize;
+ }
+
+ /**
+ * Screen images based on desired dimensions before fully decoding
+ *
+ *@param ctx Calling context
+ *@param uri Image uri
+ *@param maxWidth maximum allowed image width
+ *@param maxHeight maximum allowed image height
+ */
+ public static boolean isBitmapAllowedSize(Context ctx, Uri uri, int maxWidth, int maxHeight) {
+ InputStream inputStream = null;
+ try {
+ inputStream = ctx.getContentResolver().openInputStream(uri);
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(inputStream, null, options);
+ if (options.outWidth <= maxWidth && options.outHeight <= maxHeight) {
+ return true;
+ }
+ } catch (Exception e) {
+ return false;
+ } finally {
+ try {
+ inputStream.close();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+
+ public static Drawable getDrawableFromComponent(PackageManager pm, String activity) {
+ Drawable d = null;
+ try {
+ Intent intent = Intent.parseUri(activity, 0);
+ ActivityInfo info = intent.resolveActivityInfo(pm,
+ PackageManager.GET_ACTIVITIES);
+ if (info != null) {
+ d = info.loadIcon(pm);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return d;
+ }
+
+ public static String getFriendlyActivityName(PackageManager pm, Intent intent,
+ boolean labelOnly) {
+ ActivityInfo ai = intent.resolveActivityInfo(pm, PackageManager.GET_ACTIVITIES);
+ String friendlyName = null;
+ if (ai != null) {
+ friendlyName = ai.loadLabel(pm).toString();
+ if (friendlyName == null && !labelOnly) {
+ friendlyName = ai.name;
+ }
+ }
+ return friendlyName != null || labelOnly ? friendlyName : intent.toUri(0);
+ }
+
+ public static String getFriendlyShortcutName(PackageManager pm, Intent intent) {
+ String activityName = getFriendlyActivityName(pm, intent, true);
+ String name = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+
+ if (activityName != null && name != null) {
+ return activityName + ": " + name;
+ }
+ return name != null ? name : intent.toUri(0);
+ }
+
+ public static String getFriendlyNameForUri(Context ctx, String uri) {
+ if (uri == null) {
+ return null;
+ }
+ if (uri.startsWith(ActionHandler.SYSTEM_PREFIX)) {
+ for (int i = 0; i < ActionHandler.systemActions.length; i++) {
+ if (ActionHandler.systemActions[i].mAction.equals(uri)) {
+ return getString(ctx, ActionHandler.systemActions[i].mLabelRes,
+ ActionHandler.systemActions[i].mResPackage);
+ }
+ }
+ } else {
+ try {
+ Intent intent = Intent.parseUri(uri, 0);
+ if (Intent.ACTION_MAIN.equals(intent.getAction())) {
+ return getFriendlyActivityName(ctx.getPackageManager(), intent, false);
+ }
+ return getFriendlyShortcutName(ctx.getPackageManager(), intent);
+ } catch (URISyntaxException e) {
+ }
+ }
+ return uri;
+ }
+
+ /**
+ *
+ * @param Target package resources
+ * @param drawableName
+ * @param Target package name
+ * @return the drawable if found, otherwise fall back to a green android guy
+ */
+ public static Drawable getDrawable(Resources res, String drawableName, String pkg) {
+ try {
+ int resId = res.getIdentifier(drawableName, DRAWABLE, pkg);
+ Drawable icon = ImageHelper.getVector(res, resId, false);
+ if (icon == null) {
+ icon = res.getDrawable(resId);
+ }
+ return icon;
+ } catch (Exception e) {
+ return res.getDrawable(
+ com.android.internal.R.drawable.sym_def_app_icon);
+ }
+ }
+
+ /**
+ *
+ * @param Target package resources
+ * @param drawableName
+ * @param Target package name
+ * @return the drawable if found, null otherwise. Useful for testing if a drawable is found
+ * in a theme overlay
+ */
+ private static Drawable getMaybeNullDrawable(Resources res, String drawableName, String pkg) {
+ try {
+ int resId = res.getIdentifier(drawableName, DRAWABLE, pkg);
+ Drawable icon = ImageHelper.getVector(res, resId, false);
+ if (icon == null) {
+ icon = res.getDrawable(resId);
+ }
+ return icon;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static Resources getResourcesForPackage(Context ctx, String pkg) {
+ try {
+ Resources res = ctx.getPackageManager()
+ .getResourcesForApplication(pkg);
+ return res;
+ } catch (Exception e) {
+ return ctx.getResources();
+ }
+ }
+
+ /**
+ *
+ * @param Context of the calling package
+ * @param the action we want a drawable for
+ * @return if a system action drawable is requested, we try to get the drawable
+ * from any current navigation overlay. if no overlay is found, get it
+ * from SystemUI. Return a component drawable if not a system action
+ */
+ public static Drawable getDrawableForAction(Context context, String action) {
+ Drawable d = null;
+
+ // this null check is probably no-op but let's be safe anyways
+ if (action == null || context == null) {
+ return d;
+ }
+ if (action.startsWith(ActionHandler.SYSTEM_PREFIX)) {
+ for (int i = 0; i < ActionHandler.systemActions.length; i++) {
+ if (ActionHandler.systemActions[i].mAction.equals(action)) {
+ // should always be SystemUI
+ String packageName = ActionHandler.systemActions[i].mResPackage;
+ Resources res = getResourcesForPackage(context, packageName);
+ String iconName = ActionHandler.systemActions[i].mIconRes;
+ d = getNavbarThemedDrawable(context, res, iconName);
+ if (d == null) {
+ d = getDrawable(res, iconName, packageName);
+ }
+ }
+ }
+ } else {
+ d = getDrawableFromComponent(context.getPackageManager(), action);
+ }
+ return d;
+ }
+
+ /**
+ *
+ * @param calling package context, usually Settings for the custom action list adapter
+ * @param target package resources, usually SystemUI
+ * @param drawableName
+ * @return a navigation bar overlay themed action drawable if available, otherwise
+ * return drawable from SystemUI resources
+ */
+ public static Drawable getNavbarThemedDrawable(Context context, Resources defRes,
+ String drawableName) {
+ if (context == null || defRes == null || drawableName == null)
+ return null;
+
+ // TODO: turn on cmte support when it comes back
+ return getDrawable(defRes, drawableName, PACKAGE_SYSTEMUI);
+/*
+ ThemeConfig themeConfig = context.getResources().getConfiguration().themeConfig;
+
+ Drawable d = null;
+ if (themeConfig != null) {
+ try {
+ final String navbarThemePkgName = themeConfig.getOverlayForNavBar();
+ final String sysuiThemePkgName = themeConfig.getOverlayForStatusBar();
+ // Check if the same theme is applied for systemui, if so we can skip this
+ if (navbarThemePkgName != null && !navbarThemePkgName.equals(sysuiThemePkgName)) {
+ // Navbar theme and SystemUI (statusbar) theme packages are different
+ // But we can't assume navbar package has our drawable, so try navbar theme
+ // package first. If we fail, try the systemui (statusbar) package
+ // if we still fail, fall back to default package resource
+ Resources res = context.getPackageManager().getThemedResourcesForApplication(
+ PACKAGE_SYSTEMUI, navbarThemePkgName);
+ d = getMaybeNullDrawable(res, drawableName, PACKAGE_SYSTEMUI);
+ if (d == null) {
+ // drawable not found in overlay, get from default SystemUI res
+ d = getDrawable(defRes, drawableName, PACKAGE_SYSTEMUI);
+ }
+ } else {
+ // no navbar overlay present, get from default SystemUI res
+ d = getDrawable(defRes, drawableName, PACKAGE_SYSTEMUI);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // error thrown (unlikely), get from default SystemUI res
+ d = getDrawable(defRes, drawableName, PACKAGE_SYSTEMUI);
+ }
+ }
+ if (d == null) {
+ // theme config likely null, get from default SystemUI res
+ d = getDrawable(defRes, drawableName, PACKAGE_SYSTEMUI);
+ }
+ return d;
+ */
+ }
+}
diff --git a/src/com/android/internal/utils/du/DUPackageMonitor.java b/src/com/android/internal/utils/du/DUPackageMonitor.java
new file mode 100644
index 0000000..e922986
--- /dev/null
+++ b/src/com/android/internal/utils/du/DUPackageMonitor.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2015-2016 The TeamEos Project
+ *
+ * Author: Randall Rushing <bigrushdog@teameos.org>
+ *
+ * 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.
+ *
+ * A simplified package monitor class with easy-to-use callbacks when a
+ * state changes. We register the receiver on background thread but post events
+ * to the UI thread
+ */
+
+package com.android.internal.utils.du;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+
+import java.util.ArrayList;
+
+public class DUPackageMonitor extends com.android.internal.content.PackageMonitor {
+ private static final int MSG_PACKAGE_ADDED = 1;
+ private static final int MSG_PACKAGE_REMOVED = 2;
+ private static final int MSG_PACKAGE_CHANGED = 3;
+
+ public static enum PackageState {
+ PACKAGE_REMOVED,
+ PACKAGE_ADDED,
+ PACKAGE_CHANGED
+ }
+
+ public interface PackageChangedListener {
+ public void onPackageChanged(String pkg, PackageState state);
+ }
+
+ private Handler mHandler;
+
+ private ArrayList<PackageChangedListener> mListeners = new ArrayList<PackageChangedListener>();
+
+ public void register(Context context, Handler foreground) {
+ register(context, null, null, true);
+
+ mHandler = new Handler(foreground.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PACKAGE_ADDED:
+ for (PackageChangedListener listener : mListeners) {
+ listener.onPackageChanged((String) msg.obj, PackageState.PACKAGE_ADDED);
+ }
+ break;
+ case MSG_PACKAGE_REMOVED:
+ for (PackageChangedListener listener : mListeners) {
+ listener.onPackageChanged((String) msg.obj,
+ PackageState.PACKAGE_REMOVED);
+ }
+ break;
+ case MSG_PACKAGE_CHANGED:
+ for (PackageChangedListener listener : mListeners) {
+ listener.onPackageChanged((String) msg.obj,
+ PackageState.PACKAGE_CHANGED);
+ }
+ break;
+ }
+ }
+ };
+ }
+
+ public void addListener(PackageChangedListener listener) {
+ if (listener != null) {
+ mListeners.add(listener);
+ }
+ }
+
+ public void removeListener(PackageChangedListener listener) {
+ if (listener != null) {
+ mListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Called when a package is really added (and not replaced).
+ */
+ public void onPackageAdded(String packageName, int uid) {
+ Message msg = mHandler.obtainMessage(MSG_PACKAGE_ADDED, packageName);
+ mHandler.sendMessage(msg);
+ }
+
+ /**
+ * Called when a package is really removed (and not replaced).
+ */
+ public void onPackageRemoved(String packageName, int uid) {
+ Message msg = mHandler.obtainMessage(MSG_PACKAGE_REMOVED, packageName);
+ mHandler.sendMessage(msg);
+ }
+
+ /**
+ * Direct reflection of {@link Intent#ACTION_PACKAGE_CHANGED Intent.ACTION_PACKAGE_CHANGED}
+ * being received, informing you of changes to the enabled/disabled state of components in a
+ * package and/or of the overall package.
+ *
+ * @param packageName The name of the package that is changing.
+ * @param uid The user ID the package runs under.
+ * @param components Any components in the package that are changing. If the overall package is
+ * changing, this will contain an entry of the package name itself.
+ * @return Return true to indicate you care about this change, which will result in
+ * {@link #onSomePackagesChanged()} being called later. If you return false, no further
+ * callbacks will happen about this change. The default implementation returns true if
+ * this is a change to the entire package.
+ */
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ Message msg = mHandler.obtainMessage(MSG_PACKAGE_CHANGED, packageName);
+ mHandler.sendMessage(msg);
+ return super.onPackageChanged(packageName, uid, components);
+ }
+}
diff --git a/src/com/android/internal/utils/du/DUSystemReceiver.java b/src/com/android/internal/utils/du/DUSystemReceiver.java
new file mode 100644
index 0000000..1df571c
--- /dev/null
+++ b/src/com/android/internal/utils/du/DUSystemReceiver.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015-2016 The TeamEos Project
+ *
+ * Author: Randall Rushing <bigrushdog@teameos.org>
+ *
+ * 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.
+ *
+ * A BroadcastReceiver that filters out broadcasts from non-system
+ * related processes. Subclasses can allow additional broadcasting
+ * packages by overriding onExemptBroadcast(Context context, String packageName)
+ */
+
+package com.android.internal.utils.du;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public abstract class DUSystemReceiver extends BroadcastReceiver {
+
+ protected abstract void onSecureReceive(Context context, Intent intent);
+
+ protected boolean onExemptBroadcast(Context context, String packageName) {
+ return false;
+ }
+
+ @Override
+ public final void onReceive(Context context, Intent intent) {
+ if (context == null || intent == null) {
+ return;
+ }
+ if (isBroadcastFromSystem(context)) {
+ onSecureReceive(context, intent);
+ }
+ }
+
+ private boolean isBroadcastFromSystem(Context context) {
+ String packageName = context.getPackageName();
+ if (packageName == null
+ && android.os.Process.SYSTEM_UID == context.getApplicationInfo().uid) {
+ packageName = "android";
+ }
+ if (packageName == null) {
+ return false;
+ }
+ if (packageName.equals("com.android.systemui")
+ || packageName.equals("com.android.keyguard")
+ || packageName.equals("com.android.settings")
+ || packageName.equals("android")
+ || context.getApplicationInfo().uid == android.os.Process.SYSTEM_UID) {
+ return true;
+ }
+ if (onExemptBroadcast(context, packageName)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/internal/utils/du/ImageHelper.java b/src/com/android/internal/utils/du/ImageHelper.java
new file mode 100644
index 0000000..75d2605
--- /dev/null
+++ b/src/com/android/internal/utils/du/ImageHelper.java
@@ -0,0 +1,299 @@
+/*
+* Copyright (C) 2013 SlimRoms Project
+* Copyright (C) 2015 TeamEos Project
+* Copyright (C) 2015-2016 The DirtyUnicorns Project
+*
+* 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.internal.utils.du;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader.TileMode;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.util.Xml;
+
+public class ImageHelper {
+ private static final int VECTOR_WIDTH = 512;
+ private static final int VECTOR_HEIGHT = 512;
+
+ public static Drawable getColoredDrawable(Drawable d, int color) {
+ if (d == null) {
+ return null;
+ }
+ if (d instanceof VectorDrawable) {
+ d.setTint(color);
+ return d;
+ }
+ Bitmap colorBitmap = ((BitmapDrawable) d).getBitmap();
+ Bitmap grayscaleBitmap = toGrayscale(colorBitmap);
+ Paint pp = new Paint();
+ pp.setAntiAlias(true);
+ PorterDuffColorFilter frontFilter =
+ new PorterDuffColorFilter(color, Mode.MULTIPLY);
+ pp.setColorFilter(frontFilter);
+ Canvas cc = new Canvas(grayscaleBitmap);
+ final Rect rect = new Rect(0, 0, grayscaleBitmap.getWidth(), grayscaleBitmap.getHeight());
+ cc.drawBitmap(grayscaleBitmap, rect, rect, pp);
+ return new BitmapDrawable(grayscaleBitmap);
+ }
+
+ public static Bitmap drawableToBitmap (Drawable drawable) {
+ if (drawable == null) {
+ return null;
+ } else if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ }
+ Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
+
+ public static Bitmap getColoredBitmap(Drawable d, int color) {
+ if (d == null) {
+ return null;
+ }
+ Bitmap colorBitmap = ((BitmapDrawable) d).getBitmap();
+ Bitmap grayscaleBitmap = toGrayscale(colorBitmap);
+ Paint pp = new Paint();
+ pp.setAntiAlias(true);
+ PorterDuffColorFilter frontFilter =
+ new PorterDuffColorFilter(color, Mode.MULTIPLY);
+ pp.setColorFilter(frontFilter);
+ Canvas cc = new Canvas(grayscaleBitmap);
+ final Rect rect = new Rect(0, 0, grayscaleBitmap.getWidth(), grayscaleBitmap.getHeight());
+ cc.drawBitmap(grayscaleBitmap, rect, rect, pp);
+ return grayscaleBitmap;
+ }
+
+ private static Bitmap toGrayscale(Bitmap bmpOriginal) {
+ int width, height;
+ height = bmpOriginal.getHeight();
+ width = bmpOriginal.getWidth();
+
+ Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(bmpGrayscale);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ ColorMatrix cm = new ColorMatrix();
+ final Rect rect = new Rect(0, 0, width, height);
+ cm.setSaturation(0);
+
+ ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
+ paint.setColorFilter(f);
+ c.drawBitmap(bmpOriginal, rect, rect, paint);
+ return bmpGrayscale;
+ }
+
+ public static Drawable resize(Context context, Drawable image, int size) {
+ if (image == null || context == null) {
+ return null;
+ }
+ if (image instanceof VectorDrawable) {
+ return image;
+ } else {
+ int newSize = DUActionUtils.dpToPx(context, size);
+ Bitmap bitmap = ((BitmapDrawable) image).getBitmap();
+ Bitmap scaledBitmap = Bitmap.createBitmap(newSize, newSize, Config.ARGB_8888);
+
+ float ratioX = newSize / (float) bitmap.getWidth();
+ float ratioY = newSize / (float) bitmap.getHeight();
+ float middleX = newSize / 2.0f;
+ float middleY = newSize / 2.0f;
+
+ final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
+ paint.setAntiAlias(true);
+
+ Matrix scaleMatrix = new Matrix();
+ scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
+
+ Canvas canvas = new Canvas(scaledBitmap);
+ canvas.setMatrix(scaleMatrix);
+ canvas.drawBitmap(bitmap, middleX - bitmap.getWidth() / 2,
+ middleY - bitmap.getHeight() / 2, paint);
+ return new BitmapDrawable(context.getResources(), scaledBitmap);
+ }
+ }
+
+ public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
+ if (bitmap == null) {
+ return null;
+ }
+ Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
+ Config.ARGB_8888);
+ Canvas canvas = new Canvas(output);
+
+ final int color = 0xff424242;
+ final Paint paint = new Paint();
+ final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ final RectF rectF = new RectF(rect);
+ final float roundPx = 24;
+ paint.setAntiAlias(true);
+ canvas.drawARGB(0, 0, 0, 0);
+ paint.setColor(color);
+ canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
+ paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
+ canvas.drawBitmap(bitmap, rect, rect, paint);
+ return output;
+ }
+
+ public static Bitmap getCircleBitmap(Bitmap bitmap) {
+ if (bitmap == null) {
+ return null;
+ }
+ int width = bitmap.getWidth();
+ int height = bitmap.getHeight();
+
+ Bitmap output = Bitmap.createBitmap(width, height,
+ Config.ARGB_8888);
+ Canvas canvas = new Canvas(output);
+
+ BitmapShader shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
+ final Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setShader(shader);
+
+ canvas.drawCircle(width/2, height/2, width/2, paint);
+
+ return output;
+ }
+
+ public static Drawable getVector(Resources res, int resId) {
+ return getVector(res, resId, 0, 0, false);
+ }
+
+ public static Drawable getVector(Resources res, int resId, int width, int height) {
+ return getVector(res, resId, width, height, false);
+ }
+
+ public static Drawable getVector(Resources res, int resId, boolean toBitmapDrawable) {
+ return getVector(res, resId, 0, 0, toBitmapDrawable);
+ }
+
+ public static Drawable getVector(Resources res, int resId, int width, int height,
+ boolean toBitmapDrawable) {
+ if (width <= 0) {
+ width = VECTOR_WIDTH;
+ }
+ if (height <= 0) {
+ width = VECTOR_HEIGHT;
+ }
+
+ VectorDrawable vectorDrawable = new VectorDrawable();
+ vectorDrawable.setBounds(0, 0, width, height);
+ try {
+ XmlPullParser parser = res.getXml(resId);
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty loop
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+// Log.e("ImageHelper VectorLoader", "No start tag found");
+ }
+
+ vectorDrawable.inflate(res, parser, attrs);
+
+ if (!toBitmapDrawable) {
+ return vectorDrawable;
+ }
+
+ return new BitmapDrawable(res, drawableToBitmap(vectorDrawable));
+ } catch (Exception e) {
+// Log.e("ImageHelper VectorLoader", "Error loading resource ID " + String.valueOf(resId) + " Try loading as a non vector");
+ return null;
+ }
+ }
+
+ /**
+ * @param context callers context
+ * @param uri Uri to handle
+ * @return A bitmap from the requested uri
+ * @throws IOException
+ *
+ * @Credit: StackOverflow
+ * http://stackoverflow.com/questions/35909008/pick-image
+ * -from-gallery-or-google-photos-failing
+ */
+ public static Bitmap getBitmapFromUri(Context context, Uri uri) throws IOException {
+ if (context == null || uri == null) {
+ return null;
+ }
+ ParcelFileDescriptor parcelFileDescriptor =
+ context.getContentResolver().openFileDescriptor(uri, "r");
+ FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
+ Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
+ parcelFileDescriptor.close();
+ return image;
+ }
+
+ /**
+ * @param storageDir Desired location in storage as a File
+ * @param fileName Name of bitmap file to store
+ * @param bitmap the bitmap to store
+ * @return the Uri of the bitmap
+ */
+ public static Uri addBitmapToStorage(File storageDir, String fileName, Bitmap bitmap) {
+ if (storageDir == null || fileName == null || bitmap == null) {
+ return null;
+ }
+ File imageFile = new File(storageDir, fileName);
+ try {
+ FileOutputStream fos = new FileOutputStream(imageFile);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
+ fos.flush();
+ fos.close();
+ } catch (Exception e) {
+ return null;
+ }
+ return Uri.fromFile(imageFile);
+ }
+}
diff --git a/src/com/android/internal/utils/du/UserContentObserver.java b/src/com/android/internal/utils/du/UserContentObserver.java
new file mode 100644
index 0000000..6d77b29
--- /dev/null
+++ b/src/com/android/internal/utils/du/UserContentObserver.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * 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.internal.utils.du;
+
+import android.app.ActivityManagerNative;
+import android.app.IUserSwitchObserver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Simple extension of ContentObserver that also listens for user switch events to call update
+ */
+public abstract class UserContentObserver extends ContentObserver {
+ private static final String TAG = "UserContentObserver";
+
+ private Runnable mUpdateRunnable;
+
+ private IUserSwitchObserver mUserSwitchObserver = new IUserSwitchObserver.Stub() {
+ @Override
+ public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ }
+ @Override
+ public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ mHandler.post(mUpdateRunnable);
+ }
+ @Override
+ public void onForegroundProfileSwitch(int newProfileId) {
+ }
+ @Override
+ public void onLockedBootComplete(int val) {
+ }
+ };
+
+ private Handler mHandler;
+
+ public UserContentObserver(Handler handler) {
+ super(handler);
+ mHandler = handler;
+ mUpdateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ update();
+ }
+ };
+ }
+
+ protected void observe() {
+ try {
+ ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchObserver, TAG);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to register user switch observer!", e);
+ }
+ }
+
+ protected void unobserve() {
+ try {
+ mHandler.removeCallbacks(mUpdateRunnable);
+ ActivityManagerNative.getDefault().unregisterUserSwitchObserver(mUserSwitchObserver);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to unregister user switch observer!", e);
+ }
+ }
+
+ protected abstract void update();
+
+ @Override
+ public void onChange(boolean selfChange) {
+ update();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update();
+ }
+}