Refactor AppPicker page to adopt Settings main theme

AppPicker in Development options has been existed since 2012 without
too much maintanace. This CL mainly adopt Settings main theme into it,
and migrate from depreaced ListActvity to androidx while reamining restraint.

Bug: 277978841
Preview: https://docs.google.com/spreadsheets/d/1vwzriR1mZj2B2Flw1eu1OwfZY5wRz6YOaq7bDcXxStE
Test: manual, presubmit
Change-Id: I8bf3be499202eba894070cffd5f20f44d3d45de5
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
This commit is contained in:
Shen Lin
2023-04-13 14:32:23 +08:00
committed by Joey
parent 5925ca9b76
commit 48b7e3f855
2 changed files with 184 additions and 130 deletions

View File

@@ -3330,8 +3330,14 @@
android:value="@string/menu_key_connected_devices"/>
</activity>
<activity android:name=".development.AppPicker"
android:label="@string/select_application" />
<activity
android:name=".development.AppPicker"
android:label="@string/select_application">
<meta-data
android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.development.AppPicker$AppPickerListFragment" />
</activity>
<activity android:name=".development.AdbQrCodeActivity" />

View File

@@ -16,8 +16,6 @@
package com.android.settings.development;
import android.app.ActionBar;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -33,15 +31,19 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.ListFragment;
import com.android.settings.SettingsActivity;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class AppPicker extends ListActivity {
private AppListAdapter mAdapter;
public class AppPicker extends SettingsActivity {
public static final String EXTRA_REQUESTIING_PERMISSION
= "com.android.settings.extra.REQUESTIING_PERMISSION";
public static final String EXTRA_DEBUGGABLE = "com.android.settings.extra.DEBUGGABLE";
@@ -50,32 +52,20 @@ public class AppPicker extends ListActivity {
public static final int RESULT_NO_MATCHING_APPS = -2;
private String mPermissionName;
private boolean mDebuggableOnly;
private boolean mNonSystemOnly;
private boolean mIncludeNothing;
@Override
protected void onCreate(Bundle icicle) {
final Intent intent = getIntent();
String permissionName = getIntent().getStringExtra(EXTRA_REQUESTIING_PERMISSION);
boolean debuggableOnly = getIntent().getBooleanExtra(EXTRA_DEBUGGABLE, false);
boolean nonSystemOnly = getIntent().getBooleanExtra(EXTRA_NON_SYSTEM, false);
boolean includeNothing = getIntent().getBooleanExtra(EXTRA_INCLUDE_NOTHING, true);
intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS,
AppPickerListFragment.withArgs(permissionName, debuggableOnly, nonSystemOnly,
includeNothing));
super.onCreate(icicle);
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
mPermissionName = getIntent().getStringExtra(EXTRA_REQUESTIING_PERMISSION);
mDebuggableOnly = getIntent().getBooleanExtra(EXTRA_DEBUGGABLE, false);
mNonSystemOnly = getIntent().getBooleanExtra(EXTRA_NON_SYSTEM, false);
mIncludeNothing = getIntent().getBooleanExtra(EXTRA_INCLUDE_NOTHING, true);
mAdapter = new AppListAdapter(this);
if (mAdapter.getCount() <= 0) {
setResult(RESULT_NO_MATCHING_APPS);
finish();
} else {
setListAdapter(mAdapter);
}
}
@Override
@@ -88,16 +78,12 @@ public class AppPicker extends ListActivity {
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
MyApplicationInfo app = mAdapter.getItem(position);
Intent intent = new Intent();
if (app.info != null) intent.setAction(app.info.packageName);
setResult(RESULT_OK, intent);
finish();
protected boolean isValidFragment(String fragmentName) {
return AppPickerListFragment.class.getName().equals(fragmentName);
}
private void handleBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 1) {
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
super.onBackPressed();
} else {
setResult(RESULT_CANCELED);
@@ -105,106 +91,168 @@ public class AppPicker extends ListActivity {
}
}
class MyApplicationInfo {
ApplicationInfo info;
CharSequence label;
}
public static class AppPickerListFragment extends ListFragment {
private static final String EXTRA_PERMISSION_NAME = "extra_permission_name";
private static final String EXTRA_DEBUGGABLE_ONLY = "extra_debuggable_only";
private static final String EXTRA_NON_SYSTEM_ONLY = "extra_non_system_only";
private static final String EXTRA_INCLUDE_NOTHING = "extra_include_nothing";
public class AppListAdapter extends ArrayAdapter<MyApplicationInfo> {
private final List<MyApplicationInfo> mPackageInfoList = new ArrayList<MyApplicationInfo>();
private final LayoutInflater mInflater;
private String mPermissionName = "";
private boolean mDebuggableOnly;
private boolean mNonSystemOnly;
private boolean mIncludeNothing;
public AppListAdapter(Context context) {
super(context, 0);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
List<ApplicationInfo> pkgs = context.getPackageManager().getInstalledApplications(0);
for (int i=0; i<pkgs.size(); i++) {
ApplicationInfo ai = pkgs.get(i);
if (ai.uid == Process.SYSTEM_UID) {
continue;
}
private AppListAdapter mAdapter;
// Filter out apps that are not debuggable if required.
if (mDebuggableOnly) {
// On a user build, we only allow debugging of apps that
// are marked as debuggable. Otherwise (for platform development)
// we allow all apps.
if ((ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0
&& "user".equals(Build.TYPE)) {
continue;
}
}
// Filter out apps that are system apps if requested
if (mNonSystemOnly && ai.isSystemApp()) {
continue;
}
// Filter out apps that do not request the permission if required.
if (mPermissionName != null) {
boolean requestsPermission = false;
try {
PackageInfo pi = getPackageManager().getPackageInfo(ai.packageName,
PackageManager.GET_PERMISSIONS);
if (pi.requestedPermissions == null) {
continue;
}
for (String requestedPermission : pi.requestedPermissions) {
if (requestedPermission.equals(mPermissionName)) {
requestsPermission = true;
break;
}
}
if (!requestsPermission) {
continue;
}
} catch (PackageManager.NameNotFoundException e) {
continue;
}
}
MyApplicationInfo info = new MyApplicationInfo();
info.info = ai;
info.label = info.info.loadLabel(getPackageManager()).toString();
mPackageInfoList.add(info);
}
Collections.sort(mPackageInfoList, sDisplayNameComparator);
if (mIncludeNothing) {
MyApplicationInfo info = new MyApplicationInfo();
info.label = context.getText(com.android.settingslib.R.string.no_application);
mPackageInfoList.add(0, info);
}
addAll(mPackageInfoList);
public static Bundle withArgs(String permissionName,
boolean debuggableOnly, boolean nonSystemOnly, boolean includeNothing) {
final Bundle args = new Bundle(4);
args.putString(EXTRA_PERMISSION_NAME, permissionName);
args.putBoolean(EXTRA_DEBUGGABLE_ONLY, debuggableOnly);
args.putBoolean(EXTRA_NON_SYSTEM_ONLY, nonSystemOnly);
args.putBoolean(EXTRA_INCLUDE_NOTHING, includeNothing);
return args;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unnecessary calls
// to findViewById() on each row.
AppViewHolder holder = AppViewHolder.createOrRecycle(mInflater, convertView);
convertView = holder.rootView;
MyApplicationInfo info = getItem(position);
holder.appName.setText(info.label);
if (info.info != null) {
holder.appIcon.setImageDrawable(info.info.loadIcon(getPackageManager()));
holder.summary.setText(info.info.packageName);
} else {
holder.appIcon.setImageDrawable(null);
holder.summary.setText("");
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mPermissionName = getArguments().getString(EXTRA_PERMISSION_NAME);
mDebuggableOnly = getArguments().getBoolean(EXTRA_DEBUGGABLE_ONLY);
mNonSystemOnly = getArguments().getBoolean(EXTRA_NON_SYSTEM_ONLY);
mIncludeNothing = getArguments().getBoolean(EXTRA_INCLUDE_NOTHING);
}
mAdapter = new AppListAdapter(requireContext());
if (mAdapter.getCount() <= 0) {
requireActivity().setResult(RESULT_NO_MATCHING_APPS);
requireActivity().finish();
} else {
setListAdapter(mAdapter);
}
holder.disabled.setVisibility(View.GONE);
holder.widget.setVisibility(View.GONE);
return convertView;
}
@Override
public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) {
super.onListItemClick(l, v, position, id);
MyApplicationInfo app = mAdapter.getItem(position);
Intent intent = new Intent();
if (app.info != null) intent.setAction(app.info.packageName);
requireActivity().setResult(RESULT_OK, intent);
requireActivity().finish();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getListView().setNestedScrollingEnabled(true);
}
class MyApplicationInfo {
ApplicationInfo info;
CharSequence label;
}
private final class AppListAdapter extends ArrayAdapter<MyApplicationInfo> {
private final List<MyApplicationInfo> mPackageInfoList =
new ArrayList<MyApplicationInfo>();
private final LayoutInflater mInflater;
public AppListAdapter(Context context) {
super(context, 0);
mInflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
List<ApplicationInfo> pkgs = context.getPackageManager().getInstalledApplications(
0);
for (int i = 0; i < pkgs.size(); i++) {
ApplicationInfo ai = pkgs.get(i);
if (ai.uid == Process.SYSTEM_UID) {
continue;
}
// Filter out apps that are not debuggable if required.
if (mDebuggableOnly) {
// On a user build, we only allow debugging of apps that
// are marked as debuggable. Otherwise (for platform development)
// we allow all apps.
if ((ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0
&& "user".equals(Build.TYPE)) {
continue;
}
}
// Filter out apps that are system apps if requested
if (mNonSystemOnly && ai.isSystemApp()) {
continue;
}
// Filter out apps that do not request the permission if required.
if (mPermissionName != null) {
boolean requestsPermission = false;
try {
PackageInfo pi = getContext().getPackageManager().getPackageInfo(
ai.packageName, PackageManager.GET_PERMISSIONS);
if (pi.requestedPermissions == null) {
continue;
}
for (String requestedPermission : pi.requestedPermissions) {
if (requestedPermission.equals(mPermissionName)) {
requestsPermission = true;
break;
}
}
if (!requestsPermission) {
continue;
}
} catch (PackageManager.NameNotFoundException e) {
continue;
}
}
MyApplicationInfo info = new MyApplicationInfo();
info.info = ai;
info.label = info.info.loadLabel(getContext().getPackageManager()).toString();
mPackageInfoList.add(info);
}
Collections.sort(mPackageInfoList, sDisplayNameComparator);
if (mIncludeNothing) {
MyApplicationInfo info = new MyApplicationInfo();
info.label = context.getText(com.android.settingslib.R.string.no_application);
mPackageInfoList.add(0, info);
}
addAll(mPackageInfoList);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unnecessary calls
// to findViewById() on each row.
AppViewHolder holder = AppViewHolder.createOrRecycle(mInflater, convertView);
convertView = holder.rootView;
MyApplicationInfo info = getItem(position);
holder.appName.setText(info.label);
if (info.info != null) {
holder.appIcon.setImageDrawable(
info.info.loadIcon(getContext().getPackageManager()));
holder.summary.setText(info.info.packageName);
} else {
holder.appIcon.setImageDrawable(null);
holder.summary.setText("");
}
holder.disabled.setVisibility(View.GONE);
holder.widget.setVisibility(View.GONE);
return convertView;
}
}
private final static Comparator<MyApplicationInfo> sDisplayNameComparator
= new Comparator<MyApplicationInfo>() {
public final int
compare(MyApplicationInfo a, MyApplicationInfo b) {
return collator.compare(a.label, b.label);
}
private final Collator collator = Collator.getInstance();
};
}
private final static Comparator<MyApplicationInfo> sDisplayNameComparator
= new Comparator<MyApplicationInfo>() {
public final int
compare(MyApplicationInfo a, MyApplicationInfo b) {
return collator.compare(a.label, b.label);
}
private final Collator collator = Collator.getInstance();
};
}