blob: 26fea5d98e6114f824fe456640674b3bc907686a [file] [log] [blame]
/*
**
** 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
}
}