Merge "Add support for showing the admin disabling settings."

This commit is contained in:
Kenny Guy
2015-12-14 14:31:37 +00:00
committed by Android (Google) Code Review
14 changed files with 595 additions and 11 deletions

View File

@@ -2646,5 +2646,15 @@
android:value="com.android.settings.applications.WriteSettingsDetails" />
</activity>
<activity android:name="ShowAdminSupportDetailsDialog"
android:theme="@style/Transparent"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.app.action.SHOW_ADMIN_SUPPORT_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="22.0"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="@android:color/white"
android:pathData="M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM8.9 6c0-1.71 1.39-3.1 3.1-3.1s3.1 1.39 3.1 3.1v2H8.9V6zM18 20H6V10h12v10z" />
</vector>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 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="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/admin_details_dialog_padding"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingBottom="@dimen/admin_details_dialog_padding">
<ImageView
android:layout_width="@dimen/admin_details_dialog_icon_size"
android:layout_height="@dimen/admin_details_dialog_icon_size"
android:src="@drawable/ic_settings_lock_outline"
android:scaleType="fitCenter"
android:contentDescription="@null" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/admin_details_dialog_padding"
android:text="@string/disabled_by_policy_title"
android:textAppearance="@android:style/TextAppearance.Material.Title" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fadeScrollbars="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:id="@+id/disabled_by_admin_msg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorSecondary" />
<TextView android:id="@+id/admin_support_msg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/textColorSecondary" />
<TextView android:id="@+id/admins_policies_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/admin_details_dialog_link_padding_top"
android:text="@string/list_of_administrators"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="?android:attr/colorAccent"
android:clickable="true"
android:background="?android:attr/selectableItemBackground" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -114,4 +114,8 @@
<attr name="android:entries" />
<attr name="android:entryValues" />
</declare-styleable>
<declare-styleable name="RestrictedPreference">
<attr name="userRestriction" format="string"/>
</declare-styleable>
</resources>

View File

@@ -250,6 +250,15 @@
<dimen name="shortcut_size">40dp</dimen>
<dimen name="badge_size">10dp</dimen>
<!-- Lock icon for preferences locked by admin -->
<dimen name="restricted_lock_icon_size">16dp</dimen>
<dimen name="restricted_lock_icon_padding">4dp</dimen>
<!-- Admin support contact details dialog. -->
<dimen name="admin_details_dialog_padding">24dp</dimen>
<dimen name="admin_details_dialog_icon_size">48dp</dimen>
<dimen name="admin_details_dialog_link_padding_top">36dp</dimen>
<!-- Button bar padding for unmount button. -->
<dimen name="unmount_button_padding">8dp</dimen>

View File

@@ -6684,4 +6684,11 @@
<!-- Summary of device info page [CHAR LIMIT=NONE] -->
<string name="about_summary">Android <xliff:g id="version" example="6.0">%1$s</xliff:g></string>
<!-- TODO: Update these strings with the finalized ones. -->
<string name="disabled_by_policy_title">Disabled by policy</string>
<string name="disabled_by_admin_msg">Disabled by your <xliff:g id="organisation_name" example="organisation">%s</xliff:g>\'s administrator.</string>
<string name="default_organisation_name">organisation</string>
<string name="default_admin_support_msg">Contact them to learn more.</string>
<string name="list_of_administrators">List of administrators</string>
</resources>

View File

@@ -54,10 +54,11 @@
android:fragment="com.android.settings.ResetNetwork" />
<!-- Factory reset -->
<PreferenceScreen
<com.android.settings.RestrictedPreference
android:key="factory_reset"
android:title="@string/master_clear_title"
settings:keywords="@string/keywords_factory_data_reset"
settings:userRestriction="no_factory_reset"
android:fragment="com.android.settings.MasterClear" />
</PreferenceScreen>

View File

@@ -52,7 +52,7 @@
android:persistent="false"
android:fragment="com.android.settings.DeviceAdminSettings"/>
<SwitchPreference android:key="toggle_install_applications"
<com.android.settings.RestrictedSwitchPreference android:key="toggle_install_applications"
android:title="@string/install_applications"
android:summaryOff="@string/install_unknown_applications"
android:summaryOn="@string/install_unknown_applications"

View File

@@ -290,10 +290,6 @@ public class PrivacySettings extends SettingsPreferenceFragment implements Index
nonVisibleKeys.add(AUTO_RESTORE);
nonVisibleKeys.add(CONFIGURE_ACCOUNT);
}
if (UserManager.get(context).hasUserRestriction(
UserManager.DISALLOW_FACTORY_RESET)) {
nonVisibleKeys.add(FACTORY_RESET);
}
if (UserManager.get(context).hasUserRestriction(
UserManager.DISALLOW_NETWORK_RESET)) {
nonVisibleKeys.add(NETWORK_RESET);

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2015 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 android.content.ComponentName;
import android.content.Context;
import android.os.UserHandle;
import android.support.v4.content.res.TypedArrayUtils;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
/**
* Preference class that supports being disabled by a user restriction
* set by a device admin.
*/
public class RestrictedPreference extends Preference {
RestrictedPreferenceHelper mHelper;
public RestrictedPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
}
public RestrictedPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public RestrictedPreference(Context context, AttributeSet attrs) {
this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.preferenceStyle,
android.R.attr.preferenceStyle));
}
public RestrictedPreference(Context context) {
this(context, null);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mHelper.onBindViewHolder(holder);
}
@Override
public void performClick() {
if (!mHelper.performClick()) {
super.performClick();
}
}
@Override
protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
mHelper.onAttachedToHierarchy();
super.onAttachedToHierarchy(preferenceManager);
}
public void checkRestrictionAndSetDisabled(String userRestriction) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
}
public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
public void setDisabledByAdmin(boolean disabled) {
mHelper.setDisabledByAdmin(disabled, null, UserHandle.USER_NULL);
}
public void setDisabledByAdmin(boolean disabled, ComponentName admin, int userId) {
if (mHelper.setDisabledByAdmin(disabled, admin, userId)) {
notifyChanged();
}
}
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
}

View File

@@ -0,0 +1,195 @@
/*
* Copyright (C) 2015 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 android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
/**
* Helper class for managing settings preferences that can be disabled
* by device admins via user restrictions.
*
**/
public class RestrictedPreferenceHelper {
private final Context mContext;
private final Preference mPreference;
private final Drawable mRestrictedPadlock;
private final int mRestrictedPadlockPadding;
private final DevicePolicyManager mDevicePolicyManager;
private boolean mDisabledByAdmin;
private ComponentName mEnforcedAdmin;
private int mUserId = UserHandle.USER_NULL;
private String mAttrUserRestriction = null;
RestrictedPreferenceHelper(Context context, Preference preference,
AttributeSet attrs) {
mContext = context;
mPreference = preference;
mRestrictedPadlock = mContext.getDrawable(R.drawable.ic_settings_lock_outline);
final int iconSize = mContext.getResources().getDimensionPixelSize(
R.dimen.restricted_lock_icon_size);
mRestrictedPadlock.setBounds(0, 0, iconSize, iconSize);
mRestrictedPadlockPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.restricted_lock_icon_padding);
mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
mAttrUserRestriction = attrs.getAttributeValue(
R.styleable.RestrictedPreference_userRestriction);
final TypedArray attributes = context.obtainStyledAttributes(attrs,
R.styleable.RestrictedPreference);
final TypedValue userRestriction =
attributes.peekValue(R.styleable.RestrictedPreference_userRestriction);
CharSequence data = null;
if (userRestriction != null && userRestriction.type == TypedValue.TYPE_STRING) {
if (userRestriction.resourceId != 0) {
data = context.getText(userRestriction.resourceId);
} else {
data = userRestriction.string;
}
}
mAttrUserRestriction = data == null ? null : data.toString();
}
/**
* Modify PreferenceViewHolder to add padlock if restriction is disabled.
*/
public void onBindViewHolder(PreferenceViewHolder holder) {
final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
if (titleView != null) {
if (mDisabledByAdmin) {
titleView.setCompoundDrawablesRelative(null, null, mRestrictedPadlock, null);
titleView.setCompoundDrawablePadding(mRestrictedPadlockPadding);
holder.itemView.setEnabled(true);
} else {
titleView.setCompoundDrawablesRelative(null, null, null, null);
}
}
}
/**
* Check if the preference is disabled if so handle the click by informing the user.
*
* @return true if the method handled the click.
*/
public boolean performClick() {
if (mDisabledByAdmin) {
Intent intent = new Intent(mContext, ShowAdminSupportDetailsDialog.class);
if (mEnforcedAdmin != null) {
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mEnforcedAdmin);
}
if (mUserId != UserHandle.USER_NULL) {
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
}
mContext.startActivity(intent);
return true;
}
return false;
}
/**
* Disable / enable if we have been passed the restriction in the xml.
*/
protected void onAttachedToHierarchy() {
if (mAttrUserRestriction != null) {
checkRestrictionAndSetDisabled(mAttrUserRestriction, UserHandle.myUserId());
}
}
/**
* Set the user restriction that is used to disable this preference.
*
* @param userRestriction constant from {@link android.os.UserManager}
* @param userId user to check the restriction for.
*/
public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
ComponentName deviceOwner = mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();
int deviceOwnerUserId = mDevicePolicyManager.getDeviceOwnerUserId();
boolean enforcedByDeviceOwner = false;
if (deviceOwner != null && deviceOwnerUserId != UserHandle.USER_NULL) {
enforcedByDeviceOwner = isEnforcedByAdmin(
deviceOwner, userRestriction, deviceOwnerUserId);
}
ComponentName profileOwner = mDevicePolicyManager.getProfileOwnerAsUser(userId);
boolean enforcedByProfileOwner = false;
if (profileOwner != null && userId != UserHandle.USER_NULL) {
enforcedByProfileOwner = isEnforcedByAdmin(
profileOwner, userRestriction, userId);
}
if (!enforcedByDeviceOwner && !enforcedByProfileOwner) {
setDisabledByAdmin(false, null, UserHandle.USER_NULL);
return;
}
if (enforcedByDeviceOwner && enforcedByProfileOwner) {
setDisabledByAdmin(true, null, UserHandle.USER_NULL);
} else if (enforcedByDeviceOwner) {
setDisabledByAdmin(true, deviceOwner, deviceOwnerUserId);
} else {
setDisabledByAdmin(true, profileOwner, userId);
}
}
private boolean isEnforcedByAdmin(ComponentName admin, String userRestriction, int userId) {
Bundle enforcedRestrictions = mDevicePolicyManager.getUserRestrictions(admin, userId);
if (enforcedRestrictions != null
&& enforcedRestrictions.getBoolean(userRestriction, false)) {
return true;
}
return false;
}
/**
* Disable this preference.
*
* @param disabled true if preference should be disabled.
* @param admin Device admin that disabled the preference.
* @param userId userId the device admin is installed for.
* @return true if the disabled state was changed.
*/
public boolean setDisabledByAdmin(boolean disabled, ComponentName admin, int userId) {
if (mDisabledByAdmin != disabled) {
mDisabledByAdmin = disabled;
mEnforcedAdmin = admin;
mUserId = userId;
mPreference.setEnabled(!disabled);
return true;
}
return false;
}
public boolean isDisabledByAdmin() {
return mDisabledByAdmin;
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2015 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 android.content.ComponentName;
import android.content.Context;
import android.os.UserHandle;
import android.support.v4.content.res.TypedArrayUtils;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
/**
* Version of SwitchPreference that can be disabled by a device admin
* using a user restriction.
*/
public class RestrictedSwitchPreference extends SwitchPreference {
RestrictedPreferenceHelper mHelper;
public RestrictedSwitchPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
}
public RestrictedSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public RestrictedSwitchPreference(Context context, AttributeSet attrs) {
this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.switchPreferenceStyle,
android.R.attr.switchPreferenceStyle));
}
public RestrictedSwitchPreference(Context context) {
this(context, null);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mHelper.onBindViewHolder(holder);
}
@Override
public void performClick() {
if (!mHelper.performClick()) {
super.performClick();
}
}
@Override
protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
mHelper.onAttachedToHierarchy();
super.onAttachedToHierarchy(preferenceManager);
}
public void checkRestrictionAndSetDisabled(String userRestriction) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
}
public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
public void setDisabledByAdmin(boolean disabled) {
mHelper.setDisabledByAdmin(disabled, null, UserHandle.USER_NULL);
}
public void setDisabledByAdmin(boolean disabled, ComponentName admin, int userId) {
if (mHelper.setDisabledByAdmin(disabled, admin, userId)) {
notifyChanged();
}
}
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
}

View File

@@ -129,7 +129,7 @@ public class SecuritySettings extends SettingsPreferenceFragment
private KeyStore mKeyStore;
private Preference mResetCredentials;
private SwitchPreference mToggleAppInstallation;
private RestrictedSwitchPreference mToggleAppInstallation;
private DialogInterface mWarnInstallApps;
private SwitchPreference mPowerButtonInstantlyLocks;
@@ -313,15 +313,19 @@ public class SecuritySettings extends SettingsPreferenceFragment
// Application install
PreferenceGroup deviceAdminCategory = (PreferenceGroup)
root.findPreference(KEY_DEVICE_ADMIN_CATEGORY);
mToggleAppInstallation = (SwitchPreference) findPreference(
mToggleAppInstallation = (RestrictedSwitchPreference) findPreference(
KEY_TOGGLE_INSTALL_APPLICATIONS);
mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
// Side loading of apps.
// Disable for restricted profiles. For others, check if policy disallows it.
mToggleAppInstallation.setEnabled(!um.getUserInfo(MY_USER_ID).isRestricted());
if (um.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)
|| um.hasUserRestriction(UserManager.DISALLOW_INSTALL_APPS)) {
mToggleAppInstallation.setEnabled(false);
if (mToggleAppInstallation.isEnabled()) {
mToggleAppInstallation.checkRestrictionAndSetDisabled(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
if (!mToggleAppInstallation.isDisabledByAdmin()) {
mToggleAppInstallation.checkRestrictionAndSetDisabled(
UserManager.DISALLOW_INSTALL_APPS);
}
}
// Advanced Security features

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 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 android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
public class ShowAdminSupportDetailsDialog extends Activity
implements DialogInterface.OnDismissListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View rootView = LayoutInflater.from(this).inflate(
R.layout.admin_support_details_dialog, null);
setAdminSupportDetails(rootView);
new AlertDialog.Builder(this)
.setView(rootView)
.setPositiveButton(R.string.okay, null)
.setOnDismissListener(this)
.show();
}
private void setAdminSupportDetails(View root) {
CharSequence adminDisabledMsg = getString(R.string.disabled_by_admin_msg,
getString(R.string.default_organisation_name));
TextView textView = (TextView) root.findViewById(R.id.disabled_by_admin_msg);
textView.setText(adminDisabledMsg);
CharSequence adminSupportDetails = getString(R.string.default_admin_support_msg);
textView = (TextView) root.findViewById(R.id.admin_support_msg);
textView.setText(adminSupportDetails);
root.findViewById(R.id.admins_policies_list).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setClass(ShowAdminSupportDetailsDialog.this,
Settings.DeviceAdminSettingsActivity.class);
startActivity(intent);
finish();
}
});
}
@Override
public void onDismiss(DialogInterface dialog) {
finish();
}
}