Add initial trust agent settings

Adds a first version of the trust agent settings
under Security -> Device Administration -> Trust Agents.

Change-Id: I2e2dc41208d13cc1b11bb21d427c6f86053a3640
This commit is contained in:
Adrian Roos
2014-03-24 21:21:51 +01:00
parent 3726525d50
commit 5954ff505f
5 changed files with 444 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical">
<LinearLayout
android:id="@+id/clickable"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground">
<CheckBox
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:focusable="false"
android:clickable="false"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:fadingEdge="horizontal"/>
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:paddingBottom="3dip"
android:visibility="gone"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="13sp"
android:textColor="?android:attr/textColorSecondary"
android:focusable="false"
android:maxLines="4"/>
</RelativeLayout>
</LinearLayout>
<View
android:layout_width="2dip"
android:layout_height="match_parent"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:background="@android:drawable/divider_horizontal_dark"/>
<ImageView
android:id="@+id/settings"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingStart="15dip"
android:paddingEnd="?android:attr/scrollbarSize"
android:src="@drawable/ic_sysbar_quicksettings"
android:contentDescription="@string/input_method_settings_button"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"/>
</LinearLayout>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2014 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="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1">
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"
android:fastScrollEnabled="true" />
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/no_trust_agents"
android:textAppearance="?android:attr/textAppearanceMedium" />
</FrameLayout>
</LinearLayout>

View File

@@ -1020,6 +1020,12 @@
<!-- Summary of preference to manage device policies -->
<string name="manage_device_admin_summary">View or deactivate device administrators</string>
<!-- Title of preference to manage trust agents -->
<string name="manage_trust_agents">Trust agents</string>
<!-- Summary of preference to manage device policies -->
<string name="manage_trust_agents_summary">View or deactivate trust agents</string>
<!-- Notification access settings (part of Security) -->
<!-- Title of preference to manage notification listeners -->
@@ -4064,6 +4070,9 @@
<!-- Message when there are no available device admins to display -->
<string name="no_device_admins">No available device administrators</string>
<!-- Message when there are no available trust agents to display -->
<string name="no_trust_agents">No available trust agents</string>
<!-- Label for screen showing to add device policy -->
<string name="add_device_admin_msg">Activate device administrator?</string>
<!-- Label for button to set the active device admin -->

View File

@@ -45,6 +45,11 @@
android:persistent="false"
android:fragment="com.android.settings.DeviceAdminSettings"/>
<Preference android:title="@string/manage_trust_agents"
android:summary="@string/manage_trust_agents_summary"
android:persistent="false"
android:fragment="com.android.settings.TrustAgentSettings"/>
<CheckBoxPreference
android:key="toggle_install_applications"
android:title="@string/install_applications"

View File

@@ -0,0 +1,304 @@
/*
* Copyright (C) 2014 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.settings;
import com.android.internal.widget.LockPatternUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.ListFragment;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.service.trust.TrustAgentService;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Slog;
import android.util.Xml;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.IOException;
import java.util.List;
public class TrustAgentSettings extends ListFragment implements View.OnClickListener {
static final String TAG = "TrustAgentSettings";
private static final String SERVICE_INTERFACE = TrustAgentService.SERVICE_INTERFACE;
private static final String TRUST_AGENT_META_DATA = TrustAgentService.TRUST_AGENT_META_DATA;
private final ArraySet<ComponentName> mActiveAgents = new ArraySet<ComponentName>();
private final ArrayMap<ComponentName, AgentInfo> mAvailableAgents
= new ArrayMap<ComponentName, AgentInfo>();
private LockPatternUtils mLockPatternUtils;
public static final class AgentInfo {
CharSequence label;
Drawable icon;
ComponentName component; // service that implements ITrustAgent
ComponentName settings; // setting to launch to modify agent.
@Override
public boolean equals(Object other) {
if (other instanceof AgentInfo) {
return component.equals(((AgentInfo)other).component);
}
return true;
}
public int compareTo(AgentInfo other) {
return component.compareTo(other.component);
}
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (mLockPatternUtils == null) {
mLockPatternUtils = new LockPatternUtils(
container.getContext().getApplicationContext());
}
setListAdapter(new AgentListAdapter());
return inflater.inflate(R.layout.trust_agent_settings, container, false);
}
@Override
public void onResume() {
super.onResume();
updateList();
}
void updateList() {
Context context = getActivity();
if (context == null) {
return;
}
loadActiveAgents();
PackageManager pm = getActivity().getPackageManager();
Intent trustAgentIntent = new Intent(SERVICE_INTERFACE);
List<ResolveInfo> resolveInfos = pm.queryIntentServices(trustAgentIntent,
PackageManager.GET_META_DATA);
mAvailableAgents.clear();
mAvailableAgents.ensureCapacity(resolveInfos.size());
for (ResolveInfo resolveInfo : resolveInfos) {
if (resolveInfo.serviceInfo == null) continue;
ComponentName name = getComponentName(resolveInfo);
if (!mAvailableAgents.containsKey(name)) {
AgentInfo agentInfo = new AgentInfo();
agentInfo.label = resolveInfo.loadLabel(pm);
agentInfo.icon = resolveInfo.loadIcon(pm);
agentInfo.component = name;
agentInfo.settings = getSettingsComponentName(pm, resolveInfo);
mAvailableAgents.put(name, agentInfo);
}
}
((BaseAdapter) getListAdapter()).notifyDataSetChanged();
}
private ComponentName getComponentName(ResolveInfo resolveInfo) {
if (resolveInfo == null || resolveInfo.serviceInfo == null) return null;
return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
}
private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
if (resolveInfo == null || resolveInfo.serviceInfo == null
|| resolveInfo.serviceInfo.metaData == null) return null;
String cn = null;
XmlResourceParser parser = null;
Exception caughtException = null;
try {
parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, TRUST_AGENT_META_DATA);
if (parser == null) {
Slog.w(TAG, "Can't find " + TRUST_AGENT_META_DATA + " meta-data");
return null;
}
Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
}
String nodeName = parser.getName();
if (!"trust_agent".equals(nodeName)) {
Slog.w(TAG, "Meta-data does not start with trust_agent tag");
return null;
}
TypedArray sa = res
.obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
sa.recycle();
} catch (PackageManager.NameNotFoundException e) {
caughtException = e;
} catch (IOException e) {
caughtException = e;
} catch (XmlPullParserException e) {
caughtException = e;
} finally {
if (parser != null) parser.close();
}
if (caughtException != null) {
Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
return null;
}
if (cn != null && cn.indexOf('/') < 0) {
cn = resolveInfo.serviceInfo.packageName + "/" + cn;
}
return cn == null ? null : ComponentName.unflattenFromString(cn);
}
@Override
public void onClick(View view) {
ViewHolder h = (ViewHolder) view.getTag();
AgentInfo agentInfo = h.agentInfo;
if (view.getId() == R.id.settings) {
if (agentInfo.settings != null) {
Intent intent = new Intent();
intent.setComponent(agentInfo.settings);
intent.setAction("TODO");
startActivity(intent);
}
} else if (view.getId() == R.id.clickable) {
boolean wasActive = mActiveAgents.contains(h.agentInfo.component);
loadActiveAgents();
if (!wasActive) {
mActiveAgents.add(h.agentInfo.component);
} else {
mActiveAgents.remove(h.agentInfo.component);
}
saveActiveAgents();
((BaseAdapter) getListAdapter()).notifyDataSetChanged();
}
}
private void loadActiveAgents() {
mActiveAgents.clear();
List<ComponentName> activeTrustAgents = mLockPatternUtils.getEnabledTrustAgents();
if (activeTrustAgents != null) {
mActiveAgents.addAll(activeTrustAgents);
}
}
private void saveActiveAgents() {
mLockPatternUtils.setEnabledTrustAgents(mActiveAgents);
}
static class ViewHolder {
ImageView icon;
TextView name;
CheckBox checkbox;
TextView description;
AgentInfo agentInfo;
View clickable;
View settings;
}
class AgentListAdapter extends BaseAdapter {
final LayoutInflater mInflater;
AgentListAdapter() {
mInflater = (LayoutInflater)
getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public boolean hasStableIds() {
return false;
}
public int getCount() {
return mAvailableAgents.size();
}
public Object getItem(int position) {
return mAvailableAgents.valueAt(position);
}
public long getItemId(int position) {
return position;
}
public boolean areAllItemsEnabled() {
return false;
}
public boolean isEnabled(int position) {
return true;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v;
if (convertView == null) {
v = newView(parent);
} else {
v = convertView;
}
bindView(v, position);
return v;
}
public View newView(ViewGroup parent) {
View v = mInflater.inflate(R.layout.trust_agent_item, parent, false);
ViewHolder h = new ViewHolder();
h.icon = (ImageView)v.findViewById(R.id.icon);
h.name = (TextView)v.findViewById(R.id.name);
h.checkbox = (CheckBox)v.findViewById(R.id.checkbox);
h.clickable = v.findViewById(R.id.clickable);
h.clickable.setOnClickListener(TrustAgentSettings.this);
h.description = (TextView)v.findViewById(R.id.description);
h.settings = v.findViewById(R.id.settings);
h.settings.setOnClickListener(TrustAgentSettings.this);
v.setTag(h);
h.settings.setTag(h);
h.clickable.setTag(h);
return v;
}
public void bindView(View view, int position) {
ViewHolder vh = (ViewHolder) view.getTag();
AgentInfo item = mAvailableAgents.valueAt(position);
vh.name.setText(item.label);
vh.checkbox.setChecked(mActiveAgents.contains(item.component));
vh.agentInfo = item;
vh.settings.setVisibility(item.settings != null ? View.VISIBLE : View.INVISIBLE);
}
}
}