diff --git a/res/layout/restricted_preference_dropdown.xml b/res/layout/restricted_preference_dropdown.xml new file mode 100644 index 00000000000..1a1e19168b2 --- /dev/null +++ b/res/layout/restricted_preference_dropdown.xml @@ -0,0 +1,30 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/layout/spinner_dropdown_restricted_item.xml b/res/layout/spinner_dropdown_restricted_item.xml new file mode 100644 index 00000000000..823b430186d --- /dev/null +++ b/res/layout/spinner_dropdown_restricted_item.xml @@ -0,0 +1,36 @@ + + + + + + \ No newline at end of file diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml index 40a856917ba..ee9237c5543 100644 --- a/res/xml/app_notification_settings.xml +++ b/res/xml/app_notification_settings.xml @@ -17,8 +17,7 @@ + android:key="app_notification_settings"> @@ -43,7 +42,7 @@ android:order="4"/> - diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java index bd6f4fe5f1e..f718b3c71fa 100644 --- a/src/com/android/settings/notification/AppNotificationSettings.java +++ b/src/com/android/settings/notification/AppNotificationSettings.java @@ -26,7 +26,6 @@ import android.content.pm.UserInfo; import android.os.Bundle; import android.os.UserHandle; import android.service.notification.NotificationListenerService.Ranking; -import android.support.v7.preference.DropDownPreference; import android.util.ArrayMap; import android.util.Log; @@ -76,7 +75,7 @@ public class AppNotificationSettings extends NotificationSettingsBase { mPriority = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BYPASS_DND); mVisibilityOverride = - (DropDownPreference) getPreferenceScreen().findPreference( + (RestrictedDropDownPreference) getPreferenceScreen().findPreference( KEY_VISIBILITY_OVERRIDE); mBlock = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BLOCK); mSilent = (RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_SILENT); diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java index 77a329c092d..97a36b66696 100644 --- a/src/com/android/settings/notification/NotificationSettingsBase.java +++ b/src/com/android/settings/notification/NotificationSettingsBase.java @@ -23,6 +23,7 @@ import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedSwitchPreference; import android.app.Notification; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; @@ -33,7 +34,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.service.notification.NotificationListenerService.Ranking; -import android.support.v7.preference.DropDownPreference; import android.support.v7.preference.Preference; import android.text.TextUtils; import android.util.Log; @@ -41,6 +41,7 @@ import android.widget.Toast; import java.util.ArrayList; +import static com.android.settings.notification.RestrictedDropDownPreference.RestrictedItem; import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; abstract public class NotificationSettingsBase extends SettingsPreferenceFragment { @@ -65,7 +66,7 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen protected PackageInfo mPkgInfo; protected ImportanceSeekBarPreference mImportance; protected RestrictedSwitchPreference mPriority; - protected DropDownPreference mVisibilityOverride; + protected RestrictedDropDownPreference mVisibilityOverride; protected RestrictedSwitchPreference mBlock; protected RestrictedSwitchPreference mSilent; protected EnforcedAdmin mSuspendedAppsAdmin; @@ -148,6 +149,9 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen if (mSilent != null) { mSilent.setDisabledByAdmin(mSuspendedAppsAdmin); } + if (mVisibilityOverride != null) { + mVisibilityOverride.setDisabledByAdmin(mSuspendedAppsAdmin); + } } protected void setupImportancePrefs(boolean isSystemApp, int importance, boolean banned) { @@ -216,13 +220,24 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen ArrayList entries = new ArrayList<>(); ArrayList values = new ArrayList<>(); + mVisibilityOverride.clearRestrictedItems(); if (getLockscreenNotificationsEnabled() && getLockscreenAllowPrivateNotifications()) { - entries.add(getString(R.string.lock_screen_notifications_summary_show)); - values.add(Integer.toString(Ranking.VISIBILITY_NO_OVERRIDE)); + final String summaryShowEntry = + getString(R.string.lock_screen_notifications_summary_show); + final String summaryShowEntryValue = Integer.toString(Ranking.VISIBILITY_NO_OVERRIDE); + entries.add(summaryShowEntry); + values.add(summaryShowEntryValue); + setRestrictedIfNotificationFeaturesDisabled(summaryShowEntry, summaryShowEntryValue, + DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS + | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS); } - entries.add(getString(R.string.lock_screen_notifications_summary_hide)); - values.add(Integer.toString(Notification.VISIBILITY_PRIVATE)); + final String summaryHideEntry = getString(R.string.lock_screen_notifications_summary_hide); + final String summaryHideEntryValue = Integer.toString(Notification.VISIBILITY_PRIVATE); + entries.add(summaryHideEntry); + values.add(summaryHideEntryValue); + setRestrictedIfNotificationFeaturesDisabled(summaryHideEntry, summaryHideEntryValue, + DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS); entries.add(getString(R.string.lock_screen_notifications_summary_disable)); values.add(Integer.toString(Notification.VISIBILITY_SECRET)); mVisibilityOverride.setEntries(entries.toArray(new CharSequence[entries.size()])); @@ -248,6 +263,16 @@ abstract public class NotificationSettingsBase extends SettingsPreferenceFragmen }); } + private void setRestrictedIfNotificationFeaturesDisabled(CharSequence entry, + CharSequence entryValue, int keyguardNotificationFeatures) { + EnforcedAdmin admin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled( + mContext, keyguardNotificationFeatures, mUserId); + if (admin != null) { + RestrictedItem item = new RestrictedItem(entry, entryValue, admin); + mVisibilityOverride.addRestrictedItem(item); + } + } + private int getGlobalVisibility() { int globalVis = Ranking.VISIBILITY_NO_OVERRIDE; if (!getLockscreenNotificationsEnabled()) { diff --git a/src/com/android/settings/notification/RestrictedDropDownPreference.java b/src/com/android/settings/notification/RestrictedDropDownPreference.java new file mode 100644 index 00000000000..e4a4cb6b154 --- /dev/null +++ b/src/com/android/settings/notification/RestrictedDropDownPreference.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2016 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.notification; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.support.v7.preference.DropDownPreference; +import android.support.v7.preference.PreferenceViewHolder; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.ArrayAdapter; +import android.widget.Spinner; +import android.widget.TextView; + +import com.android.settings.R; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import com.android.settingslib.RestrictedPreferenceHelper; + +import java.util.ArrayList; +import java.util.List; + +public class RestrictedDropDownPreference extends DropDownPreference { + private final RestrictedPreferenceHelper mHelper; + private ReselectionSpinner mSpinner; + private List mRestrictedItems = new ArrayList<>(); + private boolean mUserClicked = false; + + public RestrictedDropDownPreference(Context context, AttributeSet attrs) { + super(context, attrs); + setLayoutResource(R.layout.restricted_preference_dropdown); + setWidgetLayoutResource(R.layout.restricted_icon); + mHelper = new RestrictedPreferenceHelper(context, this, attrs); + } + + @Override + protected ArrayAdapter createAdapter() { + return new RestrictedArrayItemAdapter(getContext()); + } + + @Override + public void setValue(String value) { + if (getRestrictedItemForEntryValue(value) != null) { + return; + } + super.setValue(value); + } + + @Override + public void onBindViewHolder(PreferenceViewHolder view) { + mSpinner = (ReselectionSpinner) view.itemView.findViewById(R.id.spinner); + mSpinner.setPreference(this); + super.onBindViewHolder(view); + mHelper.onBindViewHolder(view); + mSpinner.setOnItemSelectedListener(mItemSelectedListener); + final View restrictedIcon = view.findViewById(R.id.restricted_icon); + if (restrictedIcon != null) { + restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE); + } + } + + private boolean isRestrictedForEntry(CharSequence entry) { + if (entry == null) { + return false; + } + for (RestrictedItem item : mRestrictedItems) { + if (entry.equals(item.entry)) { + return true; + } + } + return false; + } + + private RestrictedItem getRestrictedItemForEntryValue(CharSequence entryValue) { + if (entryValue == null) { + return null; + } + for (RestrictedItem item : mRestrictedItems) { + if (entryValue.equals(item.entryValue)) { + return item; + } + } + return null; + } + + private RestrictedItem getRestrictedItemForPosition(int position) { + if (position < 0 || position >= getEntryValues().length) { + return null; + } + CharSequence entryValue = getEntryValues()[position]; + return getRestrictedItemForEntryValue(entryValue); + } + + public void addRestrictedItem(RestrictedItem item) { + mRestrictedItems.add(item); + } + + public void clearRestrictedItems() { + mRestrictedItems.clear(); + } + + @Override + public void performClick() { + if (!mHelper.performClick()) { + mUserClicked = true; + super.performClick(); + } + } + + @Override + public void setEnabled(boolean enabled) { + if (enabled && isDisabledByAdmin()) { + mHelper.setDisabledByAdmin(null); + return; + } + super.setEnabled(enabled); + } + + public void setDisabledByAdmin(EnforcedAdmin admin) { + if (mHelper.setDisabledByAdmin(admin)) { + notifyChanged(); + } + } + + public boolean isDisabledByAdmin() { + return mHelper.isDisabledByAdmin(); + } + + private void setUserClicked(boolean userClicked) { + mUserClicked = userClicked; + } + + private boolean isUserClicked() { + return mUserClicked; + } + + private final OnItemSelectedListener mItemSelectedListener = new OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View v, int position, long id) { + if (mUserClicked) { + mUserClicked = false; + } else { + return; + } + if (position >= 0 && position < getEntryValues().length) { + String value = getEntryValues()[position].toString(); + RestrictedItem item = getRestrictedItemForEntryValue(value); + if (item != null) { + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), + item.enforcedAdmin); + mSpinner.setSelection(findIndexOfValue(getValue())); + } else if (!value.equals(getValue()) && callChangeListener(value)) { + setValue(value); + } + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + // noop + } + }; + + /** + * Extension of {@link ArrayAdapter} which updates the state of the dropdown item + * depending on whether it is restricted by the admin. + */ + private class RestrictedArrayItemAdapter extends ArrayAdapter { + private static final int TEXT_RES_ID = android.R.id.text1; + public RestrictedArrayItemAdapter(Context context) { + super(context, R.layout.spinner_dropdown_restricted_item, TEXT_RES_ID); + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + View rootView = super.getView(position, convertView, parent); + CharSequence entry = getItem(position); + boolean isEntryRestricted = isRestrictedForEntry(entry); + TextView text = (TextView) rootView.findViewById(TEXT_RES_ID); + if (text != null) { + text.setEnabled(!isEntryRestricted); + } + View restrictedIcon = rootView.findViewById(R.id.restricted_icon); + if (restrictedIcon != null) { + restrictedIcon.setVisibility(isEntryRestricted ? View.VISIBLE : View.GONE); + } + return rootView; + } + } + + /** + * Extension of {@link Spinner} which triggers the admin support dialog on user clicking a + * restricted item even if was already selected. + */ + public static class ReselectionSpinner extends Spinner { + private RestrictedDropDownPreference pref; + + public ReselectionSpinner(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setPreference(RestrictedDropDownPreference pref) { + this.pref = pref; + } + + @Override + public void setSelection(int position) { + int previousSelectedPosition = getSelectedItemPosition(); + super.setSelection(position); + if (position == previousSelectedPosition && pref.isUserClicked()) { + pref.setUserClicked(false); + RestrictedItem item = pref.getRestrictedItemForPosition(position); + if (item != null) { + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), + item.enforcedAdmin); + } + } + } + } + + public static class RestrictedItem { + public final CharSequence entry; + public final CharSequence entryValue; + public final EnforcedAdmin enforcedAdmin; + + public RestrictedItem(CharSequence entry, CharSequence entryValue, + EnforcedAdmin enforcedAdmin) { + this.entry = entry; + this.entryValue = entryValue; + this.enforcedAdmin = enforcedAdmin; + } + } +} \ No newline at end of file