From 72438063453d2141218cf7fa4d8c1da6de6cbf4c Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Thu, 27 Feb 2014 18:01:20 -0500 Subject: [PATCH] Zen mode configuration panel. (packages/apps/Settings) Read-only version of the configuration screen for Limited Interruptions. Defaults to the logic implemented for this mode, namely block notifications except for Calls & Alarms. This settings panel will serve as a target for the configure affordance in SystemUI. Change-Id: I33fd1e11ab76dbb7044bb94cb096cd892945947d --- AndroidManifest.xml | 17 + ...er_default_holo_dark_am_no_underline.9.png | Bin 0 -> 408 bytes ...er_default_holo_dark_am_no_underline.9.png | Bin 0 -> 293 bytes ...er_default_holo_dark_am_no_underline.9.png | Bin 0 -> 404 bytes ...er_default_holo_dark_am_no_underline.9.png | Bin 0 -> 456 bytes res/layout/preference_zen_mode.xml | 26 ++ res/values/strings.xml | 6 +- src/com/android/settings/Settings.java | 1 + .../android/settings/SettingsActivity.java | 3 +- .../settings/ZenModeListPreference.java | 42 ++- src/com/android/settings/ZenModeSettings.java | 294 ++++++++++++++++++ 11 files changed, 385 insertions(+), 4 deletions(-) create mode 100644 res/drawable-hdpi/spinner_default_holo_dark_am_no_underline.9.png create mode 100644 res/drawable-mdpi/spinner_default_holo_dark_am_no_underline.9.png create mode 100644 res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png create mode 100644 res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png create mode 100644 res/layout/preference_zen_mode.xml create mode 100644 src/com/android/settings/ZenModeSettings.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 69fb73aef55..4f318453edd 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -561,6 +561,23 @@ android:resource="@id/sound_settings" /> + + + + + + + + + + + C3<00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3yA;#3yA?Y$;+((000McNliru-U1sBCOQ|kNvZ$<0VPR9 zK~z}7?bu67#6S?n@qdp|$MJm@@hxgp6dimZ9@S%f=W*L^N*E+eNYY71se)dFEb^ls z-JyvwvLxcd>NRQ{!$yQSVMO5=$Fyu@&&>GCCmZ5yLlAYEn@#`O?z>0000{XE)7O>#9+Nb`8qW=$J0P8#JY5_^JdVGe?#RVt$m1H{7P)J- z@QX`VV~(}HIQE;(Cg{$U)=P~lWfu4?bN<_lbn z_RAeycJ=fY=|8=VtGZUng&78fGWH!B1wCN#P$ z-(Y^uaVKT}})*0O_BPCl@i7R>anD?#srW_A3r*17h}zZ=zUdHj9Z`&Gfl%oC@7 jUm3D|pK<-~#uLn!BCL7S-`)@hx}L$))z4*}Q$iB}PWy4? literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png b/res/drawable-xhdpi/spinner_default_holo_dark_am_no_underline.9.png new file mode 100644 index 0000000000000000000000000000000000000000..8d22ce23391e365b623a091e834991be0751c2ea GIT binary patch literal 404 zcmeAS@N?(olHy`uVBq!ia0vp^dO+;N!3HEX`k#maDYhhUcNd2LAh=-f^2tCE&H|6f zVg?58P7r1^KY4mBP>{XE)7O>#9+Nb`s?G`j^%e{ajEbHvjv*QM-p(@2Vm1_To&Uzx z!AiVLmLs!hq6OpQ#XCRFd?vB;_>zsD1&J-?Zc#J;CrU4T^ihIWDr|?f=*QXXv$bYU z7iW(*%wW+gXymq8s(Wh3f%&_Ri7s6v{HlN}<^hxVjsvV9sh9^J4L47pReQOqfqMhv zw*!?bkHcT|EB5?1u4TB__*KKS&NPpl&w10kmw)J7KHKX)^If9N zkrLy_7nem#@te-gvpHSD{aAC^<(~A}=S=2hS+V{xVyTH+x9s&9VS84m{6^&u*A@g% z)!eXbf8+IuY3I~TWy7@A?s9MYsJAR#(tNY*hpXJXr0$%_n_kxteBLqi|EFlT_k3VS u{&^qw`dz@OyW88BW@&EozkmP1Q*jk$@7-w)wJU(($KdJe=d#Wzp$PyAu&E{h literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png b/res/drawable-xxhdpi/spinner_default_holo_dark_am_no_underline.9.png new file mode 100644 index 0000000000000000000000000000000000000000..29fb50f820edc7430f03a8766447f86f48bca622 GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0vp^EJ}aFGq}Y|gW!U_%O?XxI14-? ziy0WWg+Z8+Vb&Z8pdfpRr>`sfJth%;erfk#*E|^*7(+c>978H@y}fJ5*K8o*5|}^b zvFi4-rWTi%c}Oh@V99yk^VNM3W8jZW#`WC7GjIO$b@{VL(|GYr^>Yn6vpe=I+`zBU zz`(=-B|6UCv$vgDAMDl&7SpIpjWAs7#K8FE&F^N{G%XeZ2L?t|LJ^@md~@z?<_WgP zgeP=MoNkOc8o{-M{g{!$UV~{2FFOzopr0IoolnE(I) literal 0 HcmV?d00001 diff --git a/res/layout/preference_zen_mode.xml b/res/layout/preference_zen_mode.xml new file mode 100644 index 00000000000..4139d401f59 --- /dev/null +++ b/res/layout/preference_zen_mode.xml @@ -0,0 +1,26 @@ + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 7a36ccce01e..21fa912646c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5012,6 +5012,10 @@ Zen mode %1$s - + Zen mode + + Configure Zen mode + + Limited Interruptions diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 8bbd7014fdf..1c7bb59c429 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -85,6 +85,7 @@ public class Settings extends SettingsActivity { public static class PaymentSettingsActivity extends SettingsActivity { /* empty */ } public static class PrintSettingsActivity extends SettingsActivity { /* empty */ } public static class PrintJobSettingsActivity extends SettingsActivity { /* empty */ } + public static class ZenModeSettingsActivity extends SettingsActivity { /* empty */ } public static class TopLevelSettings extends SettingsActivity { /* empty */ } } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 443013899f4..337aa84bff7 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -278,7 +278,8 @@ public class SettingsActivity extends Activity TrustedCredentialsSettings.class.getName(), PaymentSettings.class.getName(), KeyboardLayoutPickerFragment.class.getName(), - DashboardSummary.class.getName() + DashboardSummary.class.getName(), + ZenModeSettings.class.getName() }; private SharedPreferences mDevelopmentPreferences; diff --git a/src/com/android/settings/ZenModeListPreference.java b/src/com/android/settings/ZenModeListPreference.java index 0315a1335fd..e405e0fe522 100644 --- a/src/com/android/settings/ZenModeListPreference.java +++ b/src/com/android/settings/ZenModeListPreference.java @@ -25,18 +25,28 @@ import android.preference.Preference; import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.ImageView; public class ZenModeListPreference extends ListPreference { private static final String TAG = "ZenModeListPreference"; private static final boolean DEBUG = false; + private final Context mContext; private final Handler mHandler = new Handler(); private final ContentResolver mResolver; + private ImageView mConfigure; + private int mMode; + public ZenModeListPreference(Context context, AttributeSet attrs) { super(context, attrs); if (DEBUG) Log.d(TAG, "new ZenModeListPreference()"); + mContext = context; mResolver = context.getContentResolver(); + setWidgetLayoutResource(R.layout.preference_zen_mode); } public void init() { @@ -55,10 +65,38 @@ public class ZenModeListPreference extends ListPreference { false, new SettingsObserver()); } + @Override + protected void onBindView(View view) { + if (DEBUG) Log.d(TAG, "onBindView"); + super.onBindView(view); + mConfigure = (ImageView)view.findViewById(R.id.configure_zen_mode); + updateConfigureVisibility(); + mConfigure.setOnClickListener(new OnClickListener(){ + @Override + public void onClick(View v) { + if (mMode != Settings.Global.ZEN_MODE_LIMITED) return; + if (mContext instanceof SettingsActivity) { + SettingsActivity sa = (SettingsActivity)mContext; + sa.startPreferencePanel(ZenModeSettings.class.getName(), + null, R.string.zen_mode_settings_title, null, null, 0); + } + } + }); + } + + private void updateConfigureVisibility() { + if (mConfigure != null) { + final boolean limited = mMode == Settings.Global.ZEN_MODE_LIMITED; + mConfigure.setVisibility(limited ? View.VISIBLE : View.GONE); + } + } + private void loadZenModeSetting(String reason) { if (DEBUG) Log.d(TAG, "loadZenModeSetting " + reason); - setValue(Integer.toString(Settings.Global.getInt(mResolver, - Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF))); + mMode = Settings.Global.getInt(mResolver, + Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); + setValue(Integer.toString(mMode)); + updateConfigureVisibility(); } private boolean saveZenModeSetting(String value) { diff --git a/src/com/android/settings/ZenModeSettings.java b/src/com/android/settings/ZenModeSettings.java new file mode 100644 index 00000000000..4b209b5bcd6 --- /dev/null +++ b/src/com/android/settings/ZenModeSettings.java @@ -0,0 +1,294 @@ +/* + * 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 android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.RelativeLayout; +import android.widget.ScrollView; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +public class ZenModeSettings extends SettingsPreferenceFragment { + private static final String TAG = "ZenModeSettings"; + private static final boolean DEBUG = false; + + private ZenModeConfigView mConfig; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + final Context context = getActivity(); + final ScrollView sv = new ScrollView(context); + sv.setVerticalScrollBarEnabled(false); + sv.setHorizontalScrollBarEnabled(false); + mConfig = new ZenModeConfigView(context); + sv.addView(mConfig); + return sv; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mConfig.resetBackground(); + } + + public static final class ZenModeConfigView extends LinearLayout { + private static final Typeface LIGHT = + Typeface.create("sans-serif-light", Typeface.NORMAL); + private static final int BG_COLOR = 0xffe7e8e9; + private final Context mContext; + + private Drawable mOldBackground; + private Toast mToast; + + public ZenModeConfigView(Context context) { + super(context); + mContext = context; + setOrientation(VERTICAL); + + int p = getResources().getDimensionPixelSize(R.dimen.content_margin_left); + TextView tv = addHeader("When on"); + tv.setPadding(0, p / 2, 0, p / 4); + addBuckets(); + tv = addHeader("Automatically turn on"); + tv.setPadding(0, p / 2, 0, p / 4); + addTriggers(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mOldBackground = getParentView().getBackground(); + if (DEBUG) Log.d(TAG, "onAttachedToWindow mOldBackground=" + mOldBackground); + getParentView().setBackgroundColor(BG_COLOR); + } + + public void resetBackground() { + if (DEBUG) Log.d(TAG, "resetBackground"); + getParentView().setBackground(mOldBackground); + } + + private View getParentView() { + return (View)getParent().getParent(); + } + + private TextView addHeader(String text) { + TextView tv = new TextView(mContext); + tv.setTypeface(LIGHT); + tv.setTextColor(0x7f000000); + tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.5f); + tv.setText(text); + addView(tv); + return tv; + } + + private void addTriggers() { + addView(new TriggerView("While driving")); + addView(new TriggerView("While in meetings")); + addView(new TriggerView("During a set time period")); + } + + private void addBuckets() { + LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.WRAP_CONTENT); + BucketView callView = new BucketView(android.R.drawable.ic_menu_call, "Calls", 2, + "Block all", "Starred contacts only", "Allow all"); + addView(callView, lp); + lp.topMargin = 4; + BucketView msgView = new BucketView(android.R.drawable.ic_menu_myplaces, + "Text & SMS Messages", 0, + "Block all", "Starred contacts only", "Allow all"); + addView(msgView, lp); + BucketView alarmView = new BucketView(android.R.drawable.ic_menu_agenda, + "Alarms & Timers", 1, + "Block all", "Allow all"); + addView(alarmView, lp); + BucketView otherView = new BucketView(android.R.drawable.ic_menu_info_details, + "Other Interruptions", 0, + "Block all", "Block all except..."); + addView(otherView, lp); + } + + private void notImplemented() { + if (mToast != null) mToast.cancel(); + mToast = Toast.makeText(mContext, "Not implemented", Toast.LENGTH_SHORT); + mToast.show(); + } + + private class BucketView extends RelativeLayout { + private final BucketSpinner mSpinner; + + public BucketView(int icon, String category, int defaultValue, String... values) { + super(ZenModeConfigView.this.mContext); + + setBackgroundColor(0xffffffff); + final int p = getResources().getDimensionPixelSize(R.dimen.content_margin_left); + + final ImageView iv = new ImageView(mContext); + iv.setId(android.R.id.icon); + iv.setImageResource(icon); + iv.setAlpha(.5f); + + final int size = mContext.getResources() + .getDimensionPixelSize(R.dimen.app_icon_size); + LayoutParams lp = new LayoutParams(size, size); + lp.addRule(CENTER_VERTICAL); + lp.leftMargin = 16; + lp.rightMargin = 16; + addView(iv, lp); + + TextView tv = new TextView(mContext); + tv.setPadding(4, 0, 0, 0); + tv.setId(android.R.id.title); + tv.setTextColor(0xff000000); + tv.setText(category); + tv.setAllCaps(true); + lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + lp.addRule(RIGHT_OF, iv.getId()); + lp.topMargin = p / 2; + addView(tv, lp); + + mSpinner = new BucketSpinner(defaultValue, values); + lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + lp.addRule(RIGHT_OF, iv.getId()); + lp.addRule(BELOW, tv.getId()); + addView(mSpinner, lp); + } + } + + private class BucketSpinner extends Spinner { + private final Bitmap mArrow; + + public BucketSpinner(int defaultValue, String... values) { + super(ZenModeConfigView.this.mContext); + setGravity(Gravity.LEFT); + mArrow = BitmapFactory.decodeResource(getResources(), + R.drawable.spinner_default_holo_dark_am_no_underline); + setPadding(0, 0, getPaddingRight(), getPaddingBottom()); + setBackgroundColor(0x00000000); + final ArrayAdapter adapter = new ArrayAdapter(mContext, 0) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return getDropDownView(position, convertView, parent); + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + final TextView tv = convertView != null ? (TextView) convertView + : new TextView(ZenModeConfigView.this.mContext); + tv.setText(getItem(position)); + if (convertView == null) { + tv.setTypeface(LIGHT); + tv.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); + tv.setTextColor(0xff000000); + tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.5f); + final int p = (int) tv.getTextSize() / 2; + if (parent instanceof ListView) { + final ListView lv = (ListView)parent; + lv.setDividerHeight(0); + tv.setBackgroundColor(BG_COLOR); + tv.setPadding(p, p, p, p); + } else { + tv.setPadding(0, 0, p, 0); + } + } + return tv; + } + }; + adapter.addAll(values); + setAdapter(adapter); + setSelection(defaultValue, true); + } + + @Override + protected void onDraw(Canvas canvas) { + final TextView tv = (TextView)getSelectedView(); + final int w = (int)tv.getLayout().getLineWidth(0); + final int left = w - mArrow.getWidth() / 4; + final int top = getHeight() - mArrow.getHeight(); + canvas.drawBitmap(mArrow, left, top, null); + super.onDraw(canvas); + } + + @Override + public void setSelection(int position) { + if (position != getSelectedItemPosition()) { + notImplemented(); + } + } + } + + private class TriggerView extends RelativeLayout { + public TriggerView(String text) { + super(ZenModeConfigView.this.mContext); + + setBackgroundColor(0xffffffff); + final int p = getResources().getDimensionPixelSize(R.dimen.content_margin_left); + final int p2 = p / 4; + setPadding(p2, p2, p2, p2); + + final CheckBox cb = new CheckBox(mContext); + cb.setId(android.R.id.checkbox); + cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + cb.setChecked(false); + notImplemented(); + } + } + }); + LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + lp.addRule(ALIGN_PARENT_RIGHT); + addView(cb, lp); + + final TextView tv = new TextView(mContext); + tv.setText(text); + tv.setTypeface(LIGHT); + tv.setTextColor(0xff000000); + tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.5f); + final int p3 = p / 2; + tv.setPadding(p3, 0, p3, 0); + lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + lp.addRule(LEFT_OF, cb.getId()); + lp.addRule(CENTER_VERTICAL); + addView(tv, lp); + } + } + } +}