Define a new activity that lists permissions and apps using that permission with some additional details as well
First pass.
This commit is contained in:
@@ -131,5 +131,11 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="PermissionDetails" android:label="Permission Info">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.development.VIEW_PERMISSION" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
135
apps/Development/res/layout/permission_details.xml
Executable file
135
apps/Development/res/layout/permission_details.xml
Executable file
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2007 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.
|
||||
-->
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fillViewport="true"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:padding="4dip" >
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
<TextView android:id="@+id/perm_name_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/perm_name_text"
|
||||
android:textStyle="bold" />
|
||||
<TextView android:id="@+id/perm_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
<TextView android:id="@+id/perm_desc_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/perm_desc_text"
|
||||
android:textStyle="bold" />
|
||||
<TextView android:id="@+id/perm_desc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
<TextView android:id="@+id/perm_group_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/perm_group_text"
|
||||
android:textStyle="bold" />
|
||||
<TextView android:id="@+id/perm_group"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
<TextView android:id="@+id/perm_protection_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/perm_protection_text"
|
||||
android:textStyle="bold" />
|
||||
<TextView android:id="@+id/perm_protection"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
<TextView android:id="@+id/perm_source_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/perm_source_text"
|
||||
android:textStyle="bold" />
|
||||
<TextView android:id="@+id/perm_source"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
<TextView android:id="@+id/source_uid_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/source_uid_text"
|
||||
android:textStyle="bold" />
|
||||
<TextView android:id="@+id/source_uid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout android:id="@+id/shared_pkgs_panel"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dip" >
|
||||
<TextView android:id="@+id/shared_pkgs_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/shared_pkgs_text"
|
||||
android:textStyle="bold" />
|
||||
<TextView android:id="@+id/shared_pkgs"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
<TextView android:id="@+id/perm_list_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="3dip"
|
||||
android:text="@string/perm_list_header_text"
|
||||
android:textStyle="bold" />
|
||||
<ListView android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
39
apps/Development/res/layout/pkg_list_item.xml
Executable file
39
apps/Development/res/layout/pkg_list_item.xml
Executable file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
** Copyright 2008, 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:paddingRight="6dip"
|
||||
android:paddingLeft="6dip"
|
||||
android:paddingTop="5dip"
|
||||
android:paddingBottom="5dip"
|
||||
android:gravity="center_vertical" >
|
||||
<TextView android:id="@+id/pkg_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textStyle="bold"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:layout_marginBottom="2dip" />
|
||||
</LinearLayout>
|
||||
|
||||
@@ -120,4 +120,17 @@
|
||||
<string name="navigation_label">navigation:</string>
|
||||
<string name="five_way_nav_label">five way nav:</string>
|
||||
<string name="gles_version_label">GLES Version:</string>
|
||||
|
||||
<!-- Permission details related string attribtues -->
|
||||
<string name="perm_name_text">Name : </string>
|
||||
<string name="dialog_title_error">Error</string>
|
||||
<string name="invalid_perm_name">Invalid Permission Name</string>
|
||||
<string name="ok">Ok</string>
|
||||
<string name="perm_desc_text">Desc : </string>
|
||||
<string name="perm_group_text">Group : </string>
|
||||
<string name="perm_protection_text">Protection Level : </string>
|
||||
<string name="perm_source_text">Source package : </string>
|
||||
<string name="perm_list_header_text">Apps using permission </string>
|
||||
<string name="source_uid_text">Source uid : </string>
|
||||
<string name="shared_pkgs_text">Packages accessing via shared uid : </string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
**
|
||||
** 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user