Cherish:Add some button settings

Hardware key: Customization support[2/2]

Volume Rocker Wake [2/2]

Volume key cursor control (2/2)

Co-authored-by: jhenrique09 <jhsv09@gmail.com>
Co-authored-by: Max <xyyx@mail.ru>
Co-authored-by: bigrushdog <randall.rushing@gmail.com>
Signed-off-by: Hưng Phan <phandinhhungvp2001@gmail.com>
This commit is contained in:
Hưng Phan
2022-09-05 23:10:11 +07:00
parent b6c4c176e5
commit 135aefde28
13 changed files with 1671 additions and 83 deletions

View File

@@ -18,44 +18,76 @@
package com.cherish.settings.fragments;
import android.content.ContentResolver;
import android.content.res.Resources;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.Vibrator;
import androidx.preference.PreferenceCategory;
import android.provider.Settings;
import android.view.View;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.SwitchPreference;
import android.provider.Settings;
import com.android.internal.lineage.hardware.LineageHardwareManager;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.cherish.CherishUtils;
import com.android.internal.util.hwkeys.ActionConstants;
import com.android.internal.util.hwkeys.ActionUtils;
import com.android.settings.R;
import com.cherish.settings.preferences.SystemSettingSwitchPreference;
import com.cherish.settings.preferences.SecureSettingSwitchPreference;
import com.android.internal.logging.nano.MetricsProto;
import com.cherish.settings.preferences.CustomSeekBarPreference;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.SearchIndexable;
import android.provider.SearchIndexableResource;
import com.cherish.settings.preferences.ActionFragment;
import com.cherish.settings.preferences.SecureSettingSwitchPreference;
import com.cherish.settings.preferences.SystemSettingSwitchPreference;
import java.util.ArrayList;
import java.util.List;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ButtonSettings extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener {
private static final String KEY_NAVBAR_INVERSE = "navigation_bar_inverse";
private static final String KEY_NAVIGATION_COMPACT_LAYOUT = "navigation_bar_compact_layout";
private SystemSettingSwitchPreference mNavbarInverse;
private SystemSettingSwitchPreference mNavigationCompactLayout;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ButtonSettings extends ActionFragment implements
Preference.OnPreferenceChangeListener {
private static final String HWKEY_DISABLE = "hardware_keys_disable";
private static final String KEY_NAVBAR_INVERSE = "navigation_bar_inverse";
private static final String KEY_NAVIGATION_COMPACT_LAYOUT = "navigation_bar_compact_layout";
private static final String KEY_SWAP_CAPACITIVE_KEYS = "swap_capacitive_keys";
// category keys
private static final String CATEGORY_HWKEY = "hardware_keys";
private static final String CATEGORY_BACK = "back_key";
private static final String CATEGORY_HOME = "home_key";
private static final String CATEGORY_MENU = "menu_key";
private static final String CATEGORY_ASSIST = "assist_key";
private static final String CATEGORY_APPSWITCH = "app_switch_key";
private static final String CATEGORY_VOLUME = "volume_keys";
private static final String CATEGORY_POWER = "power_key";
// Masks for checking presence of hardware keys.
// Must match values in frameworks/base/core/res/res/values/config.xml
public static final int KEY_MASK_HOME = 0x01;
public static final int KEY_MASK_BACK = 0x02;
public static final int KEY_MASK_MENU = 0x04;
public static final int KEY_MASK_ASSIST = 0x08;
public static final int KEY_MASK_APP_SWITCH = 0x10;
public static final int KEY_MASK_CAMERA = 0x20;
public static final int KEY_MASK_VOLUME = 0x40;
private PreferenceCategory mButtonBackLightCategory;
private PreferenceCategory mHwKeyCategory;
private SecureSettingSwitchPreference mSwapCapacitiveKeys;
private SwitchPreference mHwKeyDisable;
private SystemSettingSwitchPreference mNavbarInverse;
private SystemSettingSwitchPreference mNavigationCompactLayout;
@Override
public void onCreate(Bundle icicle) {
@@ -65,47 +97,133 @@ public class ButtonSettings extends SettingsPreferenceFragment implements
final Resources res = getResources();
final ContentResolver resolver = getActivity().getContentResolver();
final PreferenceScreen prefScreen = getPreferenceScreen();
final boolean isThreeButtonNavbarEnabled = EvolutionUtils.isThemeEnabled("com.android.internal.systemui.navbar.threebutton");
mSwapCapacitiveKeys = findPreference(KEY_SWAP_CAPACITIVE_KEYS);
if (mSwapCapacitiveKeys != null && !isKeySwapperSupported(getActivity())) {
prefScreen.removePreference(mSwapCapacitiveKeys);
mSwapCapacitiveKeys = null;
}
final boolean needsNavbar = ActionUtils.hasNavbarByDefault(getActivity());
mHwKeyCategory = (PreferenceCategory) prefScreen
.findPreference(CATEGORY_HWKEY);
int keysDisabled = 0;
if (!needsNavbar) {
mHwKeyDisable = (SwitchPreference) findPreference(HWKEY_DISABLE);
keysDisabled = Settings.System.getIntForUser(getContentResolver(),
Settings.System.HARDWARE_KEYS_DISABLE, 0,
UserHandle.USER_CURRENT);
mHwKeyDisable.setChecked(keysDisabled != 0);
mHwKeyDisable.setOnPreferenceChangeListener(this);
} else {
prefScreen.removePreference(mHwKeyCategory);
}
// bits for hardware keys present on device
final int deviceKeys = getResources().getInteger(
com.android.internal.R.integer.config_deviceHardwareKeys);
// read bits for present hardware keys
final boolean hasHomeKey = (deviceKeys & KEY_MASK_HOME) != 0;
final boolean hasBackKey = (deviceKeys & KEY_MASK_BACK) != 0;
final boolean hasMenuKey = (deviceKeys & KEY_MASK_MENU) != 0;
final boolean hasAssistKey = (deviceKeys & KEY_MASK_ASSIST) != 0;
final boolean hasAppSwitchKey = (deviceKeys & KEY_MASK_APP_SWITCH) != 0;
// load categories and init/remove preferences based on device
// configuration
final PreferenceCategory backCategory = (PreferenceCategory) prefScreen
.findPreference(CATEGORY_BACK);
final PreferenceCategory homeCategory = (PreferenceCategory) prefScreen
.findPreference(CATEGORY_HOME);
final PreferenceCategory menuCategory = (PreferenceCategory) prefScreen
.findPreference(CATEGORY_MENU);
final PreferenceCategory assistCategory = (PreferenceCategory) prefScreen
.findPreference(CATEGORY_ASSIST);
final PreferenceCategory appSwitchCategory = (PreferenceCategory) prefScreen
.findPreference(CATEGORY_APPSWITCH);
// back key
if (!hasBackKey) {
prefScreen.removePreference(backCategory);
}
// home key
if (!hasHomeKey) {
prefScreen.removePreference(homeCategory);
}
// App switch key (recents)
if (!hasAppSwitchKey) {
prefScreen.removePreference(appSwitchCategory);
}
// menu key
if (!hasMenuKey) {
prefScreen.removePreference(menuCategory);
}
// search/assist key
if (!hasAssistKey) {
prefScreen.removePreference(assistCategory);
}
// let super know we can load ActionPreferences
onPreferenceScreenLoaded(ActionConstants.getDefaults(ActionConstants.HWKEYS));
// load preferences first
setActionPreferencesEnabled(keysDisabled == 0);
final boolean isThreeButtonNavbarEnabled = CherishUtils.isThemeEnabled("com.android.internal.systemui.navbar.threebutton");
mNavbarInverse = (SystemSettingSwitchPreference) findPreference(KEY_NAVBAR_INVERSE);
mNavbarInverse.setEnabled(isThreeButtonNavbarEnabled);
mNavigationCompactLayout = (SystemSettingSwitchPreference) findPreference(KEY_NAVIGATION_COMPACT_LAYOUT);
mNavigationCompactLayout.setEnabled(isThreeButtonNavbarEnabled);
}
private static boolean isKeyDisablerSupported(Context context) {
final LineageHardwareManager hardware = LineageHardwareManager.getInstance(context);
return hardware.isSupported(LineageHardwareManager.FEATURE_KEY_DISABLE);
}
private static boolean isKeySwapperSupported(Context context) {
final LineageHardwareManager hardware = LineageHardwareManager.getInstance(context);
return hardware.isSupported(LineageHardwareManager.FEATURE_KEY_SWAP);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
ContentResolver resolver = getActivity().getContentResolver();
if (preference == mHwKeyDisable) {
boolean value = (Boolean) newValue;
Settings.System.putInt(getContentResolver(), Settings.System.HARDWARE_KEYS_DISABLE,
value ? 1 : 0);
setActionPreferencesEnabled(!value);
return true;
}
return false;
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.CHERISH_SETTINGS;
return MetricsEvent.CHERISH_SETTINGS;
}
/**
/**
* For Search.
*/
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
boolean enabled) {
ArrayList<SearchIndexableResource> result =
new ArrayList<SearchIndexableResource>();
SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.cherish_settings_button;
result.add(sir);
return result;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.cherish_settings_button) {
@Override
public List<String> getNonIndexableKeys(Context context) {
List<String> keys = super.getNonIndexableKeys(context);
LineageHardwareManager mLineageHardware = LineageHardwareManager.getInstance(context);
if (!isKeyDisablerSupported(context)) {
keys.add(HWKEY_DISABLE);
keys.add(CATEGORY_HWKEY);
keys.add(CATEGORY_BACK);
keys.add(CATEGORY_HOME);
keys.add(CATEGORY_MENU);
keys.add(CATEGORY_ASSIST);
keys.add(CATEGORY_APPSWITCH);
}
return keys;
}
};
}
};
}

View File

@@ -1,67 +1,194 @@
package com.cherish.settings.fragments;
import com.android.internal.logging.nano.MetricsProto;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import android.preference.SwitchPreference;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceFragment;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settingslib.search.SearchIndexable;
import android.provider.SearchIndexableResource;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class VolumeRockerSettings extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
private static final String TAG = "VolumeSteps";
private static final String VOLUME_STEP_DEFAULTS = "volume_step_defaults";
private static final String FIRST_RUN_KEY = "first_run";
// base map of all preference keys and the associated stream
private static final Map<String, Integer> volume_map = new HashMap<String, Integer>();
static {
volume_map.put("volume_steps_alarm", new Integer(AudioManager.STREAM_ALARM));
volume_map.put("volume_steps_dtmf", new Integer(AudioManager.STREAM_DTMF));
volume_map.put("volume_steps_music", new Integer(AudioManager.STREAM_MUSIC));
volume_map.put("volume_steps_notification", new Integer(AudioManager.STREAM_NOTIFICATION));
volume_map.put("volume_steps_ring", new Integer(AudioManager.STREAM_RING));
volume_map.put("volume_steps_system", new Integer(AudioManager.STREAM_SYSTEM));
volume_map.put("volume_steps_voice_call", new Integer(AudioManager.STREAM_VOICE_CALL));
}
// entries to remove on non-telephony devices
private static final Set<String> telephony_set = new HashSet<String>();
static {
telephony_set.add("volume_steps_dtmf");
telephony_set.add("volume_steps_ring");
telephony_set.add("volume_steps_voice_call");
}
// set of available pref keys after device configuration filter
private Set<String> mAvailableKeys = new HashSet<String>();
private AudioManager mAudioManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.cherish_settings_volume);
mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
final PreferenceScreen prefScreen = getPreferenceScreen();
mAvailableKeys = volume_map.keySet();
// remove invalid audio stream prefs
boolean isPhone = TelephonyManager.getDefault().getCurrentPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
if (!isPhone) {
// remove telephony keys from available set
mAvailableKeys.removeAll(telephony_set);
for (String key : telephony_set) {
Preference toRemove = prefScreen.findPreference(key);
if (toRemove != null) {
prefScreen.removePreference(toRemove);
}
}
}
// check prefs for initial run of this fragment
final boolean firstRun = checkForFirstRun();
// entries array isn't translatable ugh
final String defEntry = getString(R.string.volume_steps_reset);
// initialize prefs: set defaults if first run, set listeners and update values
for (String key : mAvailableKeys) {
Preference pref = prefScreen.findPreference(key);
if (pref == null || !(pref instanceof ListPreference)) {
continue;
}
final ListPreference listPref = (ListPreference) pref;
int steps = mAudioManager.getStreamMaxVolume(volume_map.get(key));
if (firstRun) {
saveDefaultSteps(listPref, steps);
}
final int defSteps = getDefaultSteps(listPref);
CharSequence[] entries = new CharSequence[listPref.getEntries().length + 1];
CharSequence[] values = new CharSequence[listPref.getEntryValues().length + 1];
for (int i = 0; i < entries.length; i++) {
if (i == 0) {
entries[i] = defEntry;
values[i] = String.valueOf(defSteps);
continue;
}
entries[i] = listPref.getEntries()[i - 1];
values[i] = listPref.getEntryValues()[i - 1];
}
listPref.setEntries(entries);
listPref.setEntryValues(values);
updateVolumeStepPrefs(listPref, steps);
listPref.setOnPreferenceChangeListener(this);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
public boolean onPreferenceChange(Preference preference, Object objValue) {
if (preference.hasKey() && mAvailableKeys.contains(preference.getKey())) {
commitVolumeSteps(preference, Integer.parseInt(objValue.toString()));
}
return true;
}
private SharedPreferences getDefaultStepsPrefs() {
return getActivity().getSharedPreferences(VOLUME_STEP_DEFAULTS,
Context.MODE_PRIVATE);
}
// test for initial run of this fragment
private boolean checkForFirstRun() {
String isFirstRun = getDefaultStepsPrefs().getString(FIRST_RUN_KEY, null);
if (isFirstRun == null) {
getDefaultStepsPrefs().edit().putString(FIRST_RUN_KEY, "first_run_initialized").commit();
return true;
}
return false;
}
private int getDefaultSteps(Preference pref) {
if (pref == null || !(pref instanceof ListPreference)) {
// unlikely
return -1;
}
String key = pref.getKey();
String value = getDefaultStepsPrefs().getString(key, null);
if (value == null) {
// unlikely
return -1;
}
return Integer.parseInt(value);
}
// on the initial run, let's store true device defaults in sharedPrefs
private void saveDefaultSteps(Preference volPref, int defaultSteps) {
String key = volPref.getKey();
getDefaultStepsPrefs().edit().putString(key, String.valueOf(defaultSteps)).commit();
}
private void updateVolumeStepPrefs(Preference pref, int steps) {
if (pref == null || !(pref instanceof ListPreference)) {
return;
}
final ListPreference listPref = (ListPreference) pref;
listPref.setSummary(String.valueOf(steps));
listPref.setValue(String.valueOf(steps));
}
private void commitVolumeSteps(Preference pref, int steps) {
Settings.System.putInt(getActivity().getContentResolver(), pref.getKey(), steps);
mAudioManager.setStreamMaxVolume(volume_map.get(pref.getKey()), steps);
updateVolumeStepPrefs(pref, steps);
Log.i(TAG, "Volume steps:" + pref.getKey() + "" + String.valueOf(steps));
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.CHERISH_SETTINGS;
return MetricsEvent.CHERISH_SETTINGS;
}
/**
/**
* For Search.
*/
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
boolean enabled) {
ArrayList<SearchIndexableResource> result =
new ArrayList<SearchIndexableResource>();
SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.cherish_settings_volume;
result.add(sir);
return result;
}
@Override
public List<String> getNonIndexableKeys(Context context) {
List<String> keys = super.getNonIndexableKeys(context);
return keys;
}
};
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.cherish_settings_volume);
}

View File

@@ -0,0 +1,261 @@
/*
* Copyright (C) 2015 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.
*
* Handle assignable action dialogs and instances of the ActionPreference
* class that holds target widget state
*/
package com.cherish.settings.preferences;
import java.util.ArrayList;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.util.hwkeys.ActionConstants.Defaults;
import com.android.internal.util.hwkeys.ActionHandler;
import com.android.internal.util.hwkeys.Config;
import com.android.internal.util.hwkeys.Config.ActionConfig;
import com.android.internal.util.hwkeys.Config.ButtonConfig;
import com.cherish.settings.preferences.ShortcutPickHelper;
import com.cherish.settings.preferences.ActionPreference;
import com.cherish.settings.preferences.CustomActionListAdapter;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
public class ActionFragment extends SettingsPreferenceFragment implements
ShortcutPickHelper.OnPickListener {
private static final int DIALOG_CATEGORY = 69;
private static final int DIALOG_CUSTOM_ACTIONS = 70;
private static final String KEY_FOCUSED_PREFERENCE = "key_focused_preference";
private ShortcutPickHelper mPicker;
protected ArrayList<ActionPreference> mPrefHolder;
private String mHolderTag;
private Defaults mDefaults;
private ArrayList<ButtonConfig> mButtons;
private ArrayList<ButtonConfig> mDefaultButtons;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
if (icicle != null) {
String holderTag = icicle.getString(KEY_FOCUSED_PREFERENCE);
if (holderTag != null) {
mHolderTag = holderTag;
}
}
mPicker = new ShortcutPickHelper(getActivity(), this);
mPrefHolder = new ArrayList<ActionPreference>();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
mPicker.onActivityResult(requestCode, resultCode, data);
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void shortcutPicked(String uri, String friendlyName, boolean isApplication) {
// activity dialogs pass null here if they are dismissed
// if null, do nothing, no harm
if (uri == null) {
return;
}
findAndUpdatePreference(new ActionConfig(getActivity(), uri), mHolderTag);
}
@Override
public boolean onPreferenceTreeClick(Preference preference) {
if (preference instanceof ActionPreference) {
mHolderTag = ((ActionPreference)preference).getTag();
showDialog(DIALOG_CATEGORY);
return true;
}
return super.onPreferenceTreeClick(preference);
}
@Override
public void onStart() {
super.onStart();
if (mDefaults != null) {
loadAndSetConfigs();
onActionPolicyEnforced(mPrefHolder);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mHolderTag != null) {
outState.putString(KEY_FOCUSED_PREFERENCE, mHolderTag);
}
}
@Override
public Dialog onCreateDialog(int dialogId) {
switch (dialogId) {
case DIALOG_CATEGORY: {
Dialog dialog;
final DialogInterface.OnClickListener categoryClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
onTargetChange(getResources().getStringArray(R.array.action_dialog_values)[item]);
dialog.dismiss();
}
};
dialog = new AlertDialog.Builder(getActivity())
.setTitle(R.string.choose_action_title)
.setItems(getResources().getStringArray(R.array.action_dialog_entries),
categoryClickListener)
.setNegativeButton(getString(android.R.string.cancel), null)
.create();
return dialog;
}
case DIALOG_CUSTOM_ACTIONS: {
Dialog dialog;
final CustomActionListAdapter adapter = new CustomActionListAdapter(getActivity());
if (!usesExtendedActionsList()) {
adapter.removeAction(ActionHandler.SYSTEMUI_TASK_HOME);
adapter.removeAction(ActionHandler.SYSTEMUI_TASK_BACK);
}
final DialogInterface.OnClickListener customActionClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
findAndUpdatePreference(adapter.getItem(item), mHolderTag);
dialog.dismiss();
}
};
dialog = new AlertDialog.Builder(getActivity())
.setTitle(getString(R.string.action_entry_custom_action))
.setAdapter(adapter, customActionClickListener)
.setNegativeButton(getString(android.R.string.cancel), null)
.create();
return dialog;
}
}
return super.onCreateDialog(dialogId);
}
@Override
public int getDialogMetricsCategory(int dialogId) {
switch (dialogId) {
case DIALOG_CATEGORY:
case DIALOG_CUSTOM_ACTIONS:
return MetricsEvent.CHERISH_SETTINGS;
default:
return 0;
}
}
// subclass overrides to include back and home actions
protected boolean usesExtendedActionsList() {
return false;
}
protected void onActionPolicyEnforced(ArrayList<ActionPreference> prefs) {
}
protected void setActionPreferencesEnabled(boolean enabled) {
for (ActionPreference pref : mPrefHolder) {
pref.setEnabled(enabled);
}
}
/**
* load our button lists and ActionPreferences map button action targets from preference keys
* and defaults config maps subclass is required to set desired Defaults interface int
* ActionContants
*/
protected void onPreferenceScreenLoaded(Defaults defaults) {
mDefaults = defaults;
final PreferenceScreen prefScreen = getPreferenceScreen();
for (int i = 0; i < prefScreen.getPreferenceCount(); i++) {
Preference pref = prefScreen.getPreference(i);
if (pref instanceof PreferenceCategory) {
PreferenceCategory cat = (PreferenceCategory) pref;
for (int j = 0; j < cat.getPreferenceCount(); j++) {
Preference child = cat.getPreference(j);
if (child instanceof ActionPreference) {
mPrefHolder.add((ActionPreference) child);
}
}
} else if (pref instanceof ActionPreference) {
mPrefHolder.add((ActionPreference) pref);
}
}
loadAndSetConfigs();
}
protected void loadAndSetConfigs() {
mButtons = Config.getConfig(getActivity(), mDefaults);
mDefaultButtons = Config.getDefaultConfig(getActivity(), mDefaults);
for (ActionPreference pref : mPrefHolder) {
pref.setDefaults(mDefaults);
ButtonConfig button = mButtons.get(pref.getConfigMap().button);
ActionConfig action = button.getActionConfig(pref.getConfigMap().action);
pref.setActionConfig(action);
ButtonConfig defButton = mDefaultButtons.get(pref.getConfigMap().button);
ActionConfig defAction = defButton.getActionConfig(pref.getConfigMap().action);
pref.setDefaultActionConfig(defAction);
}
}
private void onTargetChange(String uri) {
if (uri == null) {
return;
} else if (uri.equals(getString(R.string.action_value_default_action))) {
findAndUpdatePreference(null, mHolderTag);
} else if (uri.equals(getString(R.string.action_value_select_app))) {
mPicker.pickShortcut(null, null, getId());
} else if (uri.equals(getString(R.string.action_value_custom_action))) {
showDialog(DIALOG_CUSTOM_ACTIONS);
}
}
protected void findAndUpdatePreference(ActionConfig action, String tag) {
for (ActionPreference pref : mPrefHolder) {
if (pref.getTag().equals(mHolderTag)) {
if (action == null) {
action = pref.getDefaultActionConfig();
}
pref.setActionConfig(action);
ButtonConfig button = mButtons.get(pref.getConfigMap().button);
ActionConfig newAction = pref.getActionConfig();
button.setActionConfig(newAction, pref.getConfigMap().action);
mButtons = Config.replaceButtonAtPosition(mButtons, button, pref.getConfigMap());
Config.setConfig(getActivity(), mDefaults, mButtons);
onActionPolicyEnforced(mPrefHolder);
break;
}
}
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.CHERISH_SETTINGS;
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2015 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.
*
* Simple preference class implementing ActionHolder interface to assign
* actions to buttons. It is ABSOLUTELY IMPERITIVE that the preference
* key is identical to the target ConfigMap tag in ActionConstants
*/
package com.cherish.settings.preferences;
import java.util.Map;
import com.android.internal.util.hwkeys.ActionConstants.ConfigMap;
import com.android.internal.util.hwkeys.ActionConstants.Defaults;
import com.android.internal.util.hwkeys.ActionHolder;
import com.android.internal.util.hwkeys.Config.ActionConfig;
import com.android.internal.util.hwkeys.Config.ButtonConfig;
import android.content.Context;
import androidx.preference.Preference;
import android.util.AttributeSet;
public class ActionPreference extends Preference implements ActionHolder {
private Defaults mDefaults;
private ConfigMap mMap;
private ActionConfig mAction;
private ActionConfig mDefaultAction;
public ActionPreference(Context context) {
this(context, null);
}
public ActionPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ActionPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public ActionPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs);
}
@Override
public String getTag() {
return this.getKey();
}
@Override
public void setTag(String tag) {
this.setKey(tag);
}
@Override
public Defaults getDefaults() {
return mDefaults;
}
@Override
public void setDefaults(Defaults defaults) {
mDefaults = defaults;
final String tag = this.getKey();
for (Map.Entry<String, ConfigMap> entry : defaults.getActionMap().entrySet()) {
if (((String) entry.getKey()).equals(tag)) {
mMap = entry.getValue();
break;
}
}
}
@Override
public ConfigMap getConfigMap() {
return mMap;
}
@Override
public void setConfigMap(ConfigMap map) {
mMap = map;
}
@Override
public ButtonConfig getButtonConfig() {
return null;
}
@Override
public void setButtonConfig(ButtonConfig button) {
}
@Override
public ActionConfig getActionConfig() {
return mAction;
}
@Override
public void setActionConfig(ActionConfig action) {
mAction = action;
this.setSummary(action.getLabel());
}
@Override
public ButtonConfig getDefaultButtonConfig() {
return null;
}
@Override
public void setDefaultButtonConfig(ButtonConfig button) {
}
@Override
public ActionConfig getDefaultActionConfig() {
return mDefaultAction;
}
@Override
public void setDefaultActionConfig(ActionConfig action) {
mDefaultAction = action;
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2015 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.
*
* Adapter for displaying custom actions in a list
*/
package com.cherish.settings.preferences;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.util.hwkeys.ActionHandler;
import com.android.internal.util.hwkeys.Config.ActionConfig;
import com.android.settings.R;
public class CustomActionListAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private Context mContext;
private List<ActionConfig> mCustomActions = new ArrayList<ActionConfig>();
public CustomActionListAdapter(Context context) {
mContext = context;
mInflater = LayoutInflater.from(context);
reloadActions();
}
private void reloadActions() {
mCustomActions.clear();
mCustomActions.addAll(ActionHandler.getSystemActions(mContext));
notifyDataSetChanged();
}
public void removeAction(String action) {
int index = -1;
for (int i = 0; i < mCustomActions.size(); i++) {
if (TextUtils.equals(mCustomActions.get(i).getAction(), action)) {
index = i;
break;
}
}
if (index > -1) {
mCustomActions.remove(index);
notifyDataSetChanged();
}
}
@Override
public int getCount() {
return mCustomActions.size();
}
@Override
public ActionConfig getItem(int position) {
return mCustomActions.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
final Context ctx = mContext;
if (convertView != null) {
holder = (ViewHolder) convertView.getTag();
} else {
convertView = mInflater.inflate(R.layout.custom_action_item, null, false);
holder = new ViewHolder();
convertView.setTag(holder);
holder.title = (TextView) convertView.findViewById(com.android.internal.R.id.title);
holder.summary = (TextView) convertView
.findViewById(com.android.internal.R.id.summary);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams();
params.width = holder.icon.getMaxWidth();
params.height = holder.icon.getMaxHeight();
holder.icon.setLayoutParams(params);
holder.icon.setScaleType(ScaleType.CENTER);
holder.icon.setCropToPadding(true);
}
ActionConfig config = getItem(position);
holder.title.setText(config.getLabel());
holder.icon.setBackgroundResource(R.drawable.fab_accent);
holder.icon.setImageDrawable(config.getDefaultIcon(ctx));
holder.summary.setVisibility(View.GONE);
return convertView;
}
private static class ViewHolder {
TextView title;
TextView summary;
ImageView icon;
}
}

View File

@@ -0,0 +1,327 @@
/*
* Copyright (C) 2011 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.cherish.settings.preferences;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
import com.android.settings.R;
import com.cherish.settings.preferences.ShortcutPickHelper.AppExpandableAdapter.GroupInfo;
public class ShortcutPickHelper {
private FragmentActivity mParent;
private AlertDialog mAlertDialog;
private OnPickListener mListener;
private PackageManager mPackageManager;
private static final int REQUEST_PICK_SHORTCUT = 100;
private static final int REQUEST_PICK_APPLICATION = 101;
private static final int REQUEST_CREATE_SHORTCUT = 102;
private int lastFragmentId;
public interface OnPickListener {
void shortcutPicked(String uri, String friendlyName, boolean isApplication);
}
public ShortcutPickHelper(FragmentActivity parent, OnPickListener listener) {
mParent = parent;
mPackageManager = mParent.getPackageManager();
mListener = listener;
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == FragmentActivity.RESULT_OK) {
switch (requestCode) {
case REQUEST_PICK_APPLICATION:
completeSetCustomApp(data);
break;
case REQUEST_CREATE_SHORTCUT:
completeSetCustomShortcut(data);
break;
case REQUEST_PICK_SHORTCUT:
processShortcut(data, REQUEST_PICK_APPLICATION, REQUEST_CREATE_SHORTCUT);
break;
}
}
}
public void pickShortcut(String[] names, ShortcutIconResource[] icons, int fragmentId) {
Bundle bundle = new Bundle();
ArrayList<String> shortcutNames = new ArrayList<String>();
if (names != null) {
for (String s : names) {
shortcutNames.add(s);
}
}
shortcutNames.add(mParent.getString(R.string.profile_applist_title));
shortcutNames.add(mParent.getString(R.string.picker_activities));
bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
ArrayList<ShortcutIconResource> shortcutIcons = new ArrayList<ShortcutIconResource>();
if (icons != null) {
for (ShortcutIconResource s : icons) {
shortcutIcons.add(s);
}
}
shortcutIcons.add(ShortcutIconResource.fromContext(mParent, android.R.drawable.sym_def_app_icon));
shortcutIcons.add(ShortcutIconResource.fromContext(mParent, R.drawable.activities_icon));
bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT));
pickIntent.putExtra(Intent.EXTRA_TITLE, mParent.getText(R.string.select_custom_app_title));
pickIntent.putExtras(bundle);
lastFragmentId = fragmentId;
startFragmentOrActivity(pickIntent, REQUEST_PICK_SHORTCUT);
}
private void startFragmentOrActivity(Intent pickIntent, int requestCode) {
if (lastFragmentId == 0) {
mParent.startActivityForResult(pickIntent, requestCode);
} else {
Fragment cFrag = mParent.getSupportFragmentManager().findFragmentById(lastFragmentId);
if (cFrag != null) {
mParent.startActivityFromFragment(cFrag, pickIntent, requestCode);
}
}
}
private void processShortcut(final Intent intent, int requestCodeApplication, int requestCodeShortcut) {
// Handle case where user selected "Applications"
String applicationName = mParent.getString(R.string.profile_applist_title);
String application2name = mParent.getString(R.string.picker_activities);
String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
if (applicationName != null && applicationName.equals(shortcutName)) {
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
startFragmentOrActivity(pickIntent, requestCodeApplication);
} else if (application2name != null && application2name.equals(shortcutName)){
final List<PackageInfo> pInfos = mPackageManager.getInstalledPackages(PackageManager.GET_ACTIVITIES);
ExpandableListView appListView = new ExpandableListView(mParent);
AppExpandableAdapter appAdapter = new AppExpandableAdapter(pInfos, mParent);
appListView.setAdapter(appAdapter);
appListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
Intent shortIntent = new Intent(Intent.ACTION_MAIN);
String pkgName = ((GroupInfo)parent.getExpandableListAdapter().getGroup(groupPosition))
.info.packageName;
String actName = ((GroupInfo)parent.getExpandableListAdapter().getGroup(groupPosition))
.info.activities[childPosition].name;
shortIntent.setClassName(pkgName, actName);
completeSetCustomApp(shortIntent);
mAlertDialog.dismiss();
return true;
}
});
Builder builder = new Builder(mParent);
builder.setView(appListView);
mAlertDialog = builder.create();
mAlertDialog.setTitle(mParent.getString(R.string.select_custom_activity_title));
mAlertDialog.show();
mAlertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
mListener.shortcutPicked(null, null, false);
}
});
} else {
startFragmentOrActivity(intent, requestCodeShortcut);
}
}
public class AppExpandableAdapter extends BaseExpandableListAdapter {
ArrayList<GroupInfo> allList = new ArrayList<GroupInfo>();
final int groupPadding;
public class LabelCompare implements Comparator<GroupInfo>{
@Override
public int compare(GroupInfo item1, GroupInfo item2) {
String rank1 = item1.label.toLowerCase();
String rank2 = item2.label.toLowerCase();
int result = rank1.compareTo(rank2);
if(result == 0) {
return 0;
} else if(result < 0) {
return -1;
} else {
return +1;
}
}
}
class GroupInfo {
String label;
PackageInfo info;
GroupInfo (String l, PackageInfo p) {
label = l;
info = p;
}
}
public AppExpandableAdapter(List<PackageInfo> pInfos, Context context) {
for (PackageInfo i : pInfos) {
allList.add(new GroupInfo(i.applicationInfo.loadLabel(mPackageManager).toString(), i));
}
Collections.sort(allList, new LabelCompare());
groupPadding = context.getResources().getDimensionPixelSize(R.dimen.shortcut_picker_left_padding);
}
public String getChild(int groupPosition, int childPosition) {
return allList.get(groupPosition).info.activities[childPosition].name;
}
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
public int getChildrenCount(int groupPosition) {
if (allList.get(groupPosition).info.activities != null) {
return allList.get(groupPosition).info.activities.length;
} else {
return 0;
}
}
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(mParent, android.R.layout.simple_list_item_1, null);
convertView.setPadding(groupPadding, 0, 0, 0);
}
TextView textView = (TextView)convertView.findViewById(android.R.id.text1);
textView.setText(getChild(groupPosition, childPosition).replaceFirst(allList.get(groupPosition).info.packageName + ".", ""));
return convertView;
}
public GroupInfo getGroup(int groupPosition) {
return allList.get(groupPosition);
}
public int getGroupCount() {
return allList.size();
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(mParent, android.R.layout.simple_list_item_1, null);
convertView.setPadding(70, 0, 0, 0);
}
TextView textView = (TextView)convertView.findViewById(android.R.id.text1);
textView.setText(getGroup(groupPosition).label.toString());
return convertView;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
public boolean hasStableIds() {
return true;
}
}
private void completeSetCustomApp(Intent data) {
mListener.shortcutPicked(data.toUri(0), getFriendlyActivityName(data, false), true);
}
private void completeSetCustomShortcut(Intent data) {
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
if (intent == null) return;
// preserve shortcut name, we want to restore it later
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
// standardize the uri scheme to be sure we can launch it
// TODO: add compatibility for apps that use ACTION_CONFIRM_PIN_SHORTCUT (drag widget on the home screen)
String appUri = intent.toUri(Intent.URI_INTENT_SCHEME);
appUri = appUri.replaceAll("com.android.contacts.action.QUICK_CONTACT", "android.intent.action.VIEW");
mListener.shortcutPicked(appUri, getFriendlyShortcutName(intent), false);
}
private String getFriendlyActivityName(Intent intent, boolean labelOnly) {
ActivityInfo ai = intent.resolveActivityInfo(mPackageManager, PackageManager.GET_ACTIVITIES);
String friendlyName = null;
if (ai != null) {
friendlyName = ai.loadLabel(mPackageManager).toString();
if (friendlyName == null && !labelOnly) {
friendlyName = ai.name;
}
}
return friendlyName != null || labelOnly ? friendlyName : intent.toUri(0);
}
private String getFriendlyShortcutName(Intent intent) {
String activityName = getFriendlyActivityName(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 String getFriendlyNameForUri(String uri) {
if (uri == null) {
return null;
}
try {
Intent intent = Intent.parseUri(uri, 0);
if (Intent.ACTION_MAIN.equals(intent.getAction())) {
return getFriendlyActivityName(intent, false);
}
return getFriendlyShortcutName(intent);
} catch (URISyntaxException e) {
}
return uri;
}
}