1/* 2 * Copyright (C) 2010 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.statusbar.tablet; 18 19import android.animation.LayoutTransition; 20import android.animation.ObjectAnimator; 21import android.app.ActivityManager; 22import android.app.ActivityManagerNative; 23import android.app.Notification; 24import android.app.PendingIntent; 25import android.app.StatusBarManager; 26import android.content.BroadcastReceiver; 27import android.content.Context; 28import android.content.Intent; 29import android.content.IntentFilter; 30import android.content.SharedPreferences; 31import android.content.res.Configuration; 32import android.content.res.Resources; 33import android.graphics.PixelFormat; 34import android.graphics.Point; 35import android.graphics.drawable.Drawable; 36import android.graphics.drawable.LayerDrawable; 37import android.inputmethodservice.InputMethodService; 38import android.os.IBinder; 39import android.os.Message; 40import android.os.RemoteException; 41import android.os.ServiceManager; 42import android.text.TextUtils; 43import android.util.Slog; 44import android.view.Display; 45import android.view.Gravity; 46import android.view.IWindowManager; 47import android.view.KeyEvent; 48import android.view.MotionEvent; 49import android.view.SoundEffectConstants; 50import android.view.VelocityTracker; 51import android.view.View; 52import android.view.ViewConfiguration; 53import android.view.ViewGroup; 54import android.view.ViewGroup.LayoutParams; 55import android.view.WindowManager; 56import android.view.WindowManagerImpl; 57import android.view.accessibility.AccessibilityEvent; 58import android.widget.ImageView; 59import android.widget.LinearLayout; 60import android.widget.RemoteViews; 61import android.widget.ScrollView; 62import android.widget.TextView; 63 64import com.android.internal.statusbar.StatusBarIcon; 65import com.android.internal.statusbar.StatusBarNotification; 66import com.android.systemui.R; 67import com.android.systemui.recent.RecentTasksLoader; 68import com.android.systemui.recent.RecentsPanelView; 69import com.android.systemui.statusbar.BaseStatusBar; 70import com.android.systemui.statusbar.CommandQueue; 71import com.android.systemui.statusbar.DoNotDisturb; 72import com.android.systemui.statusbar.NotificationData; 73import com.android.systemui.statusbar.SignalClusterView; 74import com.android.systemui.statusbar.StatusBarIconView; 75import com.android.systemui.statusbar.NotificationData.Entry; 76import com.android.systemui.statusbar.policy.BatteryController; 77import com.android.systemui.statusbar.policy.BluetoothController; 78import com.android.systemui.statusbar.policy.CompatModeButton; 79import com.android.systemui.statusbar.policy.LocationController; 80import com.android.systemui.statusbar.policy.NetworkController; 81import com.android.systemui.statusbar.policy.NotificationRowLayout; 82import com.android.systemui.statusbar.policy.Prefs; 83 84import java.io.FileDescriptor; 85import java.io.PrintWriter; 86import java.util.ArrayList; 87 88public class TabletStatusBar extends BaseStatusBar implements 89 InputMethodsPanel.OnHardKeyboardEnabledChangeListener, 90 RecentsPanelView.OnRecentsPanelVisibilityChangedListener { 91 public static final boolean DEBUG = false; 92 public static final boolean DEBUG_COMPAT_HELP = false; 93 public static final String TAG = "TabletStatusBar"; 94 95 96 public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; 97 public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001; 98 public static final int MSG_OPEN_NOTIFICATION_PEEK = 1002; 99 public static final int MSG_CLOSE_NOTIFICATION_PEEK = 1003; 100 // 1020-1029 reserved for BaseStatusBar 101 public static final int MSG_SHOW_CHROME = 1030; 102 public static final int MSG_HIDE_CHROME = 1031; 103 public static final int MSG_OPEN_INPUT_METHODS_PANEL = 1040; 104 public static final int MSG_CLOSE_INPUT_METHODS_PANEL = 1041; 105 public static final int MSG_OPEN_COMPAT_MODE_PANEL = 1050; 106 public static final int MSG_CLOSE_COMPAT_MODE_PANEL = 1051; 107 public static final int MSG_STOP_TICKER = 2000; 108 109 // Fitts' Law assistance for LatinIME; see policy.EventHole 110 private static final boolean FAKE_SPACE_BAR = true; 111 112 // Notification "peeking" (flyover preview of individual notifications) 113 final static int NOTIFICATION_PEEK_HOLD_THRESH = 200; // ms 114 final static int NOTIFICATION_PEEK_FADE_DELAY = 3000; // ms 115 116 private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService 117 private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER; 118 119 // The height of the bar, as definied by the build. It may be taller if we're plugged 120 // into hdmi. 121 int mNaturalBarHeight = -1; 122 int mIconSize = -1; 123 int mIconHPadding = -1; 124 int mNavIconWidth = -1; 125 int mMenuNavIconWidth = -1; 126 private int mMaxNotificationIcons = 5; 127 128 IWindowManager mWindowManager; 129 130 TabletStatusBarView mStatusBarView; 131 View mNotificationArea; 132 View mNotificationTrigger; 133 NotificationIconArea mNotificationIconArea; 134 ViewGroup mNavigationArea; 135 136 boolean mNotificationDNDMode; 137 NotificationData.Entry mNotificationDNDDummyEntry; 138 139 ImageView mBackButton; 140 View mHomeButton; 141 View mMenuButton; 142 View mRecentButton; 143 private boolean mAltBackButtonEnabledForIme; 144 145 ViewGroup mFeedbackIconArea; // notification icons, IME icon, compat icon 146 InputMethodButton mInputMethodSwitchButton; 147 CompatModeButton mCompatModeButton; 148 149 NotificationPanel mNotificationPanel; 150 WindowManager.LayoutParams mNotificationPanelParams; 151 NotificationPeekPanel mNotificationPeekWindow; 152 ViewGroup mNotificationPeekRow; 153 int mNotificationPeekIndex; 154 IBinder mNotificationPeekKey; 155 LayoutTransition mNotificationPeekScrubLeft, mNotificationPeekScrubRight; 156 157 int mNotificationPeekTapDuration; 158 int mNotificationFlingVelocity; 159 160 BatteryController mBatteryController; 161 BluetoothController mBluetoothController; 162 LocationController mLocationController; 163 NetworkController mNetworkController; 164 DoNotDisturb mDoNotDisturb; 165 166 ViewGroup mBarContents; 167 168 // hide system chrome ("lights out") support 169 View mShadow; 170 171 NotificationIconArea.IconLayout mIconLayout; 172 173 TabletTicker mTicker; 174 175 View mFakeSpaceBar; 176 KeyEvent mSpaceBarKeyEvent = null; 177 178 View mCompatibilityHelpDialog = null; 179 180 // for disabling the status bar 181 int mDisabled = 0; 182 183 private InputMethodsPanel mInputMethodsPanel; 184 private CompatModePanel mCompatModePanel; 185 186 private int mSystemUiVisibility = 0; 187 188 private int mNavigationIconHints = 0; 189 190 private int mShowSearchHoldoff = 0; 191 192 public Context getContext() { return mContext; } 193 194 private Runnable mShowSearchPanel = new Runnable() { 195 public void run() { 196 showSearchPanel(); 197 } 198 }; 199 200 private View.OnTouchListener mHomeSearchActionListener = new View.OnTouchListener() { 201 public boolean onTouch(View v, MotionEvent event) { 202 switch(event.getAction()) { 203 case MotionEvent.ACTION_DOWN: 204 if (!shouldDisableNavbarGestures() && !inKeyguardRestrictedInputMode()) { 205 mHandler.removeCallbacks(mShowSearchPanel); 206 mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff); 207 } 208 break; 209 210 case MotionEvent.ACTION_UP: 211 case MotionEvent.ACTION_CANCEL: 212 mHandler.removeCallbacks(mShowSearchPanel); 213 break; 214 } 215 return false; 216 } 217 }; 218 219 @Override 220 protected void createAndAddWindows() { 221 addStatusBarWindow(); 222 addPanelWindows(); 223 } 224 225 private void addStatusBarWindow() { 226 final View sb = makeStatusBarView(); 227 228 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 229 ViewGroup.LayoutParams.MATCH_PARENT, 230 ViewGroup.LayoutParams.MATCH_PARENT, 231 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, 232 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 233 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING 234 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 235 // We use a pixel format of RGB565 for the status bar to save memory bandwidth and 236 // to ensure that the layer can be handled by HWComposer. On some devices the 237 // HWComposer is unable to handle SW-rendered RGBX_8888 layers. 238 PixelFormat.RGB_565); 239 240 // We explicitly leave FLAG_HARDWARE_ACCELERATED out of the flags. The status bar occupies 241 // very little screen real-estate and is updated fairly frequently. By using CPU rendering 242 // for the status bar, we prevent the GPU from having to wake up just to do these small 243 // updates, which should help keep power consumption down. 244 245 lp.gravity = getStatusBarGravity(); 246 lp.setTitle("SystemBar"); 247 lp.packageName = mContext.getPackageName(); 248 WindowManagerImpl.getDefault().addView(sb, lp); 249 } 250 251 protected void addPanelWindows() { 252 final Context context = mContext; 253 final Resources res = mContext.getResources(); 254 255 // Notification Panel 256 mNotificationPanel = (NotificationPanel)View.inflate(context, 257 R.layout.system_bar_notification_panel, null); 258 mNotificationPanel.setBar(this); 259 mNotificationPanel.show(false, false); 260 mNotificationPanel.setOnTouchListener( 261 new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PANEL, mNotificationPanel)); 262 263 // the battery icon 264 mBatteryController.addIconView((ImageView)mNotificationPanel.findViewById(R.id.battery)); 265 mBatteryController.addLabelView( 266 (TextView)mNotificationPanel.findViewById(R.id.battery_text)); 267 268 // Bt 269 mBluetoothController.addIconView( 270 (ImageView)mNotificationPanel.findViewById(R.id.bluetooth)); 271 272 // network icons: either a combo icon that switches between mobile and data, or distinct 273 // mobile and data icons 274 final ImageView mobileRSSI = 275 (ImageView)mNotificationPanel.findViewById(R.id.mobile_signal); 276 if (mobileRSSI != null) { 277 mNetworkController.addPhoneSignalIconView(mobileRSSI); 278 } 279 final ImageView wifiRSSI = 280 (ImageView)mNotificationPanel.findViewById(R.id.wifi_signal); 281 if (wifiRSSI != null) { 282 mNetworkController.addWifiIconView(wifiRSSI); 283 } 284 mNetworkController.addWifiLabelView( 285 (TextView)mNotificationPanel.findViewById(R.id.wifi_text)); 286 287 mNetworkController.addDataTypeIconView( 288 (ImageView)mNotificationPanel.findViewById(R.id.mobile_type)); 289 mNetworkController.addMobileLabelView( 290 (TextView)mNotificationPanel.findViewById(R.id.mobile_text)); 291 mNetworkController.addCombinedLabelView( 292 (TextView)mBarContents.findViewById(R.id.network_text)); 293 294 mStatusBarView.setIgnoreChildren(0, mNotificationTrigger, mNotificationPanel); 295 296 WindowManager.LayoutParams lp = mNotificationPanelParams = new WindowManager.LayoutParams( 297 res.getDimensionPixelSize(R.dimen.notification_panel_width), 298 getNotificationPanelHeight(), 299 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, 300 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 301 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 302 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 303 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH 304 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, 305 PixelFormat.TRANSLUCENT); 306 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; 307 lp.setTitle("NotificationPanel"); 308 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 309 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 310 lp.windowAnimations = com.android.internal.R.style.Animation; // == no animation 311// lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade 312 313 WindowManagerImpl.getDefault().addView(mNotificationPanel, lp); 314 315 // Recents Panel 316 mRecentTasksLoader = new RecentTasksLoader(context); 317 updateRecentsPanel(); 318 319 // Search Panel 320 mStatusBarView.setBar(this); 321 mHomeButton.setOnTouchListener(mHomeSearchActionListener); 322 updateSearchPanel(); 323 324 // Input methods Panel 325 mInputMethodsPanel = (InputMethodsPanel) View.inflate(context, 326 R.layout.system_bar_input_methods_panel, null); 327 mInputMethodsPanel.setHardKeyboardEnabledChangeListener(this); 328 mInputMethodsPanel.setOnTouchListener(new TouchOutsideListener( 329 MSG_CLOSE_INPUT_METHODS_PANEL, mInputMethodsPanel)); 330 mInputMethodsPanel.setImeSwitchButton(mInputMethodSwitchButton); 331 mStatusBarView.setIgnoreChildren(2, mInputMethodSwitchButton, mInputMethodsPanel); 332 lp = new WindowManager.LayoutParams( 333 ViewGroup.LayoutParams.WRAP_CONTENT, 334 ViewGroup.LayoutParams.WRAP_CONTENT, 335 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, 336 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 337 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 338 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH 339 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, 340 PixelFormat.TRANSLUCENT); 341 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; 342 lp.setTitle("InputMethodsPanel"); 343 lp.windowAnimations = R.style.Animation_RecentPanel; 344 345 WindowManagerImpl.getDefault().addView(mInputMethodsPanel, lp); 346 347 // Compatibility mode selector panel 348 mCompatModePanel = (CompatModePanel) View.inflate(context, 349 R.layout.system_bar_compat_mode_panel, null); 350 mCompatModePanel.setOnTouchListener(new TouchOutsideListener( 351 MSG_CLOSE_COMPAT_MODE_PANEL, mCompatModePanel)); 352 mCompatModePanel.setTrigger(mCompatModeButton); 353 mCompatModePanel.setVisibility(View.GONE); 354 mStatusBarView.setIgnoreChildren(3, mCompatModeButton, mCompatModePanel); 355 lp = new WindowManager.LayoutParams( 356 250, 357 ViewGroup.LayoutParams.WRAP_CONTENT, 358 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, 359 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 360 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 361 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH 362 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, 363 PixelFormat.TRANSLUCENT); 364 lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; 365 lp.setTitle("CompatModePanel"); 366 lp.windowAnimations = android.R.style.Animation_Dialog; 367 368 WindowManagerImpl.getDefault().addView(mCompatModePanel, lp); 369 370 mRecentButton.setOnTouchListener(mRecentsPanel); 371 372 mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content); 373 mPile.removeAllViews(); 374 mPile.setLongPressListener(getNotificationLongClicker()); 375 376 ScrollView scroller = (ScrollView)mPile.getParent(); 377 scroller.setFillViewport(true); 378 } 379 380 @Override 381 protected int getExpandedViewMaxHeight() { 382 return getNotificationPanelHeight(); 383 } 384 385 private int getNotificationPanelHeight() { 386 final Resources res = mContext.getResources(); 387 final Display d = WindowManagerImpl.getDefault().getDefaultDisplay(); 388 final Point size = new Point(); 389 d.getRealSize(size); 390 return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height), size.y); 391 } 392 393 @Override 394 public void start() { 395 super.start(); // will add the main bar view 396 } 397 398 @Override 399 protected void onConfigurationChanged(Configuration newConfig) { 400 loadDimens(); 401 mNotificationPanelParams.height = getNotificationPanelHeight(); 402 WindowManagerImpl.getDefault().updateViewLayout(mNotificationPanel, 403 mNotificationPanelParams); 404 mRecentsPanel.updateValuesFromResources(); 405 mShowSearchHoldoff = mContext.getResources().getInteger( 406 R.integer.config_show_search_delay); 407 updateSearchPanel(); 408 } 409 410 protected void loadDimens() { 411 final Resources res = mContext.getResources(); 412 413 mNaturalBarHeight = res.getDimensionPixelSize( 414 com.android.internal.R.dimen.navigation_bar_height); 415 416 int newIconSize = res.getDimensionPixelSize( 417 com.android.internal.R.dimen.system_bar_icon_size); 418 int newIconHPadding = res.getDimensionPixelSize( 419 R.dimen.status_bar_icon_padding); 420 int newNavIconWidth = res.getDimensionPixelSize(R.dimen.navigation_key_width); 421 int newMenuNavIconWidth = res.getDimensionPixelSize(R.dimen.navigation_menu_key_width); 422 423 if (mNavigationArea != null && newNavIconWidth != mNavIconWidth) { 424 mNavIconWidth = newNavIconWidth; 425 426 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( 427 mNavIconWidth, ViewGroup.LayoutParams.MATCH_PARENT); 428 mBackButton.setLayoutParams(lp); 429 mHomeButton.setLayoutParams(lp); 430 mRecentButton.setLayoutParams(lp); 431 } 432 433 if (mNavigationArea != null && newMenuNavIconWidth != mMenuNavIconWidth) { 434 mMenuNavIconWidth = newMenuNavIconWidth; 435 436 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( 437 mMenuNavIconWidth, ViewGroup.LayoutParams.MATCH_PARENT); 438 mMenuButton.setLayoutParams(lp); 439 } 440 441 if (newIconHPadding != mIconHPadding || newIconSize != mIconSize) { 442// Slog.d(TAG, "size=" + newIconSize + " padding=" + newIconHPadding); 443 mIconHPadding = newIconHPadding; 444 mIconSize = newIconSize; 445 reloadAllNotificationIcons(); // reload the tray 446 } 447 448 final int numIcons = res.getInteger(R.integer.config_maxNotificationIcons); 449 if (numIcons != mMaxNotificationIcons) { 450 mMaxNotificationIcons = numIcons; 451 if (DEBUG) Slog.d(TAG, "max notification icons: " + mMaxNotificationIcons); 452 reloadAllNotificationIcons(); 453 } 454 } 455 456 public View getStatusBarView() { 457 return mStatusBarView; 458 } 459 460 protected View makeStatusBarView() { 461 final Context context = mContext; 462 463 mWindowManager = IWindowManager.Stub.asInterface( 464 ServiceManager.getService(Context.WINDOW_SERVICE)); 465 466 loadDimens(); 467 468 final TabletStatusBarView sb = (TabletStatusBarView)View.inflate( 469 context, R.layout.system_bar, null); 470 mStatusBarView = sb; 471 472 sb.setHandler(mHandler); 473 474 try { 475 // Sanity-check that someone hasn't set up the config wrong and asked for a navigation 476 // bar on a tablet that has only the system bar 477 if (mWindowManager.hasNavigationBar()) { 478 Slog.e(TAG, "Tablet device cannot show navigation bar and system bar"); 479 } 480 } catch (RemoteException ex) { 481 } 482 483 mBarContents = (ViewGroup) sb.findViewById(R.id.bar_contents); 484 485 // the whole right-hand side of the bar 486 mNotificationArea = sb.findViewById(R.id.notificationArea); 487 mNotificationArea.setOnTouchListener(new NotificationTriggerTouchListener()); 488 489 // the button to open the notification area 490 mNotificationTrigger = sb.findViewById(R.id.notificationTrigger); 491 492 // the more notifications icon 493 mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons); 494 495 // where the icons go 496 mIconLayout = (NotificationIconArea.IconLayout) sb.findViewById(R.id.icons); 497 498 ViewConfiguration vc = ViewConfiguration.get(context); 499 mNotificationPeekTapDuration = vc.getTapTimeout(); 500 mNotificationFlingVelocity = 300; // px/s 501 502 mTicker = new TabletTicker(this); 503 504 // The icons 505 mLocationController = new LocationController(mContext); // will post a notification 506 507 // watch the PREF_DO_NOT_DISTURB and convert to appropriate disable() calls 508 mDoNotDisturb = new DoNotDisturb(mContext); 509 510 mBatteryController = new BatteryController(mContext); 511 mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery)); 512 mBluetoothController = new BluetoothController(mContext); 513 mBluetoothController.addIconView((ImageView)sb.findViewById(R.id.bluetooth)); 514 515 mNetworkController = new NetworkController(mContext); 516 final SignalClusterView signalCluster = 517 (SignalClusterView)sb.findViewById(R.id.signal_cluster); 518 mNetworkController.addSignalCluster(signalCluster); 519 520 // The navigation buttons 521 mBackButton = (ImageView)sb.findViewById(R.id.back); 522 mNavigationArea = (ViewGroup) sb.findViewById(R.id.navigationArea); 523 mHomeButton = mNavigationArea.findViewById(R.id.home); 524 mMenuButton = mNavigationArea.findViewById(R.id.menu); 525 mRecentButton = mNavigationArea.findViewById(R.id.recent_apps); 526 mRecentButton.setOnClickListener(mOnClickListener); 527 528 LayoutTransition lt = new LayoutTransition(); 529 lt.setDuration(250); 530 // don't wait for these transitions; we just want icons to fade in/out, not move around 531 lt.setDuration(LayoutTransition.CHANGE_APPEARING, 0); 532 lt.setDuration(LayoutTransition.CHANGE_DISAPPEARING, 0); 533 lt.addTransitionListener(new LayoutTransition.TransitionListener() { 534 public void endTransition(LayoutTransition transition, ViewGroup container, 535 View view, int transitionType) { 536 // ensure the menu button doesn't stick around on the status bar after it's been 537 // removed 538 mBarContents.invalidate(); 539 } 540 public void startTransition(LayoutTransition transition, ViewGroup container, 541 View view, int transitionType) {} 542 }); 543 mNavigationArea.setLayoutTransition(lt); 544 // no multi-touch on the nav buttons 545 mNavigationArea.setMotionEventSplittingEnabled(false); 546 547 // The bar contents buttons 548 mFeedbackIconArea = (ViewGroup)sb.findViewById(R.id.feedbackIconArea); 549 mInputMethodSwitchButton = (InputMethodButton) sb.findViewById(R.id.imeSwitchButton); 550 // Overwrite the lister 551 mInputMethodSwitchButton.setOnClickListener(mOnClickListener); 552 553 mCompatModeButton = (CompatModeButton) sb.findViewById(R.id.compatModeButton); 554 mCompatModeButton.setOnClickListener(mOnClickListener); 555 mCompatModeButton.setVisibility(View.GONE); 556 557 // for redirecting errant bar taps to the IME 558 mFakeSpaceBar = sb.findViewById(R.id.fake_space_bar); 559 560 // "shadows" of the status bar features, for lights-out mode 561 mShadow = sb.findViewById(R.id.bar_shadow); 562 mShadow.setOnTouchListener( 563 new View.OnTouchListener() { 564 public boolean onTouch(View v, MotionEvent ev) { 565 if (ev.getAction() == MotionEvent.ACTION_DOWN) { 566 // even though setting the systemUI visibility below will turn these views 567 // on, we need them to come up faster so that they can catch this motion 568 // event 569 mShadow.setVisibility(View.GONE); 570 mBarContents.setVisibility(View.VISIBLE); 571 572 try { 573 mBarService.setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE); 574 } catch (RemoteException ex) { 575 // system process dead 576 } 577 } 578 return false; 579 } 580 }); 581 582 // tuning parameters 583 final int LIGHTS_GOING_OUT_SYSBAR_DURATION = 750; 584 final int LIGHTS_GOING_OUT_SHADOW_DURATION = 750; 585 final int LIGHTS_GOING_OUT_SHADOW_DELAY = 0; 586 587 final int LIGHTS_COMING_UP_SYSBAR_DURATION = 200; 588// final int LIGHTS_COMING_UP_SYSBAR_DELAY = 50; 589 final int LIGHTS_COMING_UP_SHADOW_DURATION = 0; 590 591 LayoutTransition xition = new LayoutTransition(); 592 xition.setAnimator(LayoutTransition.APPEARING, 593 ObjectAnimator.ofFloat(null, "alpha", 0.5f, 1f)); 594 xition.setDuration(LayoutTransition.APPEARING, LIGHTS_COMING_UP_SYSBAR_DURATION); 595 xition.setStartDelay(LayoutTransition.APPEARING, 0); 596 xition.setAnimator(LayoutTransition.DISAPPEARING, 597 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f)); 598 xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_GOING_OUT_SYSBAR_DURATION); 599 xition.setStartDelay(LayoutTransition.DISAPPEARING, 0); 600 ((ViewGroup)sb.findViewById(R.id.bar_contents_holder)).setLayoutTransition(xition); 601 602 xition = new LayoutTransition(); 603 xition.setAnimator(LayoutTransition.APPEARING, 604 ObjectAnimator.ofFloat(null, "alpha", 0f, 1f)); 605 xition.setDuration(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DURATION); 606 xition.setStartDelay(LayoutTransition.APPEARING, LIGHTS_GOING_OUT_SHADOW_DELAY); 607 xition.setAnimator(LayoutTransition.DISAPPEARING, 608 ObjectAnimator.ofFloat(null, "alpha", 1f, 0f)); 609 xition.setDuration(LayoutTransition.DISAPPEARING, LIGHTS_COMING_UP_SHADOW_DURATION); 610 xition.setStartDelay(LayoutTransition.DISAPPEARING, 0); 611 ((ViewGroup)sb.findViewById(R.id.bar_shadow_holder)).setLayoutTransition(xition); 612 613 // set the initial view visibility 614 setAreThereNotifications(); 615 616 // receive broadcasts 617 IntentFilter filter = new IntentFilter(); 618 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 619 filter.addAction(Intent.ACTION_SCREEN_OFF); 620 context.registerReceiver(mBroadcastReceiver, filter); 621 622 return sb; 623 } 624 625 @Override 626 protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) { 627 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 628 (int) mContext.getResources().getDimension(R.dimen.status_bar_recents_width), 629 ViewGroup.LayoutParams.MATCH_PARENT, 630 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, 631 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 632 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 633 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH 634 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, 635 PixelFormat.TRANSLUCENT); 636 lp.gravity = Gravity.BOTTOM | Gravity.LEFT; 637 lp.setTitle("RecentsPanel"); 638 lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications; 639 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 640 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 641 642 return lp; 643 } 644 645 @Override 646 protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) { 647 boolean opaque = false; 648 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 649 LayoutParams.MATCH_PARENT, 650 LayoutParams.MATCH_PARENT, 651 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, 652 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 653 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM 654 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, 655 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT)); 656 if (ActivityManager.isHighEndGfx(mDisplay)) { 657 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 658 } else { 659 lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; 660 lp.dimAmount = 0.7f; 661 } 662 lp.gravity = Gravity.BOTTOM | Gravity.LEFT; 663 lp.setTitle("SearchPanel"); 664 // TODO: Define custom animation for Search panel 665 lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications; 666 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 667 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 668 return lp; 669 } 670 671 protected void updateRecentsPanel() { 672 super.updateRecentsPanel(R.layout.system_bar_recent_panel); 673 mRecentsPanel.setStatusBarView(mStatusBarView); 674 } 675 676 @Override 677 protected void updateSearchPanel() { 678 super.updateSearchPanel(); 679 mSearchPanelView.setStatusBarView(mStatusBarView); 680 mStatusBarView.setDelegateView(mSearchPanelView); 681 } 682 683 @Override 684 public void showSearchPanel() { 685 super.showSearchPanel(); 686 WindowManager.LayoutParams lp = 687 (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams(); 688 lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 689 WindowManagerImpl.getDefault().updateViewLayout(mStatusBarView, lp); 690 } 691 692 @Override 693 public void hideSearchPanel() { 694 super.hideSearchPanel(); 695 WindowManager.LayoutParams lp = 696 (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams(); 697 lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 698 WindowManagerImpl.getDefault().updateViewLayout(mStatusBarView, lp); 699 } 700 701 public int getStatusBarHeight() { 702 return mStatusBarView != null ? mStatusBarView.getHeight() 703 : mContext.getResources().getDimensionPixelSize( 704 com.android.internal.R.dimen.navigation_bar_height); 705 } 706 707 protected int getStatusBarGravity() { 708 return Gravity.BOTTOM | Gravity.FILL_HORIZONTAL; 709 } 710 711 public void onBarHeightChanged(int height) { 712 final WindowManager.LayoutParams lp 713 = (WindowManager.LayoutParams)mStatusBarView.getLayoutParams(); 714 if (lp == null) { 715 // haven't been added yet 716 return; 717 } 718 if (lp.height != height) { 719 lp.height = height; 720 final WindowManager wm = WindowManagerImpl.getDefault(); 721 wm.updateViewLayout(mStatusBarView, lp); 722 } 723 } 724 725 @Override 726 protected BaseStatusBar.H createHandler() { 727 return new TabletStatusBar.H(); 728 } 729 730 private class H extends BaseStatusBar.H { 731 public void handleMessage(Message m) { 732 super.handleMessage(m); 733 switch (m.what) { 734 case MSG_OPEN_NOTIFICATION_PEEK: 735 if (DEBUG) Slog.d(TAG, "opening notification peek window; arg=" + m.arg1); 736 737 if (m.arg1 >= 0) { 738 final int N = mNotificationData.size(); 739 740 if (!mNotificationDNDMode) { 741 if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) { 742 NotificationData.Entry entry = mNotificationData.get(N-1-mNotificationPeekIndex); 743 entry.icon.setBackgroundColor(0); 744 mNotificationPeekIndex = -1; 745 mNotificationPeekKey = null; 746 } 747 } 748 749 final int peekIndex = m.arg1; 750 if (peekIndex < N) { 751 //Slog.d(TAG, "loading peek: " + peekIndex); 752 NotificationData.Entry entry = 753 mNotificationDNDMode 754 ? mNotificationDNDDummyEntry 755 : mNotificationData.get(N-1-peekIndex); 756 NotificationData.Entry copy = new NotificationData.Entry( 757 entry.key, 758 entry.notification, 759 entry.icon); 760 inflateViews(copy, mNotificationPeekRow); 761 762 if (mNotificationDNDMode) { 763 copy.content.setOnClickListener(new View.OnClickListener() { 764 public void onClick(View v) { 765 SharedPreferences.Editor editor = Prefs.edit(mContext); 766 editor.putBoolean(Prefs.DO_NOT_DISTURB_PREF, false); 767 editor.apply(); 768 animateCollapse(); 769 visibilityChanged(false); 770 } 771 }); 772 } 773 774 entry.icon.setBackgroundColor(0x20FFFFFF); 775 776// mNotificationPeekRow.setLayoutTransition( 777// peekIndex < mNotificationPeekIndex 778// ? mNotificationPeekScrubLeft 779// : mNotificationPeekScrubRight); 780 781 mNotificationPeekRow.removeAllViews(); 782 mNotificationPeekRow.addView(copy.row); 783 784 mNotificationPeekWindow.setVisibility(View.VISIBLE); 785 mNotificationPanel.show(false, true); 786 787 mNotificationPeekIndex = peekIndex; 788 mNotificationPeekKey = entry.key; 789 } 790 } 791 break; 792 case MSG_CLOSE_NOTIFICATION_PEEK: 793 if (DEBUG) Slog.d(TAG, "closing notification peek window"); 794 mNotificationPeekWindow.setVisibility(View.GONE); 795 mNotificationPeekRow.removeAllViews(); 796 797 final int N = mNotificationData.size(); 798 if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) { 799 NotificationData.Entry entry = 800 mNotificationDNDMode 801 ? mNotificationDNDDummyEntry 802 : mNotificationData.get(N-1-mNotificationPeekIndex); 803 entry.icon.setBackgroundColor(0); 804 } 805 806 mNotificationPeekIndex = -1; 807 mNotificationPeekKey = null; 808 break; 809 case MSG_OPEN_NOTIFICATION_PANEL: 810 if (DEBUG) Slog.d(TAG, "opening notifications panel"); 811 if (!mNotificationPanel.isShowing()) { 812 mNotificationPanel.show(true, true); 813 mNotificationArea.setVisibility(View.INVISIBLE); 814 mTicker.halt(); 815 } 816 break; 817 case MSG_CLOSE_NOTIFICATION_PANEL: 818 if (DEBUG) Slog.d(TAG, "closing notifications panel"); 819 if (mNotificationPanel.isShowing()) { 820 mNotificationPanel.show(false, true); 821 mNotificationArea.setVisibility(View.VISIBLE); 822 } 823 break; 824 case MSG_OPEN_INPUT_METHODS_PANEL: 825 if (DEBUG) Slog.d(TAG, "opening input methods panel"); 826 if (mInputMethodsPanel != null) mInputMethodsPanel.openPanel(); 827 break; 828 case MSG_CLOSE_INPUT_METHODS_PANEL: 829 if (DEBUG) Slog.d(TAG, "closing input methods panel"); 830 if (mInputMethodsPanel != null) mInputMethodsPanel.closePanel(false); 831 break; 832 case MSG_OPEN_COMPAT_MODE_PANEL: 833 if (DEBUG) Slog.d(TAG, "opening compat panel"); 834 if (mCompatModePanel != null) mCompatModePanel.openPanel(); 835 break; 836 case MSG_CLOSE_COMPAT_MODE_PANEL: 837 if (DEBUG) Slog.d(TAG, "closing compat panel"); 838 if (mCompatModePanel != null) mCompatModePanel.closePanel(); 839 break; 840 case MSG_SHOW_CHROME: 841 if (DEBUG) Slog.d(TAG, "hiding shadows (lights on)"); 842 mBarContents.setVisibility(View.VISIBLE); 843 mShadow.setVisibility(View.GONE); 844 mSystemUiVisibility &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; 845 notifyUiVisibilityChanged(); 846 break; 847 case MSG_HIDE_CHROME: 848 if (DEBUG) Slog.d(TAG, "showing shadows (lights out)"); 849 animateCollapse(); 850 visibilityChanged(false); 851 mBarContents.setVisibility(View.GONE); 852 mShadow.setVisibility(View.VISIBLE); 853 mSystemUiVisibility |= View.SYSTEM_UI_FLAG_LOW_PROFILE; 854 notifyUiVisibilityChanged(); 855 break; 856 case MSG_STOP_TICKER: 857 mTicker.halt(); 858 break; 859 } 860 } 861 } 862 863 public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { 864 if (DEBUG) Slog.d(TAG, "addIcon(" + slot + ") -> " + icon); 865 } 866 867 public void updateIcon(String slot, int index, int viewIndex, 868 StatusBarIcon old, StatusBarIcon icon) { 869 if (DEBUG) Slog.d(TAG, "updateIcon(" + slot + ") -> " + icon); 870 } 871 872 public void removeIcon(String slot, int index, int viewIndex) { 873 if (DEBUG) Slog.d(TAG, "removeIcon(" + slot + ")"); 874 } 875 876 public void addNotification(IBinder key, StatusBarNotification notification) { 877 if (DEBUG) Slog.d(TAG, "addNotification(" + key + " -> " + notification + ")"); 878 addNotificationViews(key, notification); 879 880 final boolean immersive = isImmersive(); 881 if (false && immersive) { 882 // TODO: immersive mode popups for tablet 883 } else if (notification.notification.fullScreenIntent != null) { 884 // not immersive & a full-screen alert should be shown 885 Slog.w(TAG, "Notification has fullScreenIntent and activity is not immersive;" 886 + " sending fullScreenIntent"); 887 try { 888 notification.notification.fullScreenIntent.send(); 889 } catch (PendingIntent.CanceledException e) { 890 } 891 } else { 892 tick(key, notification, true); 893 } 894 895 setAreThereNotifications(); 896 } 897 898 public void removeNotification(IBinder key) { 899 if (DEBUG) Slog.d(TAG, "removeNotification(" + key + ")"); 900 removeNotificationViews(key); 901 mTicker.remove(key); 902 setAreThereNotifications(); 903 } 904 905 public void showClock(boolean show) { 906 View clock = mBarContents.findViewById(R.id.clock); 907 View network_text = mBarContents.findViewById(R.id.network_text); 908 if (clock != null) { 909 clock.setVisibility(show ? View.VISIBLE : View.GONE); 910 } 911 if (network_text != null) { 912 network_text.setVisibility((!show) ? View.VISIBLE : View.GONE); 913 } 914 } 915 916 public void disable(int state) { 917 int old = mDisabled; 918 int diff = state ^ old; 919 mDisabled = state; 920 921 // act accordingly 922 if ((diff & StatusBarManager.DISABLE_CLOCK) != 0) { 923 boolean show = (state & StatusBarManager.DISABLE_CLOCK) == 0; 924 Slog.i(TAG, "DISABLE_CLOCK: " + (show ? "no" : "yes")); 925 showClock(show); 926 } 927 if ((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { 928 boolean show = (state & StatusBarManager.DISABLE_SYSTEM_INFO) == 0; 929 Slog.i(TAG, "DISABLE_SYSTEM_INFO: " + (show ? "no" : "yes")); 930 mNotificationTrigger.setVisibility(show ? View.VISIBLE : View.GONE); 931 } 932 if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { 933 if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { 934 Slog.i(TAG, "DISABLE_EXPAND: yes"); 935 animateCollapse(); 936 visibilityChanged(false); 937 } 938 } 939 if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 940 mNotificationDNDMode = Prefs.read(mContext) 941 .getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT); 942 943 if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { 944 Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: yes" + (mNotificationDNDMode?" (DND)":"")); 945 mTicker.halt(); 946 } else { 947 Slog.i(TAG, "DISABLE_NOTIFICATION_ICONS: no" + (mNotificationDNDMode?" (DND)":"")); 948 } 949 950 // refresh icons to show either notifications or the DND message 951 reloadAllNotificationIcons(); 952 } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { 953 if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { 954 mTicker.halt(); 955 } 956 } 957 if ((diff & (StatusBarManager.DISABLE_RECENT 958 | StatusBarManager.DISABLE_BACK 959 | StatusBarManager.DISABLE_HOME)) != 0) { 960 setNavigationVisibility(state); 961 962 if ((state & StatusBarManager.DISABLE_RECENT) != 0) { 963 // close recents if it's visible 964 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); 965 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); 966 } 967 } 968 } 969 970 private void setNavigationVisibility(int visibility) { 971 boolean disableHome = ((visibility & StatusBarManager.DISABLE_HOME) != 0); 972 boolean disableRecent = ((visibility & StatusBarManager.DISABLE_RECENT) != 0); 973 boolean disableBack = ((visibility & StatusBarManager.DISABLE_BACK) != 0); 974 975 mBackButton.setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE); 976 mHomeButton.setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE); 977 mRecentButton.setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE); 978 979 mInputMethodSwitchButton.setScreenLocked( 980 (visibility & StatusBarManager.DISABLE_SYSTEM_INFO) != 0); 981 } 982 983 private boolean hasTicker(Notification n) { 984 return n.tickerView != null || !TextUtils.isEmpty(n.tickerText); 985 } 986 987 @Override 988 protected void tick(IBinder key, StatusBarNotification n, boolean firstTime) { 989 // Don't show the ticker when the windowshade is open. 990 if (mNotificationPanel.isShowing()) { 991 return; 992 } 993 // If they asked for FLAG_ONLY_ALERT_ONCE, then only show this notification 994 // if it's a new notification. 995 if (!firstTime && (n.notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) { 996 return; 997 } 998 // Show the ticker if one is requested. Also don't do this 999 // until status bar window is attached to the window manager, 1000 // because... well, what's the point otherwise? And trying to 1001 // run a ticker without being attached will crash! 1002 if (hasTicker(n.notification) && mStatusBarView.getWindowToken() != null) { 1003 if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS 1004 | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) { 1005 mTicker.add(key, n); 1006 mFeedbackIconArea.setVisibility(View.GONE); 1007 } 1008 } 1009 } 1010 1011 // called by TabletTicker when it's done with all queued ticks 1012 public void doneTicking() { 1013 mFeedbackIconArea.setVisibility(View.VISIBLE); 1014 } 1015 1016 public void animateExpand() { 1017 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL); 1018 mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL); 1019 } 1020 1021 public void animateCollapse() { 1022 animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE); 1023 } 1024 1025 public void animateCollapse(int flags) { 1026 if ((flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) { 1027 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PANEL); 1028 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PANEL); 1029 } 1030 if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) { 1031 mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL); 1032 mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL); 1033 } 1034 if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) { 1035 mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL); 1036 mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL); 1037 } 1038 if ((flags & CommandQueue.FLAG_EXCLUDE_INPUT_METHODS_PANEL) == 0) { 1039 mHandler.removeMessages(MSG_CLOSE_INPUT_METHODS_PANEL); 1040 mHandler.sendEmptyMessage(MSG_CLOSE_INPUT_METHODS_PANEL); 1041 } 1042 if ((flags & CommandQueue.FLAG_EXCLUDE_COMPAT_MODE_PANEL) == 0) { 1043 mHandler.removeMessages(MSG_CLOSE_COMPAT_MODE_PANEL); 1044 mHandler.sendEmptyMessage(MSG_CLOSE_COMPAT_MODE_PANEL); 1045 } 1046 1047 } 1048 1049 @Override // CommandQueue 1050 public void setNavigationIconHints(int hints) { 1051 if (hints == mNavigationIconHints) return; 1052 1053 if (DEBUG) { 1054 android.widget.Toast.makeText(mContext, 1055 "Navigation icon hints = " + hints, 1056 500).show(); 1057 } 1058 1059 mNavigationIconHints = hints; 1060 1061 mBackButton.setAlpha( 1062 (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_NOP)) ? 0.5f : 1.0f); 1063 mHomeButton.setAlpha( 1064 (0 != (hints & StatusBarManager.NAVIGATION_HINT_HOME_NOP)) ? 0.5f : 1.0f); 1065 mRecentButton.setAlpha( 1066 (0 != (hints & StatusBarManager.NAVIGATION_HINT_RECENT_NOP)) ? 0.5f : 1.0f); 1067 1068 mBackButton.setImageResource( 1069 (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT)) 1070 ? R.drawable.ic_sysbar_back_ime 1071 : R.drawable.ic_sysbar_back); 1072 } 1073 1074 private void notifyUiVisibilityChanged() { 1075 try { 1076 mWindowManager.statusBarVisibilityChanged(mSystemUiVisibility); 1077 } catch (RemoteException ex) { 1078 } 1079 } 1080 1081 @Override // CommandQueue 1082 public void setSystemUiVisibility(int vis, int mask) { 1083 final int oldVal = mSystemUiVisibility; 1084 final int newVal = (oldVal&~mask) | (vis&mask); 1085 final int diff = newVal ^ oldVal; 1086 1087 if (diff != 0) { 1088 mSystemUiVisibility = newVal; 1089 1090 if (0 != (diff & View.SYSTEM_UI_FLAG_LOW_PROFILE)) { 1091 mHandler.removeMessages(MSG_HIDE_CHROME); 1092 mHandler.removeMessages(MSG_SHOW_CHROME); 1093 mHandler.sendEmptyMessage(0 == (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) 1094 ? MSG_SHOW_CHROME : MSG_HIDE_CHROME); 1095 } 1096 1097 notifyUiVisibilityChanged(); 1098 } 1099 } 1100 1101 public void setLightsOn(boolean on) { 1102 // Policy note: if the frontmost activity needs the menu key, we assume it is a legacy app 1103 // that can't handle lights-out mode. 1104 if (mMenuButton.getVisibility() == View.VISIBLE) { 1105 on = true; 1106 } 1107 1108 Slog.v(TAG, "setLightsOn(" + on + ")"); 1109 if (on) { 1110 setSystemUiVisibility(0, View.SYSTEM_UI_FLAG_LOW_PROFILE); 1111 } else { 1112 setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE, View.SYSTEM_UI_FLAG_LOW_PROFILE); 1113 } 1114 } 1115 1116 public void topAppWindowChanged(boolean showMenu) { 1117 if (DEBUG) { 1118 Slog.d(TAG, (showMenu?"showing":"hiding") + " the MENU button"); 1119 } 1120 mMenuButton.setVisibility(showMenu ? View.VISIBLE : View.GONE); 1121 1122 // See above re: lights-out policy for legacy apps. 1123 if (showMenu) setLightsOn(true); 1124 1125 mCompatModeButton.refresh(); 1126 if (mCompatModeButton.getVisibility() == View.VISIBLE) { 1127 if (DEBUG_COMPAT_HELP 1128 || ! Prefs.read(mContext).getBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, false)) { 1129 showCompatibilityHelp(); 1130 } 1131 } else { 1132 hideCompatibilityHelp(); 1133 mCompatModePanel.closePanel(); 1134 } 1135 } 1136 1137 private void showCompatibilityHelp() { 1138 if (mCompatibilityHelpDialog != null) { 1139 return; 1140 } 1141 1142 mCompatibilityHelpDialog = View.inflate(mContext, R.layout.compat_mode_help, null); 1143 View button = mCompatibilityHelpDialog.findViewById(R.id.button); 1144 1145 button.setOnClickListener(new View.OnClickListener() { 1146 @Override 1147 public void onClick(View v) { 1148 hideCompatibilityHelp(); 1149 SharedPreferences.Editor editor = Prefs.edit(mContext); 1150 editor.putBoolean(Prefs.SHOWN_COMPAT_MODE_HELP, true); 1151 editor.apply(); 1152 } 1153 }); 1154 1155 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 1156 ViewGroup.LayoutParams.MATCH_PARENT, 1157 ViewGroup.LayoutParams.MATCH_PARENT, 1158 WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG, 1159 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 1160 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 1161 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, 1162 PixelFormat.TRANSLUCENT); 1163 lp.setTitle("CompatibilityModeDialog"); 1164 lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED 1165 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 1166 lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade 1167 1168 WindowManagerImpl.getDefault().addView(mCompatibilityHelpDialog, lp); 1169 } 1170 1171 private void hideCompatibilityHelp() { 1172 if (mCompatibilityHelpDialog != null) { 1173 WindowManagerImpl.getDefault().removeView(mCompatibilityHelpDialog); 1174 mCompatibilityHelpDialog = null; 1175 } 1176 } 1177 1178 public void setImeWindowStatus(IBinder token, int vis, int backDisposition) { 1179 mInputMethodSwitchButton.setImeWindowStatus(token, 1180 (vis & InputMethodService.IME_ACTIVE) != 0); 1181 updateNotificationIcons(); 1182 mInputMethodsPanel.setImeToken(token); 1183 1184 boolean altBack = (backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) 1185 || ((vis & InputMethodService.IME_VISIBLE) != 0); 1186 mAltBackButtonEnabledForIme = altBack; 1187 1188 mCommandQueue.setNavigationIconHints( 1189 altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT) 1190 : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT)); 1191 1192 if (FAKE_SPACE_BAR) { 1193 mFakeSpaceBar.setVisibility(((vis & InputMethodService.IME_VISIBLE) != 0) 1194 ? View.VISIBLE : View.GONE); 1195 } 1196 } 1197 1198 @Override 1199 public void onRecentsPanelVisibilityChanged(boolean visible) { 1200 boolean altBack = visible || mAltBackButtonEnabledForIme; 1201 mCommandQueue.setNavigationIconHints( 1202 altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT) 1203 : (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT)); 1204 } 1205 1206 @Override 1207 public void setHardKeyboardStatus(boolean available, boolean enabled) { 1208 if (DEBUG) { 1209 Slog.d(TAG, "Set hard keyboard status: available=" + available 1210 + ", enabled=" + enabled); 1211 } 1212 mInputMethodSwitchButton.setHardKeyboardStatus(available); 1213 updateNotificationIcons(); 1214 mInputMethodsPanel.setHardKeyboardStatus(available, enabled); 1215 } 1216 1217 @Override 1218 public void onHardKeyboardEnabledChange(boolean enabled) { 1219 try { 1220 mBarService.setHardKeyboardEnabled(enabled); 1221 } catch (RemoteException ex) { 1222 } 1223 } 1224 1225 private boolean isImmersive() { 1226 try { 1227 return ActivityManagerNative.getDefault().isTopActivityImmersive(); 1228 //Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive")); 1229 } catch (RemoteException ex) { 1230 // the end is nigh 1231 return false; 1232 } 1233 } 1234 1235 @Override 1236 protected void setAreThereNotifications() { 1237 if (mNotificationPanel != null) { 1238 mNotificationPanel.setClearable(isDeviceProvisioned() && mNotificationData.hasClearableItems()); 1239 } 1240 } 1241 1242 private View.OnClickListener mOnClickListener = new View.OnClickListener() { 1243 public void onClick(View v) { 1244 if (v == mRecentButton) { 1245 onClickRecentButton(); 1246 } else if (v == mInputMethodSwitchButton) { 1247 onClickInputMethodSwitchButton(); 1248 } else if (v == mCompatModeButton) { 1249 onClickCompatModeButton(); 1250 } 1251 } 1252 }; 1253 1254 public void onClickRecentButton() { 1255 if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled); 1256 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) { 1257 int msg = (mRecentsPanel.getVisibility() == View.VISIBLE) 1258 ? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL; 1259 mHandler.removeMessages(msg); 1260 mHandler.sendEmptyMessage(msg); 1261 } 1262 } 1263 1264 public void onClickInputMethodSwitchButton() { 1265 if (DEBUG) Slog.d(TAG, "clicked input methods panel; disabled=" + mDisabled); 1266 int msg = (mInputMethodsPanel.getVisibility() == View.GONE) ? 1267 MSG_OPEN_INPUT_METHODS_PANEL : MSG_CLOSE_INPUT_METHODS_PANEL; 1268 mHandler.removeMessages(msg); 1269 mHandler.sendEmptyMessage(msg); 1270 } 1271 1272 public void onClickCompatModeButton() { 1273 int msg = (mCompatModePanel.getVisibility() == View.GONE) ? 1274 MSG_OPEN_COMPAT_MODE_PANEL : MSG_CLOSE_COMPAT_MODE_PANEL; 1275 mHandler.removeMessages(msg); 1276 mHandler.sendEmptyMessage(msg); 1277 } 1278 1279 private class NotificationTriggerTouchListener implements View.OnTouchListener { 1280 VelocityTracker mVT; 1281 float mInitialTouchX, mInitialTouchY; 1282 int mTouchSlop; 1283 1284 public NotificationTriggerTouchListener() { 1285 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 1286 } 1287 1288 private Runnable mHiliteOnR = new Runnable() { public void run() { 1289 mNotificationArea.setBackgroundResource( 1290 com.android.internal.R.drawable.list_selector_pressed_holo_dark); 1291 }}; 1292 public void hilite(final boolean on) { 1293 if (on) { 1294 mNotificationArea.postDelayed(mHiliteOnR, 100); 1295 } else { 1296 mNotificationArea.removeCallbacks(mHiliteOnR); 1297 mNotificationArea.setBackgroundDrawable(null); 1298 } 1299 } 1300 1301 public boolean onTouch(View v, MotionEvent event) { 1302// Slog.d(TAG, String.format("touch: (%.1f, %.1f) initial: (%.1f, %.1f)", 1303// event.getX(), 1304// event.getY(), 1305// mInitialTouchX, 1306// mInitialTouchY)); 1307 1308 if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { 1309 return true; 1310 } 1311 1312 final int action = event.getAction(); 1313 switch (action) { 1314 case MotionEvent.ACTION_DOWN: 1315 mVT = VelocityTracker.obtain(); 1316 mInitialTouchX = event.getX(); 1317 mInitialTouchY = event.getY(); 1318 hilite(true); 1319 // fall through 1320 case MotionEvent.ACTION_OUTSIDE: 1321 case MotionEvent.ACTION_MOVE: 1322 // check for fling 1323 if (mVT != null) { 1324 mVT.addMovement(event); 1325 mVT.computeCurrentVelocity(1000); // pixels per second 1326 // require a little more oomph once we're already in peekaboo mode 1327 if (mVT.getYVelocity() < -mNotificationFlingVelocity) { 1328 animateExpand(); 1329 visibilityChanged(true); 1330 hilite(false); 1331 mVT.recycle(); 1332 mVT = null; 1333 } 1334 } 1335 return true; 1336 case MotionEvent.ACTION_UP: 1337 case MotionEvent.ACTION_CANCEL: 1338 hilite(false); 1339 if (mVT != null) { 1340 if (action == MotionEvent.ACTION_UP 1341 // was this a sloppy tap? 1342 && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop 1343 && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3) 1344 // dragging off the bottom doesn't count 1345 && (int)event.getY() < v.getBottom()) { 1346 animateExpand(); 1347 visibilityChanged(true); 1348 v.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 1349 v.playSoundEffect(SoundEffectConstants.CLICK); 1350 } 1351 1352 mVT.recycle(); 1353 mVT = null; 1354 return true; 1355 } 1356 } 1357 return false; 1358 } 1359 } 1360 1361 public void resetNotificationPeekFadeTimer() { 1362 if (DEBUG) { 1363 Slog.d(TAG, "setting peek fade timer for " + NOTIFICATION_PEEK_FADE_DELAY 1364 + "ms from now"); 1365 } 1366 mHandler.removeMessages(MSG_CLOSE_NOTIFICATION_PEEK); 1367 mHandler.sendEmptyMessageDelayed(MSG_CLOSE_NOTIFICATION_PEEK, 1368 NOTIFICATION_PEEK_FADE_DELAY); 1369 } 1370 1371 private class NotificationIconTouchListener implements View.OnTouchListener { 1372 VelocityTracker mVT; 1373 int mPeekIndex; 1374 float mInitialTouchX, mInitialTouchY; 1375 int mTouchSlop; 1376 1377 public NotificationIconTouchListener() { 1378 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 1379 } 1380 1381 public boolean onTouch(View v, MotionEvent event) { 1382 boolean peeking = mNotificationPeekWindow.getVisibility() != View.GONE; 1383 boolean panelShowing = mNotificationPanel.isShowing(); 1384 if (panelShowing) return false; 1385 1386 int numIcons = mIconLayout.getChildCount(); 1387 int newPeekIndex = (int)(event.getX() * numIcons / mIconLayout.getWidth()); 1388 if (newPeekIndex > numIcons - 1) newPeekIndex = numIcons - 1; 1389 else if (newPeekIndex < 0) newPeekIndex = 0; 1390 1391 final int action = event.getAction(); 1392 switch (action) { 1393 case MotionEvent.ACTION_DOWN: 1394 mVT = VelocityTracker.obtain(); 1395 mInitialTouchX = event.getX(); 1396 mInitialTouchY = event.getY(); 1397 mPeekIndex = -1; 1398 1399 // fall through 1400 case MotionEvent.ACTION_OUTSIDE: 1401 case MotionEvent.ACTION_MOVE: 1402 // peek and switch icons if necessary 1403 1404 if (newPeekIndex != mPeekIndex) { 1405 mPeekIndex = newPeekIndex; 1406 1407 if (DEBUG) Slog.d(TAG, "will peek at notification #" + mPeekIndex); 1408 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK); 1409 peekMsg.arg1 = mPeekIndex; 1410 1411 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK); 1412 1413 if (peeking) { 1414 // no delay if we're scrubbing left-right 1415 mHandler.sendMessage(peekMsg); 1416 } else { 1417 // wait for fling 1418 mHandler.sendMessageDelayed(peekMsg, NOTIFICATION_PEEK_HOLD_THRESH); 1419 } 1420 } 1421 1422 // check for fling 1423 if (mVT != null) { 1424 mVT.addMovement(event); 1425 mVT.computeCurrentVelocity(1000); // pixels per second 1426 // require a little more oomph once we're already in peekaboo mode 1427 if (!panelShowing && ( 1428 (peeking && mVT.getYVelocity() < -mNotificationFlingVelocity*3) 1429 || (mVT.getYVelocity() < -mNotificationFlingVelocity))) { 1430 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK); 1431 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PANEL); 1432 mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK); 1433 mHandler.sendEmptyMessage(MSG_OPEN_NOTIFICATION_PANEL); 1434 } 1435 } 1436 return true; 1437 case MotionEvent.ACTION_UP: 1438 case MotionEvent.ACTION_CANCEL: 1439 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK); 1440 if (!peeking) { 1441 if (action == MotionEvent.ACTION_UP 1442 // was this a sloppy tap? 1443 && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop 1444 && Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3) 1445 // dragging off the bottom doesn't count 1446 && (int)event.getY() < v.getBottom()) { 1447 Message peekMsg = mHandler.obtainMessage(MSG_OPEN_NOTIFICATION_PEEK); 1448 peekMsg.arg1 = mPeekIndex; 1449 mHandler.removeMessages(MSG_OPEN_NOTIFICATION_PEEK); 1450 mHandler.sendMessage(peekMsg); 1451 1452 v.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 1453 v.playSoundEffect(SoundEffectConstants.CLICK); 1454 1455 peeking = true; // not technically true yet, but the next line will run 1456 } 1457 } 1458 1459 if (peeking) { 1460 resetNotificationPeekFadeTimer(); 1461 } 1462 1463 mVT.recycle(); 1464 mVT = null; 1465 return true; 1466 } 1467 return false; 1468 } 1469 } 1470 1471 private void reloadAllNotificationIcons() { 1472 if (mIconLayout == null) return; 1473 mIconLayout.removeAllViews(); 1474 updateNotificationIcons(); 1475 } 1476 1477 @Override 1478 protected void updateNotificationIcons() { 1479 // XXX: need to implement a new limited linear layout class 1480 // to avoid removing & readding everything 1481 1482 if (mIconLayout == null) return; 1483 1484 // first, populate the main notification panel 1485 loadNotificationPanel(); 1486 1487 final LinearLayout.LayoutParams params 1488 = new LinearLayout.LayoutParams(mIconSize + 2*mIconHPadding, mNaturalBarHeight); 1489 1490 // alternate behavior in DND mode 1491 if (mNotificationDNDMode) { 1492 if (mIconLayout.getChildCount() == 0) { 1493 final Notification dndNotification = new Notification.Builder(mContext) 1494 .setContentTitle(mContext.getText(R.string.notifications_off_title)) 1495 .setContentText(mContext.getText(R.string.notifications_off_text)) 1496 .setSmallIcon(R.drawable.ic_notification_dnd) 1497 .setOngoing(true) 1498 .getNotification(); 1499 1500 final StatusBarIconView iconView = new StatusBarIconView(mContext, "_dnd", 1501 dndNotification); 1502 iconView.setImageResource(R.drawable.ic_notification_dnd); 1503 iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 1504 iconView.setPadding(mIconHPadding, 0, mIconHPadding, 0); 1505 1506 mNotificationDNDDummyEntry = new NotificationData.Entry( 1507 null, 1508 new StatusBarNotification("", 0, "", 0, 0, Notification.PRIORITY_MAX, dndNotification), 1509 iconView); 1510 1511 mIconLayout.addView(iconView, params); 1512 } 1513 1514 return; 1515 } else if (0 != (mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS)) { 1516 // if icons are disabled but we're not in DND mode, this is probably Setup and we should 1517 // just leave the area totally empty 1518 return; 1519 } 1520 1521 int N = mNotificationData.size(); 1522 1523 if (DEBUG) { 1524 Slog.d(TAG, "refreshing icons: " + N + " notifications, mIconLayout=" + mIconLayout); 1525 } 1526 1527 ArrayList<View> toShow = new ArrayList<View>(); 1528 1529 // Extra Special Icons 1530 // The IME switcher and compatibility mode icons take the place of notifications. You didn't 1531 // need to see all those new emails, did you? 1532 int maxNotificationIconsCount = mMaxNotificationIcons; 1533 if (mInputMethodSwitchButton.getVisibility() != View.GONE) maxNotificationIconsCount --; 1534 if (mCompatModeButton.getVisibility() != View.GONE) maxNotificationIconsCount --; 1535 1536 final boolean provisioned = isDeviceProvisioned(); 1537 // If the device hasn't been through Setup, we only show system notifications 1538 for (int i=0; toShow.size()< maxNotificationIconsCount; i++) { 1539 if (i >= N) break; 1540 Entry ent = mNotificationData.get(N-i-1); 1541 if ((provisioned && ent.notification.score >= HIDE_ICONS_BELOW_SCORE) 1542 || showNotificationEvenIfUnprovisioned(ent.notification)) { 1543 toShow.add(ent.icon); 1544 } 1545 } 1546 1547 ArrayList<View> toRemove = new ArrayList<View>(); 1548 for (int i=0; i<mIconLayout.getChildCount(); i++) { 1549 View child = mIconLayout.getChildAt(i); 1550 if (!toShow.contains(child)) { 1551 toRemove.add(child); 1552 } 1553 } 1554 1555 for (View remove : toRemove) { 1556 mIconLayout.removeView(remove); 1557 } 1558 1559 for (int i=0; i<toShow.size(); i++) { 1560 View v = toShow.get(i); 1561 v.setPadding(mIconHPadding, 0, mIconHPadding, 0); 1562 if (v.getParent() == null) { 1563 mIconLayout.addView(v, i, params); 1564 } 1565 } 1566 } 1567 1568 private void loadNotificationPanel() { 1569 int N = mNotificationData.size(); 1570 1571 ArrayList<View> toShow = new ArrayList<View>(); 1572 1573 final boolean provisioned = isDeviceProvisioned(); 1574 // If the device hasn't been through Setup, we only show system notifications 1575 for (int i=0; i<N; i++) { 1576 Entry ent = mNotificationData.get(N-i-1); 1577 if (provisioned || showNotificationEvenIfUnprovisioned(ent.notification)) { 1578 toShow.add(ent.row); 1579 } 1580 } 1581 1582 ArrayList<View> toRemove = new ArrayList<View>(); 1583 for (int i=0; i<mPile.getChildCount(); i++) { 1584 View child = mPile.getChildAt(i); 1585 if (!toShow.contains(child)) { 1586 toRemove.add(child); 1587 } 1588 } 1589 1590 for (View remove : toRemove) { 1591 mPile.removeView(remove); 1592 } 1593 1594 for (int i=0; i<toShow.size(); i++) { 1595 View v = toShow.get(i); 1596 if (v.getParent() == null) { 1597 // the notification panel has the most important things at the bottom 1598 mPile.addView(v, Math.min(toShow.size()-1-i, mPile.getChildCount())); 1599 } 1600 } 1601 1602 mNotificationPanel.setNotificationCount(toShow.size()); 1603 mNotificationPanel.setSettingsEnabled(isDeviceProvisioned()); 1604 } 1605 1606 @Override 1607 protected void workAroundBadLayerDrawableOpacity(View v) { 1608 Drawable bgd = v.getBackground(); 1609 if (!(bgd instanceof LayerDrawable)) return; 1610 1611 LayerDrawable d = (LayerDrawable) bgd; 1612 v.setBackgroundDrawable(null); 1613 d.setOpacity(PixelFormat.TRANSLUCENT); 1614 v.setBackgroundDrawable(d); 1615 } 1616 1617 public void clearAll() { 1618 try { 1619 mBarService.onClearAllNotifications(); 1620 } catch (RemoteException ex) { 1621 // system process is dead if we're here. 1622 } 1623 animateCollapse(); 1624 visibilityChanged(false); 1625 } 1626 1627 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1628 public void onReceive(Context context, Intent intent) { 1629 String action = intent.getAction(); 1630 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) 1631 || Intent.ACTION_SCREEN_OFF.equals(action)) { 1632 int flags = CommandQueue.FLAG_EXCLUDE_NONE; 1633 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { 1634 String reason = intent.getStringExtra("reason"); 1635 if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) { 1636 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 1637 } 1638 } 1639 if (Intent.ACTION_SCREEN_OFF.equals(action)) { 1640 // If we're turning the screen off, we want to hide the 1641 // recents panel with no animation 1642 // TODO: hide other things, like the notification tray, 1643 // with no animation as well 1644 mRecentsPanel.show(false, false); 1645 flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL; 1646 } 1647 animateCollapse(flags); 1648 } 1649 } 1650 }; 1651 1652 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1653 pw.print("mDisabled=0x"); 1654 pw.println(Integer.toHexString(mDisabled)); 1655 pw.println("mNetworkController:"); 1656 mNetworkController.dump(fd, pw, args); 1657 } 1658 1659 @Override 1660 protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) { 1661 if (parent == null || entry == null) return false; 1662 return parent.indexOfChild(entry.row) == parent.getChildCount()-1; 1663 } 1664 1665 @Override 1666 protected void haltTicker() { 1667 mTicker.halt(); 1668 } 1669 1670 @Override 1671 protected void updateExpandedViewPos(int expandedPosition) { 1672 } 1673 1674 @Override 1675 protected boolean shouldDisableNavbarGestures() { 1676 return mNotificationPanel.getVisibility() == View.VISIBLE 1677 || (mDisabled & StatusBarManager.DISABLE_HOME) != 0; 1678 } 1679} 1680 1681 1682