Cherish:HW Keys customization support [1/2]
Based on DUI jhenrique09 edits: make it DUI independent Original commit message: Same robust action library as used on software navigation. Supports single tap, double tap, and long press. As a precautionary measure, single tap back and single tap home are fixed and can not be changed. Camera button actions are not supported at this time. We will bring in wake key support at a later time. Also includes: DUI: Initial checkin for Oreo [4/7] Signed-off-by: Hưng Phan <phandinhhungvp2001@gmail.com>
This commit is contained in:
261
src/com/cherish/settings/preferences/ActionFragment.java
Normal file
261
src/com/cherish/settings/preferences/ActionFragment.java
Normal 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;
|
||||
}
|
||||
}
|
||||
134
src/com/cherish/settings/preferences/ActionPreference.java
Normal file
134
src/com/cherish/settings/preferences/ActionPreference.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
327
src/com/cherish/settings/preferences/ShortcutPickHelper.java
Normal file
327
src/com/cherish/settings/preferences/ShortcutPickHelper.java
Normal 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.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.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 Activity 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(Activity parent, OnPickListener listener) {
|
||||
mParent = parent;
|
||||
mPackageManager = mParent.getPackageManager();
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (resultCode == Activity.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.getFragmentManager().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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user