1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.development;
18 
19 import android.app.ListActivity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.os.Build;
26 import android.os.Bundle;
27 import android.os.Process;
28 import android.view.LayoutInflater;
29 import android.view.MenuItem;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.ArrayAdapter;
33 import android.widget.ListView;
34 
35 import com.android.settings.R;
36 
37 import java.text.Collator;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.Comparator;
41 import java.util.List;
42 
43 public class AppPicker extends ListActivity {
44     private AppListAdapter mAdapter;
45 
46     public static final String EXTRA_REQUESTIING_PERMISSION
47             = "com.android.settings.extra.REQUESTIING_PERMISSION";
48     public static final String EXTRA_DEBUGGABLE = "com.android.settings.extra.DEBUGGABLE";
49     public static final String EXTRA_NON_SYSTEM = "com.android.settings.extra.NON_SYSTEM";
50     public static final String EXTRA_INCLUDE_NOTHING = "com.android.settings.extra.INCLUDE_NOTHING";
51 
52     public static final int RESULT_NO_MATCHING_APPS = -2;
53 
54     private String mPermissionName;
55     private boolean mDebuggableOnly;
56     private boolean mNonSystemOnly;
57     private boolean mIncludeNothing;
58 
59     @Override
onCreate(Bundle icicle)60     protected void onCreate(Bundle icicle) {
61         super.onCreate(icicle);
62         getActionBar().setDisplayHomeAsUpEnabled(true);
63 
64         mPermissionName = getIntent().getStringExtra(EXTRA_REQUESTIING_PERMISSION);
65         mDebuggableOnly = getIntent().getBooleanExtra(EXTRA_DEBUGGABLE, false);
66         mNonSystemOnly = getIntent().getBooleanExtra(EXTRA_NON_SYSTEM, false);
67         mIncludeNothing = getIntent().getBooleanExtra(EXTRA_INCLUDE_NOTHING, true);
68 
69         mAdapter = new AppListAdapter(this);
70         if (mAdapter.getCount() <= 0) {
71             setResult(RESULT_NO_MATCHING_APPS);
72             finish();
73         } else {
74             setListAdapter(mAdapter);
75         }
76     }
77 
78     @Override
onOptionsItemSelected(MenuItem item)79     public boolean onOptionsItemSelected(MenuItem item) {
80         if (item.getItemId() == android.R.id.home) {
81             handleBackPressed();
82             return true;
83         }
84         return super.onOptionsItemSelected(item);
85     }
86 
87     @Override
onListItemClick(ListView l, View v, int position, long id)88     protected void onListItemClick(ListView l, View v, int position, long id) {
89         MyApplicationInfo app = mAdapter.getItem(position);
90         Intent intent = new Intent();
91         if (app.info != null) intent.setAction(app.info.packageName);
92         setResult(RESULT_OK, intent);
93         finish();
94     }
95 
handleBackPressed()96     private void handleBackPressed() {
97         if (getFragmentManager().getBackStackEntryCount() > 1) {
98             super.onBackPressed();
99         } else {
100             setResult(RESULT_CANCELED);
101             finish();
102         }
103     }
104 
105     class MyApplicationInfo {
106         ApplicationInfo info;
107         CharSequence label;
108     }
109 
110     public class AppListAdapter extends ArrayAdapter<MyApplicationInfo> {
111         private final List<MyApplicationInfo> mPackageInfoList = new ArrayList<MyApplicationInfo>();
112         private final LayoutInflater mInflater;
113 
AppListAdapter(Context context)114         public AppListAdapter(Context context) {
115             super(context, 0);
116             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
117             List<ApplicationInfo> pkgs = context.getPackageManager().getInstalledApplications(0);
118             for (int i=0; i<pkgs.size(); i++) {
119                 ApplicationInfo ai = pkgs.get(i);
120                 if (ai.uid == Process.SYSTEM_UID) {
121                     continue;
122                 }
123 
124                 // Filter out apps that are not debuggable if required.
125                 if (mDebuggableOnly) {
126                     // On a user build, we only allow debugging of apps that
127                     // are marked as debuggable.  Otherwise (for platform development)
128                     // we allow all apps.
129                     if ((ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0
130                             && "user".equals(Build.TYPE)) {
131                         continue;
132                     }
133                 }
134 
135                 // Filter out apps that are system apps if requested
136                 if (mNonSystemOnly && ai.isSystemApp()) {
137                     continue;
138                 }
139 
140                 // Filter out apps that do not request the permission if required.
141                 if (mPermissionName != null) {
142                     boolean requestsPermission = false;
143                     try {
144                         PackageInfo pi = getPackageManager().getPackageInfo(ai.packageName,
145                                 PackageManager.GET_PERMISSIONS);
146                         if (pi.requestedPermissions == null) {
147                             continue;
148                         }
149                         for (String requestedPermission : pi.requestedPermissions) {
150                             if (requestedPermission.equals(mPermissionName)) {
151                                 requestsPermission = true;
152                                 break;
153                             }
154                         }
155                         if (!requestsPermission) {
156                             continue;
157                         }
158                     } catch (PackageManager.NameNotFoundException e) {
159                         continue;
160                     }
161                 }
162 
163                 MyApplicationInfo info = new MyApplicationInfo();
164                 info.info = ai;
165                 info.label = info.info.loadLabel(getPackageManager()).toString();
166                 mPackageInfoList.add(info);
167             }
168             Collections.sort(mPackageInfoList, sDisplayNameComparator);
169             if (mIncludeNothing) {
170                 MyApplicationInfo info = new MyApplicationInfo();
171                 info.label = context.getText(R.string.no_application);
172                 mPackageInfoList.add(0, info);
173             }
174             addAll(mPackageInfoList);
175         }
176 
177         @Override
getView(int position, View convertView, ViewGroup parent)178         public View getView(int position, View convertView, ViewGroup parent) {
179             // A ViewHolder keeps references to children views to avoid unnecessary calls
180             // to findViewById() on each row.
181             AppViewHolder holder = AppViewHolder.createOrRecycle(mInflater, convertView);
182             convertView = holder.rootView;
183             MyApplicationInfo info = getItem(position);
184             holder.appName.setText(info.label);
185             if (info.info != null) {
186                 holder.appIcon.setImageDrawable(info.info.loadIcon(getPackageManager()));
187                 holder.summary.setText(info.info.packageName);
188             } else {
189                 holder.appIcon.setImageDrawable(null);
190                 holder.summary.setText("");
191             }
192             holder.disabled.setVisibility(View.GONE);
193             holder.widget.setVisibility(View.GONE);
194             return convertView;
195         }
196     }
197 
198     private final static Comparator<MyApplicationInfo> sDisplayNameComparator
199             = new Comparator<MyApplicationInfo>() {
200         public final int
201         compare(MyApplicationInfo a, MyApplicationInfo b) {
202             return collator.compare(a.label, b.label);
203         }
204 
205         private final Collator collator = Collator.getInstance();
206     };
207 }
208