ZenModePanel.java revision f7d22132c2c9b83134b05aaed63a89f61c639fd9
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.systemui.volume; 18 19import android.animation.Animator; 20import android.animation.AnimatorListenerAdapter; 21import android.content.Context; 22import android.content.Intent; 23import android.content.SharedPreferences; 24import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 25import android.net.Uri; 26import android.os.Handler; 27import android.os.Looper; 28import android.os.Message; 29import android.provider.Settings; 30import android.provider.Settings.Global; 31import android.service.notification.Condition; 32import android.service.notification.ZenModeConfig; 33import android.util.AttributeSet; 34import android.util.Log; 35import android.view.ContextThemeWrapper; 36import android.view.LayoutInflater; 37import android.view.View; 38import android.view.animation.AnimationUtils; 39import android.view.animation.Interpolator; 40import android.widget.CompoundButton; 41import android.widget.CompoundButton.OnCheckedChangeListener; 42import android.widget.ImageView; 43import android.widget.LinearLayout; 44import android.widget.RadioButton; 45import android.widget.TextView; 46 47import com.android.systemui.R; 48import com.android.systemui.statusbar.policy.ZenModeController; 49 50import java.util.Arrays; 51import java.util.Objects; 52 53public class ZenModePanel extends LinearLayout { 54 private static final String TAG = "ZenModePanel"; 55 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 56 57 private static final int[] MINUTE_BUCKETS = DEBUG 58 ? new int[] { 1, 2, 5, 15, 30, 45, 60, 120, 180, 240, 480 } 59 : new int[] { 15, 30, 45, 60, 120, 180, 240, 480 }; 60 private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0]; 61 private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1]; 62 private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60); 63 private static final int FOREVER_CONDITION_INDEX = 0; 64 private static final int TIME_CONDITION_INDEX = 1; 65 private static final int FIRST_CONDITION_INDEX = 2; 66 private static final float SILENT_HINT_PULSE_SCALE = 1.1f; 67 68 private static final int SECONDS_MS = 1000; 69 private static final int MINUTES_MS = 60 * SECONDS_MS; 70 71 public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS); 72 73 private final Context mContext; 74 private final LayoutInflater mInflater; 75 private final H mHandler = new H(); 76 private final Favorites mFavorites; 77 private final Interpolator mFastOutSlowInInterpolator; 78 79 private char mLogTag = '?'; 80 private String mTag; 81 82 private SegmentedButtons mZenButtons; 83 private View mZenSubhead; 84 private TextView mZenSubheadCollapsed; 85 private TextView mZenSubheadExpanded; 86 private View mMoreSettings; 87 private LinearLayout mZenConditions; 88 private View mAlarmWarning; 89 90 private Callback mCallback; 91 private ZenModeController mController; 92 private boolean mRequestingConditions; 93 private Uri mExitConditionId; 94 private int mBucketIndex = -1; 95 private boolean mExpanded; 96 private int mAttachedZen; 97 private String mExitConditionText; 98 99 public ZenModePanel(Context context, AttributeSet attrs) { 100 super(context, attrs); 101 mContext = context; 102 mFavorites = new Favorites(); 103 mInflater = LayoutInflater.from(mContext.getApplicationContext()); 104 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext, 105 android.R.interpolator.fast_out_slow_in); 106 updateTag(); 107 if (DEBUG) Log.d(mTag, "new ZenModePanel"); 108 } 109 110 private void updateTag() { 111 mTag = TAG + "/" + mLogTag + "/" + Integer.toHexString(System.identityHashCode(this)); 112 } 113 114 @Override 115 protected void onFinishInflate() { 116 super.onFinishInflate(); 117 118 mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons); 119 mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS); 120 mZenButtons.addButton(R.string.interruption_level_priority, 121 Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); 122 mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF); 123 mZenButtons.setCallback(mZenButtonsCallback); 124 125 mZenSubhead = findViewById(R.id.zen_subhead); 126 127 mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed); 128 mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() { 129 @Override 130 public void onClick(View v) { 131 setExpanded(true); 132 fireInteraction(); 133 } 134 }); 135 136 mZenSubheadExpanded = (TextView) findViewById(R.id.zen_subhead_expanded); 137 mZenSubheadExpanded.setOnClickListener(new View.OnClickListener() { 138 @Override 139 public void onClick(View v) { 140 setExpanded(false); 141 fireInteraction(); 142 } 143 }); 144 145 mMoreSettings = findViewById(R.id.zen_more_settings); 146 mMoreSettings.setOnClickListener(new View.OnClickListener() { 147 @Override 148 public void onClick(View v) { 149 fireMoreSettings(); 150 fireInteraction(); 151 } 152 }); 153 154 mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions); 155 156 mAlarmWarning = findViewById(R.id.zen_alarm_warning); 157 } 158 159 @Override 160 protected void onAttachedToWindow() { 161 super.onAttachedToWindow(); 162 if (DEBUG) Log.d(mTag, "onAttachedToWindow"); 163 mAttachedZen = getSelectedZen(-1); 164 refreshExitConditionText(); 165 } 166 167 @Override 168 protected void onDetachedFromWindow() { 169 super.onDetachedFromWindow(); 170 if (DEBUG) Log.d(mTag, "onDetachedFromWindow"); 171 mAttachedZen = -1; 172 setExpanded(false); 173 } 174 175 private void setExpanded(boolean expanded) { 176 if (expanded == mExpanded) return; 177 mExpanded = expanded; 178 updateWidgets(); 179 setRequestingConditions(mExpanded); 180 fireExpanded(); 181 } 182 183 /** Start or stop requesting relevant zen mode exit conditions */ 184 private void setRequestingConditions(boolean requesting) { 185 if (mRequestingConditions == requesting) return; 186 if (DEBUG) Log.d(mTag, "setRequestingConditions " + requesting); 187 mRequestingConditions = requesting; 188 if (mController != null) { 189 mController.requestConditions(mRequestingConditions); 190 } 191 if (mRequestingConditions) { 192 Condition timeCondition = parseExistingTimeCondition(mExitConditionId); 193 if (timeCondition != null) { 194 mBucketIndex = -1; 195 } else { 196 mBucketIndex = DEFAULT_BUCKET_INDEX; 197 timeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]); 198 } 199 if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex); 200 handleUpdateConditions(new Condition[0]); // ensures forever exists 201 bind(timeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); 202 checkForDefault(); 203 } else { 204 mZenConditions.removeAllViews(); 205 } 206 } 207 208 public void init(ZenModeController controller, char logTag) { 209 mController = controller; 210 mLogTag = logTag; 211 updateTag(); 212 setExitConditionId(mController.getExitConditionId()); 213 refreshExitConditionText(); 214 mAttachedZen = getSelectedZen(-1); 215 handleUpdateZen(mController.getZen()); 216 if (DEBUG) Log.d(mTag, "init mExitConditionId=" + mExitConditionId); 217 mZenConditions.removeAllViews(); 218 mController.addCallback(mZenCallback); 219 } 220 221 private void setExitConditionId(Uri exitConditionId) { 222 if (Objects.equals(mExitConditionId, exitConditionId)) return; 223 mExitConditionId = exitConditionId; 224 refreshExitConditionText(); 225 } 226 227 private void refreshExitConditionText() { 228 if (mExitConditionId == null) { 229 mExitConditionText = mContext.getString(R.string.zen_mode_forever); 230 } else if (ZenModeConfig.isValidCountdownConditionId(mExitConditionId)) { 231 mExitConditionText = parseExistingTimeCondition(mExitConditionId).summary; 232 } else { 233 mExitConditionText = "(until condition ends)"; // TODO persist current description 234 } 235 } 236 237 public void setCallback(Callback callback) { 238 mCallback = callback; 239 } 240 241 public void showSilentHint() { 242 if (DEBUG) Log.d(mTag, "showSilentHint"); 243 if (mZenButtons == null || mZenButtons.getChildCount() == 0) return; 244 final View noneButton = mZenButtons.getChildAt(0); 245 if (noneButton.getScaleX() != 1) return; // already running 246 noneButton.animate().cancel(); 247 noneButton.animate().scaleX(SILENT_HINT_PULSE_SCALE).scaleY(SILENT_HINT_PULSE_SCALE) 248 .setInterpolator(mFastOutSlowInInterpolator) 249 .setListener(new AnimatorListenerAdapter() { 250 @Override 251 public void onAnimationEnd(Animator animation) { 252 noneButton.animate().scaleX(1).scaleY(1).setListener(null); 253 } 254 }); 255 } 256 257 private void handleUpdateZen(int zen) { 258 if (mAttachedZen != -1 && mAttachedZen != zen) { 259 setExpanded(zen != Global.ZEN_MODE_OFF); 260 mAttachedZen = zen; 261 } 262 mZenButtons.setSelectedValue(zen); 263 updateWidgets(); 264 } 265 266 private int getSelectedZen(int defValue) { 267 final Object zen = mZenButtons.getSelectedValue(); 268 return zen != null ? (Integer) zen : defValue; 269 } 270 271 private void updateWidgets() { 272 final int zen = getSelectedZen(Global.ZEN_MODE_OFF); 273 final boolean zenOff = zen == Global.ZEN_MODE_OFF; 274 final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; 275 final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS; 276 277 mZenSubhead.setVisibility(!zenOff ? VISIBLE : GONE); 278 mZenSubheadExpanded.setVisibility(mExpanded ? VISIBLE : GONE); 279 mZenSubheadCollapsed.setVisibility(!mExpanded ? VISIBLE : GONE); 280 mMoreSettings.setVisibility(zenImportant && mExpanded ? VISIBLE : GONE); 281 mZenConditions.setVisibility(!zenOff && mExpanded ? VISIBLE : GONE); 282 mAlarmWarning.setVisibility(zenNone && mExpanded ? VISIBLE : GONE); 283 284 if (zenNone) { 285 mZenSubheadExpanded.setText(R.string.zen_no_interruptions); 286 mZenSubheadCollapsed.setText(mExitConditionText); 287 } else if (zenImportant) { 288 mZenSubheadExpanded.setText(R.string.zen_important_interruptions); 289 mZenSubheadCollapsed.setText(mExitConditionText); 290 } 291 } 292 293 private Condition parseExistingTimeCondition(Uri conditionId) { 294 final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId); 295 if (time == 0) return null; 296 final long span = time - System.currentTimeMillis(); 297 if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null; 298 return timeCondition(time, Math.round(span / (float)MINUTES_MS)); 299 } 300 301 private Condition newTimeCondition(int minutesFromNow) { 302 final long now = System.currentTimeMillis(); 303 return timeCondition(now + minutesFromNow * MINUTES_MS, minutesFromNow); 304 } 305 306 private Condition timeCondition(long time, int minutes) { 307 final int num = minutes < 60 ? minutes : Math.round(minutes / 60f); 308 final int resId = minutes < 60 309 ? R.plurals.zen_mode_duration_minutes 310 : R.plurals.zen_mode_duration_hours; 311 final String caption = mContext.getResources().getQuantityString(resId, num, num); 312 final Uri id = ZenModeConfig.toCountdownConditionId(time); 313 return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE, 314 Condition.FLAG_RELEVANT_NOW); 315 } 316 317 private void handleUpdateConditions(Condition[] conditions) { 318 final int newCount = conditions == null ? 0 : conditions.length; 319 if (DEBUG) Log.d(mTag, "handleUpdateConditions newCount=" + newCount); 320 for (int i = mZenConditions.getChildCount(); i >= newCount + FIRST_CONDITION_INDEX; i--) { 321 mZenConditions.removeViewAt(i); 322 } 323 bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX)); 324 for (int i = 0; i < newCount; i++) { 325 bind(conditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i)); 326 } 327 } 328 329 private ConditionTag getConditionTagAt(int index) { 330 return (ConditionTag) mZenConditions.getChildAt(index).getTag(); 331 } 332 333 private void checkForDefault() { 334 // are we left without anything selected? if so, set a default 335 for (int i = 0; i < mZenConditions.getChildCount(); i++) { 336 if (getConditionTagAt(i).rb.isChecked()) { 337 return; 338 } 339 } 340 if (DEBUG) Log.d(mTag, "Selecting a default"); 341 final int favoriteIndex = mFavorites.getMinuteIndex(); 342 if (favoriteIndex == -1) { 343 getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true); 344 } else { 345 final Condition c = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]); 346 mBucketIndex = favoriteIndex; 347 bind(c, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); 348 getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true); 349 } 350 } 351 352 private void handleExitConditionChanged(Uri exitCondition) { 353 setExitConditionId(exitCondition); 354 if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitConditionId); 355 final int N = mZenConditions.getChildCount(); 356 for (int i = 0; i < N; i++) { 357 final ConditionTag tag = getConditionTagAt(i); 358 tag.rb.setChecked(Objects.equals(tag.conditionId, exitCondition)); 359 } 360 } 361 362 private void bind(final Condition condition, View convertView) { 363 final boolean enabled = condition == null || condition.state == Condition.STATE_TRUE; 364 final View row; 365 if (convertView == null) { 366 row = mInflater.inflate(R.layout.zen_mode_condition, this, false); 367 if (DEBUG) Log.d(mTag, "Adding new condition view for: " + condition); 368 mZenConditions.addView(row); 369 } else { 370 row = convertView; 371 } 372 final ConditionTag tag = 373 row.getTag() != null ? (ConditionTag) row.getTag() : new ConditionTag(); 374 row.setTag(tag); 375 if (tag.rb == null) { 376 tag.rb = (RadioButton) row.findViewById(android.R.id.checkbox); 377 } 378 tag.conditionId = condition != null ? condition.id : null; 379 tag.rb.setEnabled(enabled); 380 tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() { 381 @Override 382 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 383 if (mExpanded && isChecked) { 384 if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.conditionId); 385 final int N = mZenConditions.getChildCount(); 386 for (int i = 0; i < N; i++) { 387 ConditionTag childTag = getConditionTagAt(i); 388 if (childTag == tag) continue; 389 childTag.rb.setChecked(false); 390 } 391 select(tag.conditionId); 392 fireInteraction(); 393 } 394 } 395 }); 396 final TextView title = (TextView) row.findViewById(android.R.id.title); 397 if (condition == null) { 398 title.setText(R.string.zen_mode_forever); 399 } else { 400 title.setText(condition.summary); 401 } 402 title.setEnabled(enabled); 403 title.setAlpha(enabled ? 1 : .4f); 404 final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1); 405 button1.setOnClickListener(new OnClickListener() { 406 @Override 407 public void onClick(View v) { 408 onClickTimeButton(row, tag, false /*down*/); 409 } 410 }); 411 412 final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2); 413 button2.setOnClickListener(new OnClickListener() { 414 @Override 415 public void onClick(View v) { 416 onClickTimeButton(row, tag, true /*up*/); 417 } 418 }); 419 title.setOnClickListener(new OnClickListener() { 420 @Override 421 public void onClick(View v) { 422 tag.rb.setChecked(true); 423 fireInteraction(); 424 } 425 }); 426 427 final long time = ZenModeConfig.tryParseCountdownConditionId(tag.conditionId); 428 if (time > 0) { 429 if (mBucketIndex > -1) { 430 button1.setEnabled(mBucketIndex > 0); 431 button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1); 432 } else { 433 final long span = time - System.currentTimeMillis(); 434 button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS); 435 final Condition maxCondition = newTimeCondition(MAX_BUCKET_MINUTES); 436 button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary)); 437 } 438 439 button1.setAlpha(button1.isEnabled() ? 1f : .5f); 440 button2.setAlpha(button2.isEnabled() ? 1f : .5f); 441 } else { 442 button1.setVisibility(View.GONE); 443 button2.setVisibility(View.GONE); 444 } 445 } 446 447 private void onClickTimeButton(View row, ConditionTag tag, boolean up) { 448 Condition newCondition = null; 449 final int N = MINUTE_BUCKETS.length; 450 if (mBucketIndex == -1) { 451 // not on a known index, search for the next or prev bucket by time 452 final long time = ZenModeConfig.tryParseCountdownConditionId(tag.conditionId); 453 final long now = System.currentTimeMillis(); 454 for (int i = 0; i < N; i++) { 455 int j = up ? i : N - 1 - i; 456 final int bucketMinutes = MINUTE_BUCKETS[j]; 457 final long bucketTime = now + bucketMinutes * MINUTES_MS; 458 if (up && bucketTime > time || !up && bucketTime < time) { 459 mBucketIndex = j; 460 newCondition = timeCondition(bucketTime, bucketMinutes); 461 break; 462 } 463 } 464 if (newCondition == null) { 465 mBucketIndex = DEFAULT_BUCKET_INDEX; 466 newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]); 467 } 468 } else { 469 // on a known index, simply increment or decrement 470 mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1))); 471 newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]); 472 } 473 bind(newCondition, row); 474 tag.rb.setChecked(true); 475 select(newCondition.id); 476 fireInteraction(); 477 } 478 479 private void select(Uri conditionId) { 480 if (DEBUG) Log.d(mTag, "select " + conditionId); 481 if (mController != null) { 482 mController.setExitConditionId(conditionId); 483 } 484 setExitConditionId(conditionId); 485 if (conditionId == null) { 486 mFavorites.setMinuteIndex(-1); 487 } else if (ZenModeConfig.isValidCountdownConditionId(conditionId) && mBucketIndex != -1) { 488 mFavorites.setMinuteIndex(mBucketIndex); 489 } 490 } 491 492 private void fireMoreSettings() { 493 if (mCallback != null) { 494 mCallback.onMoreSettings(); 495 } 496 } 497 498 private void fireInteraction() { 499 if (mCallback != null) { 500 mCallback.onInteraction(); 501 } 502 } 503 504 private void fireExpanded() { 505 if (mCallback != null) { 506 mCallback.onExpanded(mExpanded); 507 } 508 } 509 510 private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() { 511 @Override 512 public void onZenChanged(int zen) { 513 mHandler.obtainMessage(H.UPDATE_ZEN, zen, 0).sendToTarget(); 514 } 515 @Override 516 public void onConditionsChanged(Condition[] conditions) { 517 mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget(); 518 } 519 520 @Override 521 public void onExitConditionChanged(Uri exitConditionId) { 522 mHandler.obtainMessage(H.EXIT_CONDITION_CHANGED, exitConditionId).sendToTarget(); 523 } 524 }; 525 526 private final class H extends Handler { 527 private static final int UPDATE_CONDITIONS = 1; 528 private static final int EXIT_CONDITION_CHANGED = 2; 529 private static final int UPDATE_ZEN = 3; 530 531 private H() { 532 super(Looper.getMainLooper()); 533 } 534 535 @Override 536 public void handleMessage(Message msg) { 537 if (msg.what == UPDATE_CONDITIONS) { 538 handleUpdateConditions((Condition[])msg.obj); 539 checkForDefault(); 540 } else if (msg.what == EXIT_CONDITION_CHANGED) { 541 handleExitConditionChanged((Uri)msg.obj); 542 } else if (msg.what == UPDATE_ZEN) { 543 handleUpdateZen(msg.arg1); 544 } 545 } 546 } 547 548 public interface Callback { 549 void onMoreSettings(); 550 void onInteraction(); 551 void onExpanded(boolean expanded); 552 } 553 554 // used as the view tag on condition rows 555 private static class ConditionTag { 556 RadioButton rb; 557 Uri conditionId; 558 } 559 560 private final class Favorites implements OnSharedPreferenceChangeListener { 561 private static final String KEY_MINUTE_INDEX = "minuteIndex"; 562 563 private int mMinuteIndex; 564 565 private Favorites() { 566 prefs().registerOnSharedPreferenceChangeListener(this); 567 updateMinuteIndex(); 568 } 569 570 public int getMinuteIndex() { 571 return mMinuteIndex; 572 } 573 574 public void setMinuteIndex(int minuteIndex) { 575 minuteIndex = clamp(minuteIndex); 576 if (minuteIndex == mMinuteIndex) return; 577 mMinuteIndex = clamp(minuteIndex); 578 if (DEBUG) Log.d(mTag, "Setting favorite minute index: " + mMinuteIndex); 579 prefs().edit().putInt(KEY_MINUTE_INDEX, mMinuteIndex).apply(); 580 } 581 582 @Override 583 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { 584 updateMinuteIndex(); 585 } 586 587 private SharedPreferences prefs() { 588 return mContext.getSharedPreferences(ZenModePanel.class.getSimpleName(), 0); 589 } 590 591 private void updateMinuteIndex() { 592 mMinuteIndex = clamp(prefs().getInt(KEY_MINUTE_INDEX, DEFAULT_BUCKET_INDEX)); 593 if (DEBUG) Log.d(mTag, "Favorite minute index: " + mMinuteIndex); 594 } 595 596 private int clamp(int index) { 597 return Math.max(-1, Math.min(MINUTE_BUCKETS.length - 1, index)); 598 } 599 } 600 601 private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() { 602 @Override 603 public void onSelected(Object value) { 604 if (value != null && mZenButtons.isShown()) { 605 if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value); 606 mController.setZen((Integer) value); 607 mController.setExitConditionId(null); 608 } 609 } 610 }; 611} 612