OSDN Git Service

Add initial trust agent settings
authorAdrian Roos <roosa@google.com>
Mon, 24 Mar 2014 20:21:51 +0000 (21:21 +0100)
committerAdrian Roos <roosa@google.com>
Mon, 31 Mar 2014 21:00:51 +0000 (23:00 +0200)
Adds a first version of the trust agent settings
under Security -> Device Administration -> Trust Agents.

Change-Id: I2e2dc41208d13cc1b11bb21d427c6f86053a3640

res/layout/trust_agent_item.xml [new file with mode: 0644]
res/layout/trust_agent_settings.xml [new file with mode: 0644]
res/values/strings.xml
res/xml/security_settings_misc.xml
src/com/android/settings/TrustAgentSettings.java [new file with mode: 0644]

diff --git a/res/layout/trust_agent_item.xml b/res/layout/trust_agent_item.xml
new file mode 100644 (file)
index 0000000..5674d03
--- /dev/null
@@ -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>
diff --git a/res/layout/trust_agent_settings.xml b/res/layout/trust_agent_settings.xml
new file mode 100644 (file)
index 0000000..952d967
--- /dev/null
@@ -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>
index 90a37bf..7ad8f8e 100644 (file)
     <!-- 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 -->
     <!-- 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 -->
index 299bdf6..58f92d8 100644 (file)
                 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"
diff --git a/src/com/android/settings/TrustAgentSettings.java b/src/com/android/settings/TrustAgentSettings.java
new file mode 100644 (file)
index 0000000..f209ca5
--- /dev/null
@@ -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);
+        }
+    }
+}