1 /*
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 package com.android.development;
19 
20 import com.android.development.R;
21 
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.List;
25 
26 import android.app.Activity;
27 import android.app.AlertDialog;
28 import android.app.Dialog;
29 import android.content.Context;
30 import android.content.DialogInterface;
31 import android.content.Intent;
32 import android.content.DialogInterface.OnCancelListener;
33 import android.content.pm.ApplicationInfo;
34 import android.content.pm.PackageInfo;
35 import android.content.pm.PackageManager;
36 import android.content.pm.PermissionInfo;
37 import android.content.pm.PackageManager.NameNotFoundException;
38 import android.os.Bundle;
39 import android.os.Handler;
40 import android.os.Message;
41 import android.util.Log;
42 import android.view.LayoutInflater;
43 import android.view.View;
44 import android.view.ViewGroup;
45 import android.widget.AdapterView;
46 import android.widget.BaseAdapter;
47 import android.widget.ImageView;
48 import android.widget.LinearLayout;
49 import android.widget.ListView;
50 import android.widget.TextView;
51 import android.widget.AdapterView.OnItemClickListener;
52 
53 /**
54  * This activity displays permission details including
55  * the list of apps using a permission.
56  */
57 public class PermissionDetails extends Activity implements OnCancelListener, OnItemClickListener {
58     private static final String TAG = "PermissionDetails";
59     PackageManager mPm;
60     // layout inflater object used to inflate views
61     private LayoutInflater mInflater;
62     private AppListAdapter mAdapter;
63 
64     // Dialog related
65     private static final int DLG_BASE = 0;
66     private static final int DLG_ERROR = DLG_BASE + 1;
67     private static final String PROTECTION_NORMAL="Normal";
68     private static final String PROTECTION_DANGEROUS="Dangerous";
69     private static final String PROTECTION_SIGNATURE="Signature";
70     private static final String PROTECTION_SIGNATURE_OR_SYSTEM="SignatureOrSystem";
71 
72     private static final String KEY_APPS_USING_PERM="AppsUsingPerm";
73 
74     private static final int HANDLER_MSG_BASE = 0;
75     private static final int HANDLER_MSG_GET_APPS = HANDLER_MSG_BASE + 1;
76     private Handler mHandler = new Handler() {
77         public void handleMessage(Message msg) {
78             switch (msg.what) {
79             case HANDLER_MSG_GET_APPS:
80                 ArrayList<PackageInfo> appList = msg.getData().getParcelableArrayList(KEY_APPS_USING_PERM);
81                 createAppList(appList);
82                 break;
83             }
84         }
85     };
86 
87     // View Holder used when displaying views
88     static class AppViewHolder {
89         TextView pkgName;
90     }
91 
92     class AppListAdapter extends BaseAdapter {
93         private List<PackageInfo> mList;
94 
AppListAdapter(List<PackageInfo> list)95         AppListAdapter(List<PackageInfo> list) {
96             mList = list;
97         }
98 
getCount()99         public int getCount() {
100             return mList.size();
101         }
102 
getItem(int position)103         public Object getItem(int position) {
104             return mList.get(position);
105         }
106 
getItemId(int position)107         public long getItemId(int position) {
108             return position;
109         }
110 
getPkg(int position)111         public PackageInfo getPkg(int position) {
112             return mList.get(position);
113         }
114 
getView(int position, View convertView, ViewGroup parent)115         public View getView(int position, View convertView, ViewGroup parent) {
116             // A ViewHolder keeps references to children views to avoid unneccessary calls
117             // to findViewById() on each row.
118             AppViewHolder holder;
119 
120             // When convertView is not null, we can reuse it directly, there is no need
121             // to reinflate it. We only inflate a new View when the convertView supplied
122             // by ListView is null.
123             if (convertView == null) {
124                 convertView = mInflater.inflate(R.layout.pkg_list_item, null);
125 
126                 // Creates a ViewHolder and store references to the two children views
127                 // we want to bind data to.
128                 holder = new AppViewHolder();
129                 holder.pkgName = (TextView) convertView.findViewById(R.id.pkg_name);
130                 convertView.setTag(holder);
131             } else {
132                 // Get the ViewHolder back to get fast access to the TextView
133                 // and the ImageView.
134                 holder = (AppViewHolder) convertView.getTag();
135             }
136             // Bind the data efficiently with the holder
137             PackageInfo pInfo = mList.get(position);
138             holder.pkgName.setText(pInfo.packageName);
139             return convertView;
140         }
141     }
142 
createAppList(List<PackageInfo> list)143     private void createAppList(List<PackageInfo> list) {
144         Log.i(TAG, "list.size=" + list.size());
145         for (PackageInfo pkg : list) {
146             Log.i(TAG, "Adding pkg : " +  pkg.packageName);
147         }
148         ListView listView = (ListView)findViewById(android.R.id.list);
149         mAdapter = new AppListAdapter(list);
150         ListView lv= (ListView) findViewById(android.R.id.list);
151         lv.setOnItemClickListener(this);
152         lv.setSaveEnabled(true);
153         lv.setItemsCanFocus(true);
154         listView.setAdapter(mAdapter);
155     }
156 
getAppsUsingPerm(PermissionInfo pInfo)157     private  void getAppsUsingPerm(PermissionInfo pInfo) {
158         List<PackageInfo> list = mPm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
159         HashSet<PackageInfo> set = new HashSet<PackageInfo>();
160         for (PackageInfo pkg : list) {
161             if (pkg.requestedPermissions == null) {
162                 continue;
163             }
164             for (String perm : pkg.requestedPermissions) {
165                 if (perm.equalsIgnoreCase(pInfo.name)) {
166                     Log.i(TAG, "Pkg:" + pkg.packageName+" uses permission");
167                     set.add(pkg);
168                     break;
169                 }
170             }
171         }
172         ArrayList<PackageInfo> retList = new ArrayList<PackageInfo>();
173         for (PackageInfo pkg : set) {
174             retList.add(pkg);
175         }
176         Message msg = mHandler.obtainMessage(HANDLER_MSG_GET_APPS);
177         Bundle data = msg.getData();
178         data.putParcelableArrayList(KEY_APPS_USING_PERM, retList);
179         mHandler.dispatchMessage(msg);
180     }
181 
182     @Override
onCreate(Bundle icicle)183     protected void onCreate(Bundle icicle) {
184         super.onCreate(icicle);
185         setContentView(R.layout.permission_details);
186         Intent intent = getIntent();
187         String permName = intent.getStringExtra("permission");
188         if(permName == null) {
189             showDialogInner(DLG_ERROR);
190         }
191         mPm = getPackageManager();
192         mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
193         PermissionInfo pInfo = null;
194         try {
195             pInfo = mPm.getPermissionInfo(permName,
196                 PackageManager.GET_PERMISSIONS);
197         } catch (NameNotFoundException e) {
198             showDialogInner(DLG_ERROR);
199         }
200         setTextView(R.id.perm_name, pInfo.name);
201         setTextView(R.id.perm_desc, pInfo.descriptionRes);
202         setTextView(R.id.perm_group, pInfo.group);
203         setProtectionLevel(R.id.perm_protection, pInfo.protectionLevel);
204         setTextView(R.id.perm_source, pInfo.packageName);
205         ApplicationInfo appInfo = null;
206         try {
207             appInfo =  mPm.getApplicationInfo(pInfo.packageName, 0);
208             String uidStr = mPm.getNameForUid(appInfo.uid);
209             setTextView(R.id.source_uid, uidStr);
210         } catch (NameNotFoundException e) {
211         }
212         boolean sharedVisibility = false;
213         // List of apps acquiring access via shared user id
214         LinearLayout sharedPanel = (LinearLayout) findViewById(R.id.shared_pkgs_panel);
215         if (appInfo != null) {
216             String[] sharedList = mPm.getPackagesForUid(appInfo.uid);
217             if ((sharedList != null) && (sharedList.length > 1)) {
218                 sharedVisibility = true;
219                 TextView label = (TextView) sharedPanel.findViewById(R.id.shared_pkgs_label);
220                 TextView sharedView = (TextView) sharedPanel.findViewById(R.id.shared_pkgs);
221                 label.setVisibility(View.VISIBLE);
222                 StringBuilder buff = new StringBuilder();
223                 buff.append(sharedList[0]);
224                 for (int i = 1; i < sharedList.length; i++) {
225                     buff.append(", ");
226                     buff.append(sharedList[i]);
227                 }
228                 sharedView.setText(buff.toString());
229             }
230         }
231         if (sharedVisibility) {
232             sharedPanel.setVisibility(View.VISIBLE);
233         } else {
234             sharedPanel.setVisibility(View.GONE);
235         }
236         getAppsUsingPerm(pInfo);
237     }
238 
setProtectionLevel(int viewId, int protectionLevel)239     private void setProtectionLevel(int viewId, int protectionLevel) {
240         String levelStr = "";
241         if (protectionLevel == PermissionInfo.PROTECTION_NORMAL) {
242             levelStr = PROTECTION_NORMAL;
243         } else if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) {
244             levelStr = PROTECTION_DANGEROUS;
245         } else if (protectionLevel == PermissionInfo.PROTECTION_SIGNATURE) {
246             levelStr = PROTECTION_SIGNATURE;
247         } else if (protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
248             levelStr = PROTECTION_SIGNATURE_OR_SYSTEM;
249         } else {
250             levelStr = "Invalid";
251         }
252         setTextView(viewId, levelStr);
253     }
254 
setTextView(int viewId, int textId)255     private void setTextView(int viewId, int textId) {
256         TextView view = (TextView)findViewById(viewId);
257         view.setText(textId);
258     }
259 
setTextView(int viewId, String text)260     private void setTextView(int viewId, String text) {
261         TextView view = (TextView)findViewById(viewId);
262         view.setText(text);
263     }
264 
265     @Override
onCreateDialog(int id)266     public Dialog onCreateDialog(int id) {
267         if (id == DLG_ERROR) {
268             return new AlertDialog.Builder(this)
269             .setTitle(R.string.dialog_title_error)
270             .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
271                 public void onClick(DialogInterface dialog, int which) {
272                     finish();
273                 }})
274             .setMessage(R.string.invalid_perm_name)
275             .setOnCancelListener(this)
276             .create();
277         }
278         return null;
279     }
280 
281     private void showDialogInner(int id) {
282         // TODO better fix for this? Remove dialog so that it gets created again
283         removeDialog(id);
284         showDialog(id);
285     }
286 
287     @Override
288     protected void onResume() {
289         super.onResume();
290     }
291 
292     @Override
293     protected void onStop() {
294         super.onStop();
295     }
296 
297     public void onCancel(DialogInterface dialog) {
298         finish();
299     }
300 
301     public void onItemClick(AdapterView<?> parent, View view, int position,
302             long id) {
303         // TODO Launch app details activity
304     }
305 }
306