| /* | |
| ** | |
| ** Copyright 2006, The Android Open Source 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.android.development; | |
| import com.android.development.R; | |
| import java.util.ArrayList; | |
| import java.util.HashSet; | |
| import java.util.List; | |
| import android.app.Activity; | |
| import android.app.AlertDialog; | |
| import android.app.Dialog; | |
| import android.content.Context; | |
| import android.content.DialogInterface; | |
| import android.content.Intent; | |
| import android.content.DialogInterface.OnCancelListener; | |
| import android.content.pm.ApplicationInfo; | |
| import android.content.pm.PackageInfo; | |
| import android.content.pm.PackageManager; | |
| import android.content.pm.PermissionInfo; | |
| import android.content.pm.PackageManager.NameNotFoundException; | |
| import android.os.Bundle; | |
| import android.os.Handler; | |
| import android.os.Message; | |
| import android.util.Log; | |
| import android.view.LayoutInflater; | |
| import android.view.View; | |
| import android.view.ViewGroup; | |
| import android.widget.AdapterView; | |
| import android.widget.BaseAdapter; | |
| import android.widget.ImageView; | |
| import android.widget.LinearLayout; | |
| import android.widget.ListView; | |
| import android.widget.TextView; | |
| import android.widget.AdapterView.OnItemClickListener; | |
| /** | |
| * This activity displays permission details including | |
| * the list of apps using a permission. | |
| */ | |
| public class PermissionDetails extends Activity implements OnCancelListener, OnItemClickListener { | |
| private static final String TAG = "PermissionDetails"; | |
| PackageManager mPm; | |
| // layout inflater object used to inflate views | |
| private LayoutInflater mInflater; | |
| private AppListAdapter mAdapter; | |
| // Dialog related | |
| private static final int DLG_BASE = 0; | |
| private static final int DLG_ERROR = DLG_BASE + 1; | |
| private static final String PROTECTION_NORMAL="Normal"; | |
| private static final String PROTECTION_DANGEROUS="Dangerous"; | |
| private static final String PROTECTION_SIGNATURE="Signature"; | |
| private static final String PROTECTION_SIGNATURE_OR_SYSTEM="SignatureOrSystem"; | |
| private static final String KEY_APPS_USING_PERM="AppsUsingPerm"; | |
| private static final int HANDLER_MSG_BASE = 0; | |
| private static final int HANDLER_MSG_GET_APPS = HANDLER_MSG_BASE + 1; | |
| private Handler mHandler = new Handler() { | |
| public void handleMessage(Message msg) { | |
| switch (msg.what) { | |
| case HANDLER_MSG_GET_APPS: | |
| ArrayList<PackageInfo> appList = msg.getData().getParcelableArrayList(KEY_APPS_USING_PERM); | |
| createAppList(appList); | |
| break; | |
| } | |
| } | |
| }; | |
| // View Holder used when displaying views | |
| static class AppViewHolder { | |
| TextView pkgName; | |
| } | |
| class AppListAdapter extends BaseAdapter { | |
| private List<PackageInfo> mList; | |
| AppListAdapter(List<PackageInfo> list) { | |
| mList = list; | |
| } | |
| public int getCount() { | |
| return mList.size(); | |
| } | |
| public Object getItem(int position) { | |
| return mList.get(position); | |
| } | |
| public long getItemId(int position) { | |
| return position; | |
| } | |
| public PackageInfo getPkg(int position) { | |
| return mList.get(position); | |
| } | |
| public View getView(int position, View convertView, ViewGroup parent) { | |
| // A ViewHolder keeps references to children views to avoid unneccessary calls | |
| // to findViewById() on each row. | |
| AppViewHolder holder; | |
| // When convertView is not null, we can reuse it directly, there is no need | |
| // to reinflate it. We only inflate a new View when the convertView supplied | |
| // by ListView is null. | |
| if (convertView == null) { | |
| convertView = mInflater.inflate(R.layout.pkg_list_item, null); | |
| // Creates a ViewHolder and store references to the two children views | |
| // we want to bind data to. | |
| holder = new AppViewHolder(); | |
| holder.pkgName = (TextView) convertView.findViewById(R.id.pkg_name); | |
| convertView.setTag(holder); | |
| } else { | |
| // Get the ViewHolder back to get fast access to the TextView | |
| // and the ImageView. | |
| holder = (AppViewHolder) convertView.getTag(); | |
| } | |
| // Bind the data efficiently with the holder | |
| PackageInfo pInfo = mList.get(position); | |
| holder.pkgName.setText(pInfo.packageName); | |
| return convertView; | |
| } | |
| } | |
| private void createAppList(List<PackageInfo> list) { | |
| Log.i(TAG, "list.size=" + list.size()); | |
| for (PackageInfo pkg : list) { | |
| Log.i(TAG, "Adding pkg : " + pkg.packageName); | |
| } | |
| ListView listView = (ListView)findViewById(android.R.id.list); | |
| mAdapter = new AppListAdapter(list); | |
| ListView lv= (ListView) findViewById(android.R.id.list); | |
| lv.setOnItemClickListener(this); | |
| lv.setSaveEnabled(true); | |
| lv.setItemsCanFocus(true); | |
| listView.setAdapter(mAdapter); | |
| } | |
| private void getAppsUsingPerm(PermissionInfo pInfo) { | |
| List<PackageInfo> list = mPm.getInstalledPackages(PackageManager.GET_PERMISSIONS); | |
| HashSet<PackageInfo> set = new HashSet<PackageInfo>(); | |
| for (PackageInfo pkg : list) { | |
| if (pkg.requestedPermissions == null) { | |
| continue; | |
| } | |
| for (String perm : pkg.requestedPermissions) { | |
| if (perm.equalsIgnoreCase(pInfo.name)) { | |
| Log.i(TAG, "Pkg:" + pkg.packageName+" uses permission"); | |
| set.add(pkg); | |
| break; | |
| } | |
| } | |
| } | |
| ArrayList<PackageInfo> retList = new ArrayList<PackageInfo>(); | |
| for (PackageInfo pkg : set) { | |
| retList.add(pkg); | |
| } | |
| Message msg = mHandler.obtainMessage(HANDLER_MSG_GET_APPS); | |
| Bundle data = msg.getData(); | |
| data.putParcelableArrayList(KEY_APPS_USING_PERM, retList); | |
| mHandler.dispatchMessage(msg); | |
| } | |
| @Override | |
| protected void onCreate(Bundle icicle) { | |
| super.onCreate(icicle); | |
| setContentView(R.layout.permission_details); | |
| Intent intent = getIntent(); | |
| String permName = intent.getStringExtra("permission"); | |
| if(permName == null) { | |
| showDialogInner(DLG_ERROR); | |
| } | |
| mPm = getPackageManager(); | |
| mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); | |
| PermissionInfo pInfo = null; | |
| try { | |
| pInfo = mPm.getPermissionInfo(permName, | |
| PackageManager.GET_PERMISSIONS); | |
| } catch (NameNotFoundException e) { | |
| showDialogInner(DLG_ERROR); | |
| } | |
| setTextView(R.id.perm_name, pInfo.name); | |
| setTextView(R.id.perm_desc, pInfo.descriptionRes); | |
| setTextView(R.id.perm_group, pInfo.group); | |
| setProtectionLevel(R.id.perm_protection, pInfo.protectionLevel); | |
| setTextView(R.id.perm_source, pInfo.packageName); | |
| ApplicationInfo appInfo = null; | |
| try { | |
| appInfo = mPm.getApplicationInfo(pInfo.packageName, 0); | |
| String uidStr = mPm.getNameForUid(appInfo.uid); | |
| setTextView(R.id.source_uid, uidStr); | |
| } catch (NameNotFoundException e) { | |
| } | |
| boolean sharedVisibility = false; | |
| // List of apps acquiring access via shared user id | |
| LinearLayout sharedPanel = (LinearLayout) findViewById(R.id.shared_pkgs_panel); | |
| if (appInfo != null) { | |
| String[] sharedList = mPm.getPackagesForUid(appInfo.uid); | |
| if ((sharedList != null) && (sharedList.length > 1)) { | |
| sharedVisibility = true; | |
| TextView label = (TextView) sharedPanel.findViewById(R.id.shared_pkgs_label); | |
| TextView sharedView = (TextView) sharedPanel.findViewById(R.id.shared_pkgs); | |
| label.setVisibility(View.VISIBLE); | |
| StringBuilder buff = new StringBuilder(); | |
| buff.append(sharedList[0]); | |
| for (int i = 1; i < sharedList.length; i++) { | |
| buff.append(", "); | |
| buff.append(sharedList[i]); | |
| } | |
| sharedView.setText(buff.toString()); | |
| } | |
| } | |
| if (sharedVisibility) { | |
| sharedPanel.setVisibility(View.VISIBLE); | |
| } else { | |
| sharedPanel.setVisibility(View.GONE); | |
| } | |
| getAppsUsingPerm(pInfo); | |
| } | |
| private void setProtectionLevel(int viewId, int protectionLevel) { | |
| String levelStr = ""; | |
| if (protectionLevel == PermissionInfo.PROTECTION_NORMAL) { | |
| levelStr = PROTECTION_NORMAL; | |
| } else if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) { | |
| levelStr = PROTECTION_DANGEROUS; | |
| } else if (protectionLevel == PermissionInfo.PROTECTION_SIGNATURE) { | |
| levelStr = PROTECTION_SIGNATURE; | |
| } else if (protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { | |
| levelStr = PROTECTION_SIGNATURE_OR_SYSTEM; | |
| } else { | |
| levelStr = "Invalid"; | |
| } | |
| setTextView(viewId, levelStr); | |
| } | |
| private void setTextView(int viewId, int textId) { | |
| TextView view = (TextView)findViewById(viewId); | |
| view.setText(textId); | |
| } | |
| private void setTextView(int viewId, String text) { | |
| TextView view = (TextView)findViewById(viewId); | |
| view.setText(text); | |
| } | |
| @Override | |
| public Dialog onCreateDialog(int id) { | |
| if (id == DLG_ERROR) { | |
| return new AlertDialog.Builder(this) | |
| .setTitle(R.string.dialog_title_error) | |
| .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { | |
| public void onClick(DialogInterface dialog, int which) { | |
| finish(); | |
| }}) | |
| .setMessage(R.string.invalid_perm_name) | |
| .setOnCancelListener(this) | |
| .create(); | |
| } | |
| return null; | |
| } | |
| private void showDialogInner(int id) { | |
| // TODO better fix for this? Remove dialog so that it gets created again | |
| removeDialog(id); | |
| showDialog(id); | |
| } | |
| @Override | |
| protected void onResume() { | |
| super.onResume(); | |
| } | |
| @Override | |
| protected void onStop() { | |
| super.onStop(); | |
| } | |
| public void onCancel(DialogInterface dialog) { | |
| finish(); | |
| } | |
| public void onItemClick(AdapterView<?> parent, View view, int position, | |
| long id) { | |
| // TODO Launch app details activity | |
| } | |
| } |