Implement new volume UI design.
- Add segmented zen-mode picker to the rocker UI.
- Add a new "no interruptions" value to the zen setting.
- Implement expandable condition subpanel on the rocker UI.
- Remove the old circle&slash icons.
- Suppress alarm sounds if in "no interruptions" mode.
- Add warning re: alarms to the condition UI.
- Allow rocker UI to display over the keyguard.
- Remove Notifications QS tile.
- Realign volume rocker to the top of the screen.
- Add support for new "days" sleepMode.
- New icon policy rules for "volume" slot.
- New important icon (star).
Associated Settings change:
I6ed56791784968adfbd684f490dbbebed285a2dd
Bug:15831713
Change-Id: I35afe38646f04d2ba0dbac11c2c6356120a33694
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
deleted file mode 100644
index 3bdea79..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotificationsTile.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * 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.systemui.qs.tiles;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnAttachStateChangeListener;
-import android.view.ViewGroup;
-
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.volume.VolumeComponent;
-import com.android.systemui.volume.VolumePanel;
-import com.android.systemui.volume.ZenModePanel;
-
-/** Quick settings tile: Notifications **/
-public class NotificationsTile extends QSTile<NotificationsTile.NotificationsState> {
- private final ZenModeController mZenController;
- private final AudioManager mAudioManager;
-
- public NotificationsTile(Host host) {
- super(host);
- mZenController = host.getZenModeController();
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- }
-
- @Override
- public DetailAdapter getDetailAdapter() {
- return mDetailAdapter;
- }
-
- @Override
- protected NotificationsState newTileState() {
- return new NotificationsState();
- }
-
- @Override
- public void setListening(boolean listening) {
- if (listening) {
- mZenController.addCallback(mCallback);
- final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
- mContext.registerReceiver(mReceiver, filter);
- } else {
- mZenController.removeCallback(mCallback);
- mContext.unregisterReceiver(mReceiver);
- }
- }
-
- @Override
- protected void handleClick() {
- showDetail(true);
- }
-
- @Override
- protected void handleUpdateState(NotificationsState state, Object arg) {
- state.visible = true;
- state.zen = arg instanceof Boolean ? (Boolean) arg : mZenController.isZen();
- state.ringerMode = mAudioManager.getRingerMode();
- if (state.zen) {
- state.iconId = R.drawable.ic_qs_zen_on;
- } else if (state.ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
- state.iconId = R.drawable.ic_qs_ringer_vibrate;
- } else if (state.ringerMode == AudioManager.RINGER_MODE_SILENT) {
- state.iconId = R.drawable.ic_qs_ringer_silent;
- } else {
- state.iconId = R.drawable.ic_qs_ringer_audible;
- }
- state.label = mContext.getString(R.string.quick_settings_notifications_label);
- }
-
- private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
- @Override
- public void onZenChanged(boolean zen) {
- if (DEBUG) Log.d(TAG, "onZenChanged " + zen);
- refreshState(zen);
- }
- };
-
- public static final class NotificationsState extends QSTile.State {
- public boolean zen;
- public int ringerMode;
-
- @Override
- public boolean copyTo(State other) {
- final NotificationsState o = (NotificationsState) other;
- final boolean changed = o.zen != zen || o.ringerMode != ringerMode;
- o.zen = zen;
- o.ringerMode = ringerMode;
- return super.copyTo(other) || changed;
- }
-
- @Override
- protected StringBuilder toStringBuilder() {
- final StringBuilder rt = super.toStringBuilder();
- rt.insert(rt.length() - 1, ",zen=" + zen + ",ringerMode=" + ringerMode);
- return rt;
- }
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
- refreshState();
- }
- }
- };
-
- private final DetailAdapter mDetailAdapter = new DetailAdapter() {
-
- @Override
- public int getTitle() {
- return R.string.quick_settings_notifications_label;
- }
-
- @Override
- public Boolean getToggleState() {
- return null;
- }
-
- public void setToggleState(boolean state) {
- // noop
- }
-
- public Intent getSettingsIntent() {
- return ZenModePanel.ZEN_SETTINGS;
- }
-
- @Override
- public View createDetailView(Context context, View convertView, ViewGroup parent) {
- if (convertView != null) return convertView;
- final VolumeComponent volumeComponent = mHost.getVolumeComponent();
- final VolumePanel vp = new VolumePanel(mContext, parent, mZenController);
- final View v = vp.getContentView();
- v.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
- @Override
- public void onViewDetachedFromWindow(View v) {
- volumeComponent.setVolumePanel(null);
- }
-
- @Override
- public void onViewAttachedToWindow(View v) {
- vp.updateStates();
- volumeComponent.setVolumePanel(vp);
- }
- });
- vp.setZenModePanelCallback(new ZenModePanel.Callback() {
- @Override
- public void onMoreSettings() {
- mHost.startSettingsActivity(ZenModePanel.ZEN_SETTINGS);
- }
-
- @Override
- public void onInteraction() {
- // noop
- }
- });
- vp.postVolumeChanged(AudioManager.STREAM_RING, AudioManager.FLAG_SHOW_UI);
- return v;
- }
- };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 84eee24..5d1b16c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -266,7 +266,7 @@
final TextView summary = (TextView) item.findViewById(android.R.id.summary);
if (ap.isConnected) {
item.setMinimumHeight(mContext.getResources()
- .getDimensionPixelSize(R.dimen.qs_detail_item_height_connected));
+ .getDimensionPixelSize(R.dimen.qs_detail_item_height_twoline));
summary.setText(R.string.quick_settings_connected);
} else {
summary.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 0a3fdef..a11e610 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -60,7 +60,7 @@
} else if (mDemoMode && command.equals(COMMAND_STATUS)) {
String volume = args.getString("volume");
if (volume != null) {
- int iconId = volume.equals("zen") ? R.drawable.stat_sys_ringer_zen
+ int iconId = volume.equals("important") ? R.drawable.stat_sys_zen_important
: volume.equals("silent") ? R.drawable.stat_sys_ringer_silent
: volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate
: 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f697098..a6b2110 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -738,6 +738,14 @@
return mStatusBarView;
}
+ @Override
+ protected void setZenMode(int mode) {
+ super.setZenMode(mode);
+ if (mIconPolicy != null) {
+ mIconPolicy.setZenMode(mode);
+ }
+ }
+
private void startKeyguard() {
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index b6f5ae0..186b618 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -24,6 +24,7 @@
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
+import android.provider.Settings.Global;
import android.util.Log;
import com.android.internal.telephony.IccCardConstants;
@@ -64,7 +65,7 @@
private boolean mVolumeVisible;
// zen mode
- private boolean mZen;
+ private int mZen;
// bluetooth device status
private boolean mBluetoothEnabled = false;
@@ -155,7 +156,7 @@
updateVolume();
}
- public void setZenMode(boolean zen) {
+ public void setZenMode(int zen) {
mZen = zen;
updateVolume();
}
@@ -202,21 +203,21 @@
private final void updateVolume() {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
final int ringerMode = audioManager.getRingerMode();
- final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
- ringerMode == AudioManager.RINGER_MODE_VIBRATE ||
- mZen;
-
- final int iconId;
+ int iconId = 0;
String contentDescription = null;
- if (mZen) {
- iconId = R.drawable.stat_sys_ringer_zen;
- contentDescription = mContext.getString(R.string.zen_mode_title);
+ boolean visible = false;
+ if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
+ visible = true;
+ iconId = R.drawable.stat_sys_ringer_silent;
+ contentDescription = mContext.getString(R.string.accessibility_ringer_silent);
+ } else if (mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+ visible = true;
+ iconId = R.drawable.stat_sys_zen_important;
+ contentDescription = mContext.getString(R.string.zen_important_interruptions);
} else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+ visible = true;
iconId = R.drawable.stat_sys_ringer_vibrate;
contentDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
- } else {
- iconId = R.drawable.stat_sys_ringer_silent;
- contentDescription = mContext.getString(R.string.accessibility_ringer_silent);
}
if (visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 04b1443..5fbade1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -21,19 +21,16 @@
import android.os.HandlerThread;
import android.os.Looper;
-import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.tiles.AirplaneModeTile;
import com.android.systemui.qs.tiles.BluetoothTile;
-import com.android.systemui.qs.tiles.BugreportTile;
import com.android.systemui.qs.tiles.CastTile;
import com.android.systemui.qs.tiles.CellularTile;
import com.android.systemui.qs.tiles.ColorInversionTile;
import com.android.systemui.qs.tiles.FlashlightTile;
-import com.android.systemui.qs.tiles.LocationTile;
-import com.android.systemui.qs.tiles.NotificationsTile;
-import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.HotspotTile;
+import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.WifiTile;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.BluetoothController;
@@ -93,7 +90,6 @@
mTiles.add(new ColorInversionTile(this));
mTiles.add(new CellularTile(this));
mTiles.add(new AirplaneModeTile(this));
- mTiles.add(new NotificationsTile(this));
mTiles.add(new RotationLockTile(this));
mTiles.add(new LocationTile(this));
mTiles.add(new CastTile(this));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 4cf72a2..61902a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -22,14 +22,15 @@
public interface ZenModeController {
void addCallback(Callback callback);
void removeCallback(Callback callback);
- void setZen(boolean zen);
- boolean isZen();
+ void setZen(int zen);
+ int getZen();
void requestConditions(boolean request);
void setExitConditionId(Uri exitConditionId);
Uri getExitConditionId();
+ boolean hasNextAlarm();
public static class Callback {
- public void onZenChanged(boolean zen) {}
+ public void onZenChanged(int zen) {}
public void onExitConditionChanged(Uri exitConditionId) {}
public void onConditionsChanged(Condition[] conditions) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index da8fd32..7703966 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -28,6 +28,7 @@
import android.service.notification.ZenModeConfig;
import android.util.Slog;
+import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.qs.GlobalSetting;
import java.util.ArrayList;
@@ -44,15 +45,17 @@
private final GlobalSetting mConfigSetting;
private final INotificationManager mNoMan;
private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
+ private final LockPatternUtils mUtils;
private boolean mRequesting;
public ZenModeControllerImpl(Context context, Handler handler) {
mContext = context;
+ mUtils = new LockPatternUtils(mContext);
mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
@Override
protected void handleValueChanged(int value) {
- fireZenChanged(value != 0);
+ fireZenChanged(value);
}
};
mConfigSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE_CONFIG_ETAG) {
@@ -78,13 +81,13 @@
}
@Override
- public boolean isZen() {
- return mModeSetting.getValue() != 0;
+ public int getZen() {
+ return mModeSetting.getValue();
}
@Override
- public void setZen(boolean zen) {
- mModeSetting.setValue(zen ? 1 : 0);
+ public void setZen(int zen) {
+ mModeSetting.setValue(zen);
}
@Override
@@ -122,7 +125,12 @@
return null;
}
- private void fireZenChanged(boolean zen) {
+ @Override
+ public boolean hasNextAlarm() {
+ return mUtils.getNextAlarm() != null;
+ }
+
+ private void fireZenChanged(int zen) {
for (Callback cb : mCallbacks) {
cb.onZenChanged(zen);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
new file mode 100644
index 0000000..d339dd4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -0,0 +1,93 @@
+/*
+ * 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.systemui.volume;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+
+import java.util.Objects;
+
+public class SegmentedButtons extends LinearLayout {
+
+ private final Context mContext;
+ private final LayoutInflater mInflater;
+
+ private Callback mCallback;
+ private Object mSelectedValue;
+
+ public SegmentedButtons(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ mInflater = LayoutInflater.from(mContext);
+ setOrientation(HORIZONTAL);
+ }
+
+ public void setCallback(Callback callback) {
+ mCallback = callback;
+ }
+
+ public Object getSelectedValue() {
+ return mSelectedValue;
+ }
+
+ public void setSelectedValue(Object value) {
+ if (Objects.equals(value, mSelectedValue)) return;
+ mSelectedValue = value;
+ for (int i = 0; i < getChildCount(); i++) {
+ final View c = getChildAt(i);
+ final Object tag = c.getTag();
+ c.setSelected(Objects.equals(mSelectedValue, tag));
+ }
+ fireOnSelected();
+ }
+
+ public void addButton(int labelResId, Object value) {
+ final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false);
+ b.setText(labelResId);
+ final LayoutParams lp = (LayoutParams) b.getLayoutParams();
+ if (getChildCount() == 0) {
+ lp.leftMargin = lp.rightMargin = 0; // first button has no margin
+ }
+ b.setLayoutParams(lp);
+ addView(b);
+ b.setTag(value);
+ b.setOnClickListener(mClick);
+ }
+
+ private void fireOnSelected() {
+ if (mCallback != null) {
+ mCallback.onSelected(mSelectedValue);
+ }
+ }
+
+ private final View.OnClickListener mClick = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setSelectedValue(v.getTag());
+ }
+ };
+
+ public interface Callback {
+ void onSelected(Object value);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 53daaae..b6d6767 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -16,8 +16,6 @@
package com.android.systemui.volume;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
@@ -38,24 +36,21 @@
import android.media.session.MediaController;
import android.media.session.MediaController.VolumeInfo;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
+import android.provider.Settings.Global;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -71,7 +66,8 @@
* @hide
*/
public class VolumePanel extends Handler {
- private static boolean LOGD = false;
+ private static final String TAG = "VolumePanel";
+ private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
@@ -89,7 +85,6 @@
private static final int FREE_DELAY = 10000;
private static final int TIMEOUT_DELAY = 3000;
private static final int TIMEOUT_DELAY_EXPANDED = 10000;
- private static final float ICON_PULSE_SCALE = 1.3f;
private static final int MSG_VOLUME_CHANGED = 0;
private static final int MSG_FREE_RESOURCES = 1;
@@ -105,6 +100,7 @@
private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
private static final int MSG_LAYOUT_DIRECTION = 12;
private static final int MSG_ZEN_MODE_CHANGED = 13;
+ private static final int MSG_USER_ACTIVITY = 14;
// Pseudo stream type for master volume
private static final int STREAM_MASTER = -100;
@@ -114,7 +110,6 @@
protected final Context mContext;
private final AudioManager mAudioManager;
private final ZenModeController mZenController;
- private final Interpolator mFastOutSlowInInterpolator;
private boolean mRingIsSilent;
private boolean mVoiceCapable;
private boolean mZenModeCapable;
@@ -135,18 +130,12 @@
private final ViewGroup mPanel;
/** Contains the slider and its touchable icons */
private final ViewGroup mSliderPanel;
- /** The button that expands the dialog to show the zen panel */
- private final ImageView mExpandButton;
- /** Dummy divider icon that needs to vanish with the expand button */
- private final View mExpandDivider;
/** The zen mode configuration panel view stub */
private final ViewStub mZenPanelStub;
/** The zen mode configuration panel view, once inflated */
private ZenModePanel mZenPanel;
- /** Dummy divider icon that needs to vanish with the zen panel */
- private final View mZenPanelDivider;
- private ZenModePanel.Callback mZenPanelCallback;
+ private Callback mCallback;
/** Currently active stream that shows up at the top of the list of sliders */
private int mActiveStreamType = -1;
@@ -231,7 +220,6 @@
ViewGroup group;
ImageView icon;
SeekBar seekbarView;
- View seekbarContainer;
int iconRes;
int iconMuteRes;
}
@@ -280,13 +268,11 @@
public VolumePanel(Context context, ViewGroup parent, ZenModeController zenController) {
- mTag = String.format("VolumePanel%s.%08x", parent == null ? "Dialog" : "", hashCode());
+ mTag = String.format("%s.%s.%08x", TAG, parent == null ? "Dialog" : "Embed", hashCode());
mContext = context;
mParent = parent;
mZenController = zenController;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_slow_in);
// For now, only show master volume if master volume is supported
final Resources res = context.getResources();
@@ -318,12 +304,11 @@
lp.token = null;
// Offset from the top
lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
- lp.width = res.getDimensionPixelSize(com.android.systemui.R.dimen.volume_panel_width);
- lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
+ lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
lp.format = PixelFormat.TRANSLUCENT;
- lp.windowAnimations = R.style.Animation_VolumePanel;
+ lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
+ lp.gravity = Gravity.TOP;
window.setAttributes(lp);
- window.setGravity(Gravity.TOP);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.requestFeature(Window.FEATURE_NO_TITLE);
window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
@@ -337,7 +322,7 @@
public void onDismiss(DialogInterface dialog) {
mActiveStreamType = -1;
mAudioManager.forceVolumeControlStream(mActiveStreamType);
- collapse();
+ setZenPanelVisible(false);
}
});
@@ -362,19 +347,14 @@
}
mPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.visible_panel);
mSliderPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.slider_panel);
- mExpandButton = (ImageView) mView.findViewById(com.android.systemui.R.id.expand_button);
- mExpandDivider = mView.findViewById(com.android.systemui.R.id.expand_button_divider);
mZenPanelStub = (ViewStub)mView.findViewById(com.android.systemui.R.id.zen_panel_stub);
- mZenPanelDivider = mView.findViewById(com.android.systemui.R.id.zen_panel_divider);
mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
mZenModeCapable = !useMasterVolume && mZenController != null;
- mZenPanelDivider.setVisibility(View.GONE);
- mExpandButton.setOnClickListener(mClickListener);
- updateZenMode(mZenController == null ? false : mZenController.isZen());
+ updateZenMode(mZenController != null ? mZenController.getZen() : Global.ZEN_MODE_OFF);
mZenController.addCallback(mZenCallback);
final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
@@ -502,17 +482,7 @@
toggle(sc);
}
});
- sc.icon.setOnLongClickListener(new OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- resetTimeout();
- longToggle(sc);
- return true;
- }
- });
}
- sc.seekbarContainer =
- sc.group.findViewById(com.android.systemui.R.id.seekbar_container);
sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar);
final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
@@ -533,29 +503,19 @@
}
}
- private void longToggle(StreamControl sc) {
- if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
- mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- postVolumeChanged(sc.streamType, AudioManager.FLAG_PLAY_SOUND);
- } else {
- mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
- postVolumeChanged(sc.streamType, AudioManager.FLAG_SHOW_UI); // disable the slider
- }
- }
-
private void reorderSliders(int activeStreamType) {
mSliderPanel.removeAllViews();
final StreamControl active = mStreamControls.get(activeStreamType);
if (active == null) {
- Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
+ Log.e(TAG, "Missing stream type! - " + activeStreamType);
mActiveStreamType = -1;
} else {
mSliderPanel.addView(active.group);
mActiveStreamType = activeStreamType;
active.group.setVisibility(View.VISIBLE);
updateSlider(active);
- updateZenMode(mZenController == null ? false : mZenController.isZen());
+ setZenPanelVisible(isNotificationOrRing(mActiveStreamType));
}
}
@@ -575,6 +535,7 @@
private void updateSliderEnabled(final StreamControl sc, boolean muted, boolean fixedVolume) {
final boolean wasEnabled = sc.seekbarView.isEnabled();
+ final boolean isRinger = isNotificationOrRing(sc.streamType);
if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
// never disable touch interactions for remote playback, the muting is not tied to
// the state of the phone.
@@ -583,40 +544,37 @@
(sc.streamType != mAudioManager.getMasterStreamType() && muted) ||
(sConfirmSafeVolumeDialog != null)) {
sc.seekbarView.setEnabled(false);
- } else if (isNotificationOrRing(sc.streamType)
- && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
+ } else if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
sc.seekbarView.setEnabled(false);
+ sc.icon.setEnabled(false);
+ sc.icon.setClickable(false);
} else {
sc.seekbarView.setEnabled(true);
+ sc.icon.setEnabled(true);
}
- // pulse the ringer icon when the disabled slider is touched in silent mode
- if (sc.icon.isClickable() && wasEnabled != sc.seekbarView.isEnabled()) {
+ // show the silent hint when the disabled slider is touched in silent mode
+ if (isRinger && wasEnabled != sc.seekbarView.isEnabled()) {
if (sc.seekbarView.isEnabled()) {
- sc.seekbarContainer.setOnTouchListener(null);
+ sc.group.setOnTouchListener(null);
+ sc.icon.setClickable(true);
} else {
- sc.seekbarContainer.setOnTouchListener(new View.OnTouchListener() {
+ final View.OnTouchListener showHintOnTouch = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
resetTimeout();
- pulseIcon(sc.icon);
+ showSilentHint();
return false;
}
- });
+ };
+ sc.group.setOnTouchListener(showHintOnTouch);
}
}
}
- private void pulseIcon(final ImageView icon) {
- if (icon.getScaleX() != 1) return; // already running
- icon.animate().cancel();
- icon.animate().scaleX(ICON_PULSE_SCALE).scaleY(ICON_PULSE_SCALE)
- .setInterpolator(mFastOutSlowInInterpolator)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- icon.animate().scaleX(1).scaleY(1).setListener(null);
- }
- });
+ private void showSilentHint() {
+ if (mZenPanel != null) {
+ mZenPanel.showSilentHint();
+ }
}
private static boolean isNotificationOrRing(int streamType) {
@@ -624,47 +582,45 @@
|| streamType == AudioManager.STREAM_NOTIFICATION;
}
- public void setZenModePanelCallback(ZenModePanel.Callback callback) {
- mZenPanelCallback = callback;
+ public void setCallback(Callback callback) {
+ mCallback = callback;
}
- private void expand() {
- if (LOGD) Log.d(mTag, "expand mZenPanel=" + mZenPanel);
- if (mZenPanel == null) {
- mZenPanel = (ZenModePanel) mZenPanelStub.inflate();
- final boolean isDialog = mDialog != null;
- mZenPanel.init(mZenController, isDialog ? 'D' : 'E', isDialog);
- mZenPanel.setCallback(new ZenModePanel.Callback() {
- @Override
- public void onMoreSettings() {
- if (mZenPanelCallback != null) {
- mZenPanelCallback.onMoreSettings();
+ private void setZenPanelVisible(boolean visible) {
+ if (LOGD) Log.d(mTag, "setZenPanelVisible " + visible + " mZenPanel=" + mZenPanel);
+ if (visible) {
+ if (mZenPanel == null) {
+ mZenPanel = (ZenModePanel) mZenPanelStub.inflate();
+ mZenPanel.init(mZenController, mDialog != null ? 'D' : 'E');
+ mZenPanel.setCallback(new ZenModePanel.Callback() {
+ @Override
+ public void onMoreSettings() {
+ if (mCallback != null) {
+ mCallback.onZenSettings();
+ }
}
- }
- @Override
- public void onInteraction() {
- resetTimeout();
- if (mZenPanelCallback != null) {
- mZenPanelCallback.onInteraction();
+ @Override
+ public void onInteraction() {
+ resetTimeout();
}
- }
- });
- }
- mZenPanel.setVisibility(View.VISIBLE);
- mZenPanelDivider.setVisibility(View.VISIBLE);
- mTimeoutDelay = TIMEOUT_DELAY_EXPANDED;
- resetTimeout();
- }
- private void collapse() {
- if (LOGD) Log.d(mTag, "collapse mZenPanel=" + mZenPanel);
- if (mZenPanel != null) {
- mZenPanel.setVisibility(View.GONE);
+ @Override
+ public void onExpanded(boolean expanded) {
+ mTimeoutDelay = expanded ? TIMEOUT_DELAY_EXPANDED : TIMEOUT_DELAY;
+ resetTimeout();
+ }
+ });
+ }
+ mZenPanel.setVisibility(View.VISIBLE);
+ resetTimeout();
+ } else {
+ if (mZenPanel != null) {
+ mZenPanel.setVisibility(View.GONE);
+ }
+ mTimeoutDelay = TIMEOUT_DELAY;
+ resetTimeout();
}
- mZenPanelDivider.setVisibility(View.GONE);
- mTimeoutDelay = TIMEOUT_DELAY;
- resetTimeout();
}
public void updateStates() {
@@ -675,25 +631,14 @@
}
}
- private void updateZenMode(boolean zen) {
- if (mZenModeCapable) {
- final boolean show = isNotificationOrRing(mActiveStreamType);
- mExpandButton.setVisibility(show ? View.VISIBLE : View.GONE);
- mExpandDivider.setVisibility(show ? View.VISIBLE : View.GONE);
- mExpandButton.setImageResource(zen ? com.android.systemui.R.drawable.ic_vol_zen_on
- : com.android.systemui.R.drawable.ic_vol_zen_off);
- if (show && !zen) {
- collapse();
- }
- } else {
- mExpandButton.setVisibility(View.GONE);
- mExpandDivider.setVisibility(View.GONE);
- }
+ private void updateZenMode(int zen) {
+ final boolean show = mZenModeCapable && isNotificationOrRing(mActiveStreamType);
+ setZenPanelVisible(show);
}
- public void postZenModeChanged(boolean zen) {
+ public void postZenModeChanged(int zen) {
removeMessages(MSG_ZEN_MODE_CHANGED);
- obtainMessage(MSG_ZEN_MODE_CHANGED, zen ? 1 : 0, 0).sendToTarget();
+ obtainMessage(MSG_ZEN_MODE_CHANGED, zen).sendToTarget();
}
public void postVolumeChanged(int streamType, int flags) {
@@ -955,8 +900,8 @@
}
// Pulse the slider icon if an adjustment was suppressed due to silent mode.
- if (sc != null && (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
- pulseIcon(sc.icon);
+ if ((flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
+ showSilentHint();
}
}
@@ -1233,15 +1178,23 @@
break;
case MSG_ZEN_MODE_CHANGED:
- updateZenMode(msg.arg1 != 0);
+ updateZenMode(msg.arg1);
+ break;
+
+ case MSG_USER_ACTIVITY:
+ if (mCallback != null) {
+ mCallback.onInteraction();
+ }
break;
}
}
- public void resetTimeout() {
+ private void resetTimeout() {
if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis());
removeMessages(MSG_TIMEOUT);
sendEmptyMessageDelayed(MSG_TIMEOUT, mTimeoutDelay);
+ removeMessages(MSG_USER_ACTIVITY);
+ sendEmptyMessage(MSG_USER_ACTIVITY);
}
private void forceTimeout() {
@@ -1273,29 +1226,8 @@
}
};
- private final View.OnClickListener mClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (v == mExpandButton && mZenController != null) {
- final boolean newZen = !mZenController.isZen();
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- mZenController.setZen(newZen);
- }
- });
- if (newZen) {
- expand();
- } else {
- collapse();
- }
- }
- resetTimeout();
- }
- };
-
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
- public void onZenChanged(boolean zen) {
+ public void onZenChanged(int zen) {
postZenModeChanged(zen);
}
};
@@ -1305,4 +1237,9 @@
onRemoteVolumeUpdateIfShown();
}
};
+
+ public interface Callback {
+ void onZenSettings();
+ void onInteraction();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index c1f92ff..51be833 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -1,8 +1,8 @@
package com.android.systemui.volume;
+import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.media.IRemoteVolumeController;
@@ -17,8 +17,8 @@
import android.provider.Settings;
import android.util.Log;
-import com.android.systemui.R;
import com.android.systemui.SystemUI;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
@@ -80,17 +80,19 @@
private void initPanel() {
mPanel = new VolumePanel(mContext, null, new ZenModeControllerImpl(mContext, mHandler));
- final int delay = mContext.getResources().getInteger(R.integer.feedback_start_delay);
- mPanel.setZenModePanelCallback(new ZenModePanel.Callback() {
+ mPanel.setCallback(new VolumePanel.Callback() {
@Override
- public void onMoreSettings() {
+ public void onZenSettings() {
mHandler.removeCallbacks(mStartZenSettings);
- mHandler.postDelayed(mStartZenSettings, delay);
+ mHandler.post(mStartZenSettings);
}
@Override
public void onInteraction() {
- mDialogPanel.resetTimeout();
+ final KeyguardViewMediator kvm = getComponent(KeyguardViewMediator.class);
+ if (kvm != null) {
+ kvm.userActivity();
+ }
}
});
mDialogPanel = mPanel;
@@ -108,6 +110,11 @@
@Override
public void run() {
mDialogPanel.postDismiss();
+ try {
+ // Dismiss the lock screen when Settings starts.
+ ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+ } catch (RemoteException e) {
+ }
final Intent intent = ZenModePanel.ZEN_SETTINGS;
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 9917944..afa5bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -16,6 +16,8 @@
package com.android.systemui.volume;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -25,6 +27,7 @@
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.util.AttributeSet;
@@ -32,7 +35,8 @@
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
@@ -47,12 +51,19 @@
import java.util.Objects;
public class ZenModePanel extends LinearLayout {
- private static final boolean DEBUG = false;
+ private static final String TAG = "ZenModePanel";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
+ private static final int[] MINUTE_BUCKETS = DEBUG
+ ? new int[] { 1, 2, 5, 15, 30, 45, 60, 120, 180, 240, 480 }
+ : new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
+ private static final int FOREVER_CONDITION_INDEX = 0;
+ private static final int TIME_CONDITION_INDEX = 1;
+ private static final int FIRST_CONDITION_INDEX = 2;
+ private static final float SILENT_HINT_PULSE_SCALE = 1.1f;
private static final int SECONDS_MS = 1000;
private static final int MINUTES_MS = 60 * SECONDS_MS;
@@ -63,73 +74,110 @@
private final LayoutInflater mInflater;
private final H mHandler = new H();
private final Favorites mFavorites;
+ private final Interpolator mFastOutSlowInInterpolator;
private char mLogTag = '?';
private String mTag;
- private LinearLayout mConditions;
+
+ private SegmentedButtons mZenButtons;
+ private View mZenSubhead;
+ private TextView mZenSubheadCollapsed;
+ private TextView mZenSubheadExpanded;
private View mMoreSettings;
+ private LinearLayout mZenConditions;
+ private View mAlarmWarning;
+
private Callback mCallback;
private ZenModeController mController;
private boolean mRequestingConditions;
private Uri mExitConditionId;
private int mBucketIndex = -1;
- private boolean mShowing;
+ private boolean mExpanded;
+ private int mAttachedZen;
+ private String mExitConditionText;
public ZenModePanel(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
mFavorites = new Favorites();
mInflater = LayoutInflater.from(new ContextThemeWrapper(context, R.style.QSWhiteTheme));
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext,
+ android.R.interpolator.fast_out_slow_in);
updateTag();
if (DEBUG) Log.d(mTag, "new ZenModePanel");
}
private void updateTag() {
- mTag = "ZenModePanel/" + mLogTag + "/" + Integer.toHexString(System.identityHashCode(this));
+ mTag = TAG + "/" + mLogTag + "/" + Integer.toHexString(System.identityHashCode(this));
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mConditions = (LinearLayout) findViewById(android.R.id.content);
- mMoreSettings = findViewById(android.R.id.button2);
+
+ mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
+ mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS);
+ mZenButtons.addButton(R.string.interruption_level_priority,
+ Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF);
+ mZenButtons.setCallback(mZenButtonsCallback);
+
+ mZenSubhead = findViewById(R.id.zen_subhead);
+
+ mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
+ mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setExpanded(true);
+ fireInteraction();
+ }
+ });
+
+ mZenSubheadExpanded = (TextView) findViewById(R.id.zen_subhead_expanded);
+ mZenSubheadExpanded.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setExpanded(false);
+ fireInteraction();
+ }
+ });
+
+ mMoreSettings = findViewById(R.id.zen_more_settings);
mMoreSettings.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fireMoreSettings();
+ fireInteraction();
}
});
+
+ mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
+
+ mAlarmWarning = findViewById(R.id.zen_alarm_warning);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (DEBUG) Log.d(mTag, "onAttachedToWindow");
- final ViewGroup p = (ViewGroup) getParent();
- updateShowing(p != null && p.getVisibility() == VISIBLE);
+ mAttachedZen = getSelectedZen(-1);
+ refreshExitConditionText();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
- updateShowing(false);
+ mAttachedZen = -1;
+ setExpanded(false);
}
- @Override
- public void setVisibility(int visibility) {
- super.setVisibility(visibility);
- final boolean vis = visibility == VISIBLE;
- updateShowing(isAttachedToWindow() && vis);
- }
-
- private void updateShowing(boolean showing) {
- if (showing == mShowing) return;
- mShowing = showing;
- if (DEBUG) Log.d(mTag, "mShowing=" + mShowing);
- if (mController != null) {
- setRequestingConditions(mShowing);
- }
+ private void setExpanded(boolean expanded) {
+ if (expanded == mExpanded) return;
+ mExpanded = expanded;
+ updateWidgets();
+ setRequestingConditions(mExpanded);
+ fireExpanded();
}
/** Start or stop requesting relevant zen mode exit conditions */
@@ -149,24 +197,40 @@
timeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
}
if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex);
- bind(timeCondition, mConditions.getChildAt(0));
- handleUpdateConditions(new Condition[0]);
+ handleUpdateConditions(new Condition[0]); // ensures forever exists
+ bind(timeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
+ checkForDefault();
} else {
- mConditions.removeAllViews();
+ mZenConditions.removeAllViews();
}
}
- public void init(ZenModeController controller, char logTag, boolean moreSettings) {
+ public void init(ZenModeController controller, char logTag) {
mController = controller;
mLogTag = logTag;
updateTag();
- mExitConditionId = mController.getExitConditionId();
+ setExitConditionId(mController.getExitConditionId());
+ refreshExitConditionText();
+ mAttachedZen = getSelectedZen(-1);
+ handleUpdateZen(mController.getZen());
if (DEBUG) Log.d(mTag, "init mExitConditionId=" + mExitConditionId);
- mMoreSettings.setVisibility(moreSettings ? VISIBLE : GONE);
- mConditions.removeAllViews();
+ mZenConditions.removeAllViews();
mController.addCallback(mZenCallback);
- if (mShowing) {
- setRequestingConditions(true);
+ }
+
+ private void setExitConditionId(Uri exitConditionId) {
+ if (Objects.equals(mExitConditionId, exitConditionId)) return;
+ mExitConditionId = exitConditionId;
+ refreshExitConditionText();
+ }
+
+ private void refreshExitConditionText() {
+ if (mExitConditionId == null) {
+ mExitConditionText = mContext.getString(R.string.zen_mode_forever);
+ } else if (ZenModeConfig.isValidCountdownConditionId(mExitConditionId)) {
+ mExitConditionText = parseExistingTimeCondition(mExitConditionId).summary;
+ } else {
+ mExitConditionText = "(until condition ends)"; // TODO persist current description
}
}
@@ -174,6 +238,59 @@
mCallback = callback;
}
+ public void showSilentHint() {
+ if (DEBUG) Log.d(mTag, "showSilentHint");
+ if (mZenButtons == null || mZenButtons.getChildCount() == 0) return;
+ final View noneButton = mZenButtons.getChildAt(0);
+ if (noneButton.getScaleX() != 1) return; // already running
+ noneButton.animate().cancel();
+ noneButton.animate().scaleX(SILENT_HINT_PULSE_SCALE).scaleY(SILENT_HINT_PULSE_SCALE)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ noneButton.animate().scaleX(1).scaleY(1).setListener(null);
+ }
+ });
+ }
+
+ private void handleUpdateZen(int zen) {
+ if (mAttachedZen != -1 && mAttachedZen != zen) {
+ setExpanded(zen != Global.ZEN_MODE_OFF);
+ mAttachedZen = zen;
+ }
+ mZenButtons.setSelectedValue(zen);
+ updateWidgets();
+ }
+
+ private int getSelectedZen(int defValue) {
+ final Object zen = mZenButtons.getSelectedValue();
+ return zen != null ? (Integer) zen : defValue;
+ }
+
+ private void updateWidgets() {
+ final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
+ final boolean zenOff = zen == Global.ZEN_MODE_OFF;
+ final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+ final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
+
+ mZenSubhead.setVisibility(!zenOff ? VISIBLE : GONE);
+ mZenSubheadExpanded.setVisibility(mExpanded ? VISIBLE : GONE);
+ mZenSubheadCollapsed.setVisibility(!mExpanded ? VISIBLE : GONE);
+ mMoreSettings.setVisibility(zenImportant && mExpanded ? VISIBLE : GONE);
+ mZenConditions.setVisibility(!zenOff && mExpanded ? VISIBLE : GONE);
+ mAlarmWarning.setVisibility(zenNone && mExpanded && mController != null
+ && mController.hasNextAlarm() ? VISIBLE : GONE);
+
+ if (zenNone) {
+ mZenSubheadExpanded.setText(R.string.zen_no_interruptions);
+ mZenSubheadCollapsed.setText(mExitConditionText);
+ } else if (zenImportant) {
+ mZenSubheadExpanded.setText(R.string.zen_important_interruptions);
+ mZenSubheadCollapsed.setText(mExitConditionText);
+ }
+ }
+
private Condition parseExistingTimeCondition(Uri conditionId) {
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
if (time == 0) return null;
@@ -200,23 +317,23 @@
private void handleUpdateConditions(Condition[] conditions) {
final int newCount = conditions == null ? 0 : conditions.length;
- for (int i = mConditions.getChildCount() - 1; i > newCount; i--) {
- mConditions.removeViewAt(i);
+ if (DEBUG) Log.d(mTag, "handleUpdateConditions newCount=" + newCount);
+ for (int i = mZenConditions.getChildCount(); i >= newCount + FIRST_CONDITION_INDEX; i--) {
+ mZenConditions.removeViewAt(i);
}
+ bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX));
for (int i = 0; i < newCount; i++) {
- bind(conditions[i], mConditions.getChildAt(i + 1));
+ bind(conditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i));
}
- bind(null, mConditions.getChildAt(newCount + 1));
- checkForDefault();
}
private ConditionTag getConditionTagAt(int index) {
- return (ConditionTag) mConditions.getChildAt(index).getTag();
+ return (ConditionTag) mZenConditions.getChildAt(index).getTag();
}
private void checkForDefault() {
// are we left without anything selected? if so, set a default
- for (int i = 0; i < mConditions.getChildCount(); i++) {
+ for (int i = 0; i < mZenConditions.getChildCount(); i++) {
if (getConditionTagAt(i).rb.isChecked()) {
return;
}
@@ -224,19 +341,19 @@
if (DEBUG) Log.d(mTag, "Selecting a default");
final int favoriteIndex = mFavorites.getMinuteIndex();
if (favoriteIndex == -1) {
- getConditionTagAt(mConditions.getChildCount() - 1).rb.setChecked(true);
+ getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
} else {
final Condition c = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
mBucketIndex = favoriteIndex;
- bind(c, mConditions.getChildAt(0));
- getConditionTagAt(0).rb.setChecked(true);
+ bind(c, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
+ getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true);
}
}
private void handleExitConditionChanged(Uri exitCondition) {
- mExitConditionId = exitCondition;
+ setExitConditionId(exitCondition);
if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitConditionId);
- final int N = mConditions.getChildCount();
+ final int N = mZenConditions.getChildCount();
for (int i = 0; i < N; i++) {
final ConditionTag tag = getConditionTagAt(i);
tag.rb.setChecked(Objects.equals(tag.conditionId, exitCondition));
@@ -249,7 +366,7 @@
if (convertView == null) {
row = mInflater.inflate(R.layout.zen_mode_condition, this, false);
if (DEBUG) Log.d(mTag, "Adding new condition view for: " + condition);
- mConditions.addView(row);
+ mZenConditions.addView(row);
} else {
row = convertView;
}
@@ -264,9 +381,9 @@
tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (mShowing && isChecked) {
+ if (mExpanded && isChecked) {
if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.conditionId);
- final int N = mConditions.getChildCount();
+ final int N = mZenConditions.getChildCount();
for (int i = 0; i < N; i++) {
ConditionTag childTag = getConditionTagAt(i);
if (childTag == tag) continue;
@@ -284,7 +401,7 @@
title.setText(condition.summary);
}
title.setEnabled(enabled);
- title.setAlpha(enabled ? 1 : .5f);
+ title.setAlpha(enabled ? 1 : .4f);
final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
@@ -365,7 +482,7 @@
if (mController != null) {
mController.setExitConditionId(conditionId);
}
- mExitConditionId = conditionId;
+ setExitConditionId(conditionId);
if (conditionId == null) {
mFavorites.setMinuteIndex(-1);
} else if (ZenModeConfig.isValidCountdownConditionId(conditionId) && mBucketIndex != -1) {
@@ -385,8 +502,18 @@
}
}
+ private void fireExpanded() {
+ if (mCallback != null) {
+ mCallback.onExpanded(mExpanded);
+ }
+ }
+
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
@Override
+ public void onZenChanged(int zen) {
+ mHandler.obtainMessage(H.UPDATE_ZEN, zen, 0).sendToTarget();
+ }
+ @Override
public void onConditionsChanged(Condition[] conditions) {
mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
}
@@ -400,6 +527,7 @@
private final class H extends Handler {
private static final int UPDATE_CONDITIONS = 1;
private static final int EXIT_CONDITION_CHANGED = 2;
+ private static final int UPDATE_ZEN = 3;
private H() {
super(Looper.getMainLooper());
@@ -409,8 +537,11 @@
public void handleMessage(Message msg) {
if (msg.what == UPDATE_CONDITIONS) {
handleUpdateConditions((Condition[])msg.obj);
+ checkForDefault();
} else if (msg.what == EXIT_CONDITION_CHANGED) {
handleExitConditionChanged((Uri)msg.obj);
+ } else if (msg.what == UPDATE_ZEN) {
+ handleUpdateZen(msg.arg1);
}
}
}
@@ -418,6 +549,7 @@
public interface Callback {
void onMoreSettings();
void onInteraction();
+ void onExpanded(boolean expanded);
}
// used as the view tag on condition rows
@@ -466,4 +598,15 @@
return Math.max(-1, Math.min(MINUTE_BUCKETS.length - 1, index));
}
}
+
+ private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
+ @Override
+ public void onSelected(Object value) {
+ if (value != null && mZenButtons.isShown()) {
+ if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value);
+ mController.setZen((Integer) value);
+ mController.setExitConditionId(null);
+ }
+ }
+ };
}