Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

HALO (1/2)

HALO is Androids one and only multitasking solution.

We explicitly do not go the Samsung/Cornerstone route. This solution is basically an extension of
the regular notificationshade, which is an aggregator for notifications that can be checked out when
time permits. HALO completes it by allowing you to respond to tasks on the spot, trying to be as
unintrusive as possible and flexible in regards to policies (white/black lists).

Features:

- Apps open up in floating state, apps underneath do not pause
- complete SystemUI & Core integration, making HALO feel like a native feature, source/SDK and UI/UX
- HALO has white and blacklists, which for now allow fine control for apps pinging through HALO
- multiple gestures to navigate HALO:
  - double-tap-move: move
  - tap-drag-left/right: task through notifications, finger up launches
  - tap-drag-up: dismiss notification
  - tap-drag-down: put HALO into semi-hidden state
  - swipe while HALO is hidden wakes it up
  - drag-to-X to remove HALO altogether
- comes with as few settings as possible, everything should be self explanatory and intutive,
  users must be informed about the double-tap gestures which is the only catch.

Known issues:

- Integration has been finished for PhoneUI. TabletUI and PIE must be integrated still.
- Packageinstaller must allow HALO through its overlay check or it will disable the install-app button.
- The low level has a few remaining issues:
  - Some apps still go up fullscale (they trick us with services, circumventing the intent flagging)
  - Some 3D games still pause
  - There is one known app that refuses to end on back or touch-outside, that is WeChat
  - The activitystack pause implementation works but is makeshift

To-Do:

- On-screen tutorial at first start up to teach users the gestures
- Fixing all known issues, full integration in the remaining UI's
- Perhaps hybrid engine integration for running floating apps in a decreased size

Merge branch 'multiwindow' into jellybean
commit 518c329e8c67fa96b8a8fc22e1962ddb8497c333 2 parents 3c308f1 + 4cbe154
drcmda drcmda authored

Showing 86 changed files with 2,144 additions and 122 deletions. Show diff stats Hide diff stats

  1. +74 3 core/java/android/app/Activity.java
  2. +1 6 core/java/android/app/ActivityThread.java
  3. +7 0 core/java/android/app/INotificationManager.aidl
  4. +15 3 core/java/android/app/TaskStackBuilder.java
  5. +5 1 core/java/android/content/Intent.java
  6. +18 0 core/java/android/provider/Settings.java
  7. +2 0  core/java/android/view/Window.java
  8. +4 4 core/java/com/android/internal/widget/ActionBarView.java
  9. BIN  core/res/res/drawable-nodpi/floating_frame.9.png
  10. +2 0  core/res/res/values/symbols.xml
  11. +24 0 core/res/res/values/themes_device_defaults.xml
  12. +6 0 packages/SystemUI/AndroidManifest.xml
  13. +9 0 packages/SystemUI/proguard.flags
  14. BIN  packages/SystemUI/res/drawable-hdpi/halo_back_left.png
  15. BIN  packages/SystemUI/res/drawable-hdpi/halo_back_right.png
  16. BIN  packages/SystemUI/res/drawable-hdpi/halo_bg.png
  17. BIN  packages/SystemUI/res/drawable-hdpi/halo_bigred.png
  18. BIN  packages/SystemUI/res/drawable-hdpi/halo_black_x.png
  19. BIN  packages/SystemUI/res/drawable-hdpi/halo_dismiss.png
  20. BIN  packages/SystemUI/res/drawable-hdpi/halo_marker_b.png
  21. BIN  packages/SystemUI/res/drawable-hdpi/halo_marker_l.png
  22. BIN  packages/SystemUI/res/drawable-hdpi/halo_marker_r.png
  23. BIN  packages/SystemUI/res/drawable-hdpi/halo_marker_t.png
  24. BIN  packages/SystemUI/res/drawable-hdpi/halo_number.9.png
  25. BIN  packages/SystemUI/res/drawable-hdpi/halo_pulse1.png
  26. BIN  packages/SystemUI/res/drawable-hdpi/halo_x.png
  27. BIN  packages/SystemUI/res/drawable-hdpi/ic_launcher_clear_active_holo.png
  28. BIN  packages/SystemUI/res/drawable-hdpi/ic_launcher_clear_normal_holo.png
  29. BIN  packages/SystemUI/res/drawable-hdpi/ic_notify_halo_normal.png
  30. BIN  packages/SystemUI/res/drawable-hdpi/ic_notify_halo_pressed.png
  31. BIN  packages/SystemUI/res/drawable-mdpi/halo_back_left.png
  32. BIN  packages/SystemUI/res/drawable-mdpi/halo_back_right.png
  33. BIN  packages/SystemUI/res/drawable-mdpi/halo_bg.png
  34. BIN  packages/SystemUI/res/drawable-mdpi/halo_bigred.png
  35. BIN  packages/SystemUI/res/drawable-mdpi/halo_black_x.png
  36. BIN  packages/SystemUI/res/drawable-mdpi/halo_dismiss.png
  37. BIN  packages/SystemUI/res/drawable-mdpi/halo_marker_b.png
  38. BIN  packages/SystemUI/res/drawable-mdpi/halo_marker_l.png
  39. BIN  packages/SystemUI/res/drawable-mdpi/halo_marker_r.png
  40. BIN  packages/SystemUI/res/drawable-mdpi/halo_marker_t.png
  41. BIN  packages/SystemUI/res/drawable-mdpi/halo_number.9.png
  42. BIN  packages/SystemUI/res/drawable-mdpi/halo_pulse1.png
  43. BIN  packages/SystemUI/res/drawable-mdpi/halo_x.png
  44. BIN  packages/SystemUI/res/drawable-mdpi/ic_launcher_clear_active_holo.png
  45. BIN  packages/SystemUI/res/drawable-mdpi/ic_launcher_clear_normal_holo.png
  46. BIN  packages/SystemUI/res/drawable-mdpi/ic_notify_halo_normal.png
  47. BIN  packages/SystemUI/res/drawable-mdpi/ic_notify_halo_pressed.png
  48. BIN  packages/SystemUI/res/drawable-nodpi/bubble_black_l.9.png
  49. BIN  packages/SystemUI/res/drawable-nodpi/bubble_black_r.9.png
  50. BIN  packages/SystemUI/res/drawable-nodpi/bubble_l.9.png
  51. BIN  packages/SystemUI/res/drawable-nodpi/bubble_r.9.png
  52. BIN  packages/SystemUI/res/drawable-xhdpi/halo_back_left.png
  53. BIN  packages/SystemUI/res/drawable-xhdpi/halo_back_right.png
  54. BIN  packages/SystemUI/res/drawable-xhdpi/halo_bg.png
  55. BIN  packages/SystemUI/res/drawable-xhdpi/halo_bigred.png
  56. BIN  packages/SystemUI/res/drawable-xhdpi/halo_black_x.png
  57. BIN  packages/SystemUI/res/drawable-xhdpi/halo_dismiss.png
  58. BIN  packages/SystemUI/res/drawable-xhdpi/halo_marker_b.png
  59. BIN  packages/SystemUI/res/drawable-xhdpi/halo_marker_l.png
  60. BIN  packages/SystemUI/res/drawable-xhdpi/halo_marker_r.png
  61. BIN  packages/SystemUI/res/drawable-xhdpi/halo_marker_t.png
  62. BIN  packages/SystemUI/res/drawable-xhdpi/halo_number.9.png
  63. BIN  packages/SystemUI/res/drawable-xhdpi/halo_pulse1.png
  64. BIN  packages/SystemUI/res/drawable-xhdpi/halo_x.png
  65. BIN  packages/SystemUI/res/drawable-xhdpi/ic_notify_halo_normal.png
  66. BIN  packages/SystemUI/res/drawable-xhdpi/ic_notify_halo_pressed.png
  67. +36 0 packages/SystemUI/res/layout/halo_bubble.xml
  68. +22 0 packages/SystemUI/res/layout/halo_number.xml
  69. +49 0 packages/SystemUI/res/layout/halo_speech.xml
  70. +7 0 packages/SystemUI/res/layout/halo_trigger.xml
  71. +11 1 packages/SystemUI/res/layout/status_bar_expanded_header.xml
  72. +1 0  packages/SystemUI/res/values-land/dimens.xml
  73. +2 0  packages/SystemUI/res/values/dimens.xml
  74. +3 0  packages/SystemUI/res/values/strings.xml
  75. +20 0 packages/SystemUI/src/com/android/systemui/Transparent.java
  76. +144 10 packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
  77. +17 0 packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
  78. +90 0 packages/SystemUI/src/com/android/systemui/statusbar/halo/CustomObjectAnimator.java
  79. +1,092 0 packages/SystemUI/src/com/android/systemui/statusbar/halo/Halo.java
  80. +164 0 packages/SystemUI/src/com/android/systemui/statusbar/halo/HaloProperties.java
  81. +73 23 packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
  82. +32 17 packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
  83. +1 0  packages/SystemUI/src/com/android/systemui/statusbar/view/PieStatusPanel.java
  84. +147 41 services/java/com/android/server/NotificationManagerService.java
  85. +53 1 services/java/com/android/server/am/ActivityRecord.java
  86. +13 12 services/java/com/android/server/am/ActivityStack.java
77 core/java/android/app/Activity.java
@@ -59,13 +59,17 @@
59 59 import android.util.ColorUtils;
60 60 import android.util.EventLog;
61 61 import android.util.ExtendedPropertiesUtils;
  62 +import android.util.DisplayMetrics;
62 63 import android.util.Log;
  64 +import android.util.TypedValue;
63 65 import android.util.Slog;
64 66 import android.util.SparseArray;
65 67 import android.view.ActionMode;
66 68 import android.view.ContextMenu;
67 69 import android.view.ContextMenu.ContextMenuInfo;
68 70 import android.view.ContextThemeWrapper;
  71 +import android.view.Display;
  72 +import android.view.Gravity;
69 73 import android.view.KeyEvent;
70 74 import android.view.LayoutInflater;
71 75 import android.view.Menu;
@@ -1463,6 +1467,9 @@ public void onConfigurationChanged(Configuration newConfig) {
1463 1467 if (mWindow != null) {
1464 1468 // Pass the configuration changed event to the window
1465 1469 mWindow.onConfigurationChanged(newConfig);
  1470 + if (mWindow.mIsFloatingWindow) {
  1471 + scaleFloatingWindow(null);
  1472 + }
1466 1473 }
1467 1474
1468 1475 if (mActionBar != null) {
@@ -5060,11 +5067,47 @@ final void attach(Context context, ActivityThread aThread,
5060 5067 CharSequence title, Activity parent, String id,
5061 5068 NonConfigurationInstances lastNonConfigurationInstances,
5062 5069 Configuration config) {
  5070 +
5063 5071 attachBaseContext(context);
5064 5072
5065 5073 mFragments.attachActivity(this, mContainer, null);
5066   -
5067   - mWindow = PolicyManager.makeNewWindow(this);
  5074 +
  5075 + boolean floating = (intent.getFlags()&Intent.FLAG_FLOATING_WINDOW) == Intent.FLAG_FLOATING_WINDOW;
  5076 + if (intent != null && floating) {
  5077 + TypedArray styleArray = context.obtainStyledAttributes(info.theme, com.android.internal.R.styleable.Window);
  5078 + TypedValue backgroundValue = styleArray.peekValue(com.android.internal.R.styleable.Window_windowBackground);
  5079 +
  5080 + // Apps that have no title don't need no title bar
  5081 + TypedValue outValue = new TypedValue();
  5082 + boolean result = styleArray.getValue(com.android.internal.R.styleable.Window_windowNoTitle, outValue);
  5083 +
  5084 + if (backgroundValue != null && backgroundValue.toString().contains("light")) {
  5085 + context.getTheme().applyStyle(com.android.internal.R.style.Theme_DeviceDefault_FloatingWindowLight, true);
  5086 + } else {
  5087 + context.getTheme().applyStyle(com.android.internal.R.style.Theme_DeviceDefault_FloatingWindow, true);
  5088 + }
  5089 +
  5090 + parent = null;
  5091 +
  5092 + // Create our new window
  5093 + mWindow = PolicyManager.makeNewWindow(this);
  5094 + mWindow.mIsFloatingWindow = true;
  5095 + mWindow.setCloseOnTouchOutsideIfNotSet(true);
  5096 + mWindow.setGravity(Gravity.CENTER);
  5097 +
  5098 + mWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
  5099 + WindowManager.LayoutParams.FLAG_DIM_BEHIND);
  5100 + WindowManager.LayoutParams params = mWindow.getAttributes();
  5101 + params.alpha = 1f;
  5102 + params.dimAmount = 0.25f;
  5103 + mWindow.setAttributes((android.view.WindowManager.LayoutParams) params);
  5104 +
  5105 + // Scale it
  5106 + scaleFloatingWindow(context);
  5107 + } else {
  5108 + mWindow = PolicyManager.makeNewWindow(this);
  5109 + }
  5110 +
5068 5111 mWindow.setCallback(this);
5069 5112 mWindow.getLayoutInflater().setPrivateFactory(this);
5070 5113 if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
@@ -5099,6 +5142,26 @@ final void attach(Context context, ActivityThread aThread,
5099 5142 mCurrentConfig = config;
5100 5143 }
5101 5144
  5145 + private void scaleFloatingWindow(Context context) {
  5146 + if (!mWindow.mIsFloatingWindow) {
  5147 + return;
  5148 + }
  5149 + WindowManager wm = null;
  5150 + if (context != null) {
  5151 + wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  5152 + } else {
  5153 + wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
  5154 + }
  5155 + Display display = wm.getDefaultDisplay();
  5156 + DisplayMetrics metrics = new DisplayMetrics();
  5157 + display.getMetrics(metrics);
  5158 + if (metrics.heightPixels > metrics.widthPixels) {
  5159 + mWindow.setLayout((int)(metrics.widthPixels * 0.9f), (int)(metrics.heightPixels * 0.7f));
  5160 + } else {
  5161 + mWindow.setLayout((int)(metrics.widthPixels * 0.7f), (int)(metrics.heightPixels * 0.8f));
  5162 + }
  5163 + }
  5164 +
5102 5165 /** @hide */
5103 5166 public final IBinder getActivityToken() {
5104 5167 return mParent != null ? mParent.getActivityToken() : mToken;
@@ -5265,7 +5328,7 @@ final void performUserLeaving() {
5265 5328 onUserInteraction();
5266 5329 onUserLeaveHint();
5267 5330 }
5268   -
  5331 +
5269 5332 final void performStop() {
5270 5333 if (mLoadersStarted) {
5271 5334 mLoadersStarted = false;
@@ -5311,6 +5374,14 @@ final void performStop() {
5311 5374 mStopped = true;
5312 5375 }
5313 5376 mResumed = false;
  5377 +
  5378 + // Floatingwindows activities should be kept volatile to prevent new activities taking
  5379 + // up front in a minimized space. Every stop call, for instance when pressing home,
  5380 + // will terminate the activity. If the activity is already finishing we might just
  5381 + // as well let it go.
  5382 + if (!mChangingConfigurations && mWindow != null && mWindow.mIsFloatingWindow && !isFinishing()) {
  5383 + finish();
  5384 + }
5314 5385 }
5315 5386
5316 5387 final void performDestroy() {
7 core/java/android/app/ActivityThread.java
@@ -2871,12 +2871,7 @@ public final ActivityClientRecord performResumeActivity(IBinder token,
2871 2871 r.stopped = false;
2872 2872 r.state = null;
2873 2873 } catch (Exception e) {
2874   - if (!mInstrumentation.onException(r.activity, e)) {
2875   - throw new RuntimeException(
2876   - "Unable to resume activity "
2877   - + r.intent.getComponent().toShortString()
2878   - + ": " + e.toString(), e);
2879   - }
  2874 + // Unable to resume activity
2880 2875 }
2881 2876 }
2882 2877 return r;
7 core/java/android/app/INotificationManager.aidl
@@ -34,5 +34,12 @@ interface INotificationManager
34 34
35 35 void setNotificationsEnabledForPackage(String pkg, boolean enabled);
36 36 boolean areNotificationsEnabledForPackage(String pkg);
  37 +
  38 + void setHaloPolicyBlack(boolean state);
  39 + void setHaloStatus(String pkg, boolean status);
  40 + void setHaloBlacklistStatus(String pkg, boolean status);
  41 + void setHaloWhitelistStatus(String pkg, boolean status);
  42 + boolean isHaloPolicyBlack();
  43 + boolean isPackageAllowedForHalo(String pkg);
37 44 }
38 45
18 core/java/android/app/TaskStackBuilder.java
@@ -62,6 +62,7 @@
62 62
63 63 private final ArrayList<Intent> mIntents = new ArrayList<Intent>();
64 64 private final Context mSourceContext;
  65 + private boolean mFirstTaskOnHome = true;
65 66
66 67 private TaskStackBuilder(Context a) {
67 68 mSourceContext = a;
@@ -78,6 +79,10 @@ public static TaskStackBuilder create(Context context) {
78 79 return new TaskStackBuilder(context);
79 80 }
80 81
  82 + public void setTaskOnHome(boolean firstTaskOnHome) {
  83 + mFirstTaskOnHome = firstTaskOnHome;
  84 + }
  85 +
81 86 /**
82 87 * Add a new Intent to the task stack. The most recently added Intent will invoke
83 88 * the Activity at the top of the final task stack.
@@ -298,9 +303,16 @@ public PendingIntent getPendingIntent(int requestCode, int flags, Bundle options
298 303 Intent[] intents = new Intent[mIntents.size()];
299 304 if (intents.length == 0) return intents;
300 305
301   - intents[0] = new Intent(mIntents.get(0)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
302   - Intent.FLAG_ACTIVITY_CLEAR_TASK |
303   - Intent.FLAG_ACTIVITY_TASK_ON_HOME);
  306 + Intent newIntent = new Intent(mIntents.get(0));
  307 + newIntent.addFlags(
  308 + Intent.FLAG_ACTIVITY_NEW_TASK |
  309 + Intent.FLAG_ACTIVITY_CLEAR_TASK);
  310 +
  311 + if (mFirstTaskOnHome) {
  312 + newIntent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
  313 + }
  314 +
  315 + intents[0] = newIntent;
304 316 for (int i = 1; i < intents.length; i++) {
305 317 intents[i] = new Intent(mIntents.get(i));
306 318 }
6 core/java/android/content/Intent.java
@@ -3101,7 +3101,6 @@ public static Intent createChooser(Intent target, CharSequence title) {
3101 3101 * places where the framework may automatically set the exclude flag).
3102 3102 */
3103 3103 public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020;
3104   -
3105 3104 /**
3106 3105 * If set, the new activity is not kept in the history stack. As soon as
3107 3106 * the user navigates away from it, the activity is finished. This may also
@@ -3318,6 +3317,11 @@ public static Intent createChooser(Intent target, CharSequence title) {
3318 3317 */
3319 3318 public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0X00004000;
3320 3319 /**
  3320 + * If set, this intent will always match start up as a floating window
  3321 + * in mutil window scenarios.
  3322 + */
  3323 + public static final int FLAG_FLOATING_WINDOW = 0x00002000;
  3324 + /**
3321 3325 * If set, when sending a broadcast only registered receivers will be
3322 3326 * called -- no BroadcastReceiver components will be launched.
3323 3327 */
18 core/java/android/provider/Settings.java
@@ -2561,6 +2561,24 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean
2561 2561 public static final String DISABLE_FULLSCREEN_KEYBOARD = "disable_fullscreen_keyboard";
2562 2562
2563 2563 /**
  2564 + * HALO, should default to 0 (no, do not show)
  2565 + * @hide
  2566 + */
  2567 + public static final String HALO_ACTIVE = "halo_active";
  2568 +
  2569 + /**
  2570 + * HALO reversed?, should default to 1 (yes, reverse)
  2571 + * @hide
  2572 + */
  2573 + public static final String HALO_REVERSED = "halo_reversed";
  2574 +
  2575 + /**
  2576 + * HALO hide?, should default to 0 (no, do not hide)
  2577 + * @hide
  2578 + */
  2579 + public static final String HALO_HIDE = "halo_hide";
  2580 +
  2581 + /**
2564 2582 * Pie menu, should default to 1 (yes, show)
2565 2583 * @hide
2566 2584 */
2  core/java/android/view/Window.java
@@ -152,6 +152,8 @@
152 152
153 153 private boolean mDestroyed;
154 154
  155 + public boolean mIsFloatingWindow = false;
  156 +
155 157 // The current window attributes.
156 158 private final WindowManager.LayoutParams mWindowAttributes =
157 159 new WindowManager.LayoutParams();
8 core/java/com/android/internal/widget/ActionBarView.java
@@ -904,14 +904,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
904 904
905 905 int widthMode = MeasureSpec.getMode(widthMeasureSpec);
906 906 if (widthMode != MeasureSpec.EXACTLY) {
907   - throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
908   - "with android:layout_width=\"match_parent\" (or fill_parent)");
  907 + //throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
  908 + // "with android:layout_width=\"match_parent\" (or fill_parent)");
909 909 }
910 910
911 911 int heightMode = MeasureSpec.getMode(heightMeasureSpec);
912 912 if (heightMode != MeasureSpec.AT_MOST) {
913   - throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
914   - "with android:layout_height=\"wrap_content\"");
  913 + //throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
  914 + // "with android:layout_height=\"wrap_content\"");
915 915 }
916 916
917 917 int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
BIN  core/res/res/drawable-nodpi/floating_frame.9.png
2  core/res/res/values/symbols.xml
@@ -1159,6 +1159,8 @@
1159 1159 <java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
1160 1160 <java-symbol type="style" name="Theme.IconMenu" />
1161 1161 <java-symbol type="style" name="Theme.Panel.Volume" />
  1162 + <java-symbol type="style" name="Theme.DeviceDefault.FloatingWindow" />
  1163 + <java-symbol type="style" name="Theme.DeviceDefault.FloatingWindowLight" />
1162 1164
1163 1165 <java-symbol type="attr" name="mediaRouteButtonStyle" />
1164 1166 <java-symbol type="attr" name="externalRouteEnabledDrawable" />
24 core/res/res/values/themes_device_defaults.xml
@@ -485,8 +485,32 @@ easier.
485 485 decorations, so you basically have an empty rectangle in which to place your content. It makes
486 486 the window floating, with a transparent background, and turns off dimming behind the window. -->
487 487 <style name="Theme.DeviceDefault.Panel" parent="Theme.Holo.Panel" >
  488 + </style>
  489 +
  490 + <style name="Theme.DeviceDefault.FloatingWindow">
  491 + <item name="android:windowIsFloating">false</item>
  492 + <item name="android:windowIsTranslucent">true</item>
  493 + <item name="android:windowFrame">@null</item>
  494 + <item name="android:windowContentOverlay">@null</item>
  495 + <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
  496 + <item name="android:windowActionModeOverlay">true</item>
  497 + <item name="android:windowCloseOnTouchOutside">true</item>
  498 + <item name="android:windowFullscreen">false</item>
  499 + <item name="android:windowSoftInputMode">stateAlwaysHidden|adjustPan</item>
  500 + </style>
488 501
  502 + <style name="Theme.DeviceDefault.FloatingWindowLight" parent="Theme.Holo.Light.Dialog">
  503 + <item name="android:windowIsFloating">false</item>
  504 + <item name="android:windowIsTranslucent">true</item>
  505 + <item name="android:windowFrame">@null</item>
  506 + <item name="android:windowContentOverlay">@null</item>
  507 + <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
  508 + <item name="android:windowActionModeOverlay">true</item>
  509 + <item name="android:windowCloseOnTouchOutside">true</item>
  510 + <item name="android:windowFullscreen">false</item>
  511 + <item name="android:windowSoftInputMode">stateAlwaysHidden|adjustPan</item>
489 512 </style>
  513 +
490 514 <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
491 515 decorations, so you basically have an empty rectangle in which to place your content. It makes
492 516 the window floating, with a transparent background, and turns off dimming behind the window. -->
6 packages/SystemUI/AndroidManifest.xml
@@ -74,6 +74,9 @@
74 74 <uses-permission android:name="android.permission.READ_DREAM_STATE" />
75 75 <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
76 76
  77 + <!--Halo-->
  78 + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
  79 +
77 80 <application
78 81 android:persistent="true"
79 82 android:allowClearUserData="false"
@@ -243,5 +246,8 @@
243 246 <category android:name="android.intent.category.DESK_DOCK" />
244 247 </intent-filter>
245 248 </activity>
  249 +
  250 + <activity android:name="com.android.systemui.Transparent"
  251 + android:theme="@android:style/Theme.Translucent.NoTitleBar" />
246 252 </application>
247 253 </manifest>
9 packages/SystemUI/proguard.flags
@@ -14,4 +14,13 @@
14 14 public void setGlowScale(float);
15 15 }
16 16
  17 +-keep class com.android.systemui.statusbar.halo.HaloProperties {
  18 + public int getHaloX();
  19 + public int getHaloY();
  20 + public float getHaloContentAlpha();
  21 + public void setHaloX(int);
  22 + public void setHaloY(int);
  23 + public void setHaloContentAlpha(float);
  24 +}
  25 +
17 26 -keep class com.android.systemui.statusbar.tv.TvStatusBar
BIN  packages/SystemUI/res/drawable-hdpi/halo_back_left.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_back_right.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_bg.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_bigred.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_black_x.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_dismiss.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_marker_b.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_marker_l.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_marker_r.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_marker_t.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_number.9.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_pulse1.png
BIN  packages/SystemUI/res/drawable-hdpi/halo_x.png
BIN  packages/SystemUI/res/drawable-hdpi/ic_launcher_clear_active_holo.png
BIN  packages/SystemUI/res/drawable-hdpi/ic_launcher_clear_normal_holo.png
BIN  packages/SystemUI/res/drawable-hdpi/ic_notify_halo_normal.png
BIN  packages/SystemUI/res/drawable-hdpi/ic_notify_halo_pressed.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_back_left.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_back_right.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_bg.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_bigred.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_black_x.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_dismiss.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_marker_b.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_marker_l.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_marker_r.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_marker_t.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_number.9.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_pulse1.png
BIN  packages/SystemUI/res/drawable-mdpi/halo_x.png
BIN  packages/SystemUI/res/drawable-mdpi/ic_launcher_clear_active_holo.png
BIN  packages/SystemUI/res/drawable-mdpi/ic_launcher_clear_normal_holo.png
BIN  packages/SystemUI/res/drawable-mdpi/ic_notify_halo_normal.png
BIN  packages/SystemUI/res/drawable-mdpi/ic_notify_halo_pressed.png
BIN  packages/SystemUI/res/drawable-nodpi/bubble_black_l.9.png
BIN  packages/SystemUI/res/drawable-nodpi/bubble_black_r.9.png
BIN  packages/SystemUI/res/drawable-nodpi/bubble_l.9.png
BIN  packages/SystemUI/res/drawable-nodpi/bubble_r.9.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_back_left.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_back_right.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_bg.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_bigred.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_black_x.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_dismiss.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_marker_b.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_marker_l.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_marker_r.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_marker_t.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_number.9.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_pulse1.png
BIN  packages/SystemUI/res/drawable-xhdpi/halo_x.png
BIN  packages/SystemUI/res/drawable-xhdpi/ic_notify_halo_normal.png
BIN  packages/SystemUI/res/drawable-xhdpi/ic_notify_halo_pressed.png
36 packages/SystemUI/res/layout/halo_bubble.xml
... ... @@ -0,0 +1,36 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<FrameLayout
  3 + xmlns:android="http://schemas.android.com/apk/res/android"
  4 + xmlns:tools="http://schemas.android.com/tools"
  5 + android:layout_width="wrap_content"
  6 + android:layout_height="wrap_content">
  7 +
  8 + <RelativeLayout
  9 + android:id="@+id/halo_content"
  10 + android:layout_width="wrap_content"
  11 + android:layout_height="wrap_content">
  12 +
  13 + <ImageView
  14 + android:id="@+id/halo_bg"
  15 + android:layout_width="wrap_content"
  16 + android:layout_height="wrap_content"
  17 + android:src="@drawable/halo_bg"/>
  18 +
  19 + <ImageView
  20 + android:id="@+id/app_icon"
  21 + android:layout_width="wrap_content"
  22 + android:layout_height="wrap_content"
  23 + android:layout_centerVertical="true"
  24 + android:layout_centerHorizontal="true"/>
  25 +
  26 + <ImageView
  27 + android:id="@+id/halo_overlay"
  28 + android:layout_width="wrap_content"
  29 + android:layout_height="wrap_content"
  30 + android:layout_centerVertical="true"
  31 + android:layout_centerHorizontal="true"
  32 + android:alpha="0"/>
  33 +
  34 + </RelativeLayout>
  35 +
  36 +</FrameLayout>
22 packages/SystemUI/res/layout/halo_number.xml
... ... @@ -0,0 +1,22 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout
  3 + xmlns:android="http://schemas.android.com/apk/res/android"
  4 + xmlns:tools="http://schemas.android.com/tools"
  5 + android:layout_width="wrap_content"
  6 + android:layout_height="wrap_content">
  7 +
  8 + <TextView
  9 + android:id="@+id/number"
  10 + android:animateLayoutChanges="true"
  11 + android:layout_width="wrap_content"
  12 + android:layout_height="wrap_content"
  13 + android:paddingLeft="5dp"
  14 + android:paddingRight="5dp"
  15 + android:paddingTop="2dp"
  16 + android:paddingBottom="2dp"
  17 + android:background="@drawable/halo_number"
  18 + android:textColor="#fff"
  19 + android:textStyle="bold"
  20 + android:textSize="16sp"/>
  21 +
  22 +</LinearLayout>
49 packages/SystemUI/res/layout/halo_speech.xml
... ... @@ -0,0 +1,49 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout
  3 + xmlns:android="http://schemas.android.com/apk/res/android"
  4 + xmlns:tools="http://schemas.android.com/tools"
  5 + android:layout_width="wrap_content"
  6 + android:layout_height="wrap_content">
  7 +
  8 + <RelativeLayout
  9 + android:layout_width="@dimen/halo_content_max_width"
  10 + android:layout_height="wrap_content">
  11 +
  12 + <RelativeLayout
  13 + android:id="@+id/ticker"
  14 + android:layout_width="wrap_content"
  15 + android:layout_height="wrap_content">
  16 +
  17 + <TextView
  18 + android:id="@+id/bubble_r"
  19 + android:layout_width="wrap_content"
  20 + android:layout_height="wrap_content"
  21 + android:paddingLeft="20dp"
  22 + android:paddingRight="20dp"
  23 + android:paddingTop="17dp"
  24 + android:paddingBottom="30dp"
  25 + android:background="@drawable/bubble_black_r"
  26 + android:singleLine="false"
  27 + android:textColor="#ffffff"
  28 + android:maxLines = "3"
  29 + android:visibility="gone"/>
  30 +
  31 + <TextView
  32 + android:id="@+id/bubble_l"
  33 + android:layout_width="wrap_content"
  34 + android:layout_height="wrap_content"
  35 + android:paddingLeft="20dp"
  36 + android:paddingRight="20dp"
  37 + android:paddingTop="17dp"
  38 + android:paddingBottom="30dp"
  39 + android:background="@drawable/bubble_black_l"
  40 + android:singleLine="false"
  41 + android:textColor="#ffffff"
  42 + android:maxLines = "3"
  43 + android:visibility="gone"/>
  44 +
  45 + </RelativeLayout>
  46 +
  47 + </RelativeLayout>
  48 +
  49 +</LinearLayout>
7 packages/SystemUI/res/layout/halo_trigger.xml
... ... @@ -0,0 +1,7 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<com.android.systemui.statusbar.halo.Halo
  3 + xmlns:android="http://schemas.android.com/apk/res/android"
  4 + xmlns:tools="http://schemas.android.com/tools"
  5 + android:layout_width="match_parent"
  6 + android:layout_height="match_parent">
  7 +</com.android.systemui.statusbar.halo.Halo>
12 packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -74,9 +74,19 @@
74 74 android:padding="2dp"
75 75 />
76 76
  77 + <ImageView android:id="@+id/halo_button"
  78 + android:layout_width="50dp"
  79 + android:layout_height="50dp"
  80 + android:scaleType="center"
  81 + android:src="@drawable/ic_notify_halo_normal"
  82 + android:background="@drawable/ic_notify_button_bg"
  83 + android:contentDescription="@string/accessibility_halo"
  84 + />
  85 +
77 86 <ImageView android:id="@+id/clear_all_button"
78 87 android:layout_width="50dp"
79 88 android:layout_height="50dp"
  89 + android:layout_marginLeft="5dp"
80 90 android:scaleType="center"
81 91 android:src="@drawable/ic_notify_clear"
82 92 android:background="@drawable/ic_notify_button_bg"
@@ -86,7 +96,7 @@
86 96 <FrameLayout android:id="@+id/settings_button_holder"
87 97 android:layout_width="50dp"
88 98 android:layout_height="50dp"
89   - android:layout_marginLeft="12dp"
  99 + android:layout_marginLeft="5dp"
90 100 >
91 101 <ImageView android:id="@+id/settings_button"
92 102 android:layout_width="50dp"
1  packages/SystemUI/res/values-land/dimens.xml
@@ -42,4 +42,5 @@
42 42 <dimen name="quick_settings_cell_height">100dp</dimen>
43 43
44 44 <dimen name="pie_panel_padding">100dp</dimen>
  45 + <dimen name="halo_content_max_width">350dp</dimen>
45 46 </resources>
2  packages/SystemUI/res/values/dimens.xml
@@ -242,4 +242,6 @@
242 242 <dimen name="pie_panel_padding">20dp</dimen>
243 243 <!-- PIE PIE PIE PIE PIE PIE PIE PIE PIE PIE PIE PIE PIE PIE -->
244 244
  245 + <dimen name="halo_content_max_width">250dp</dimen>
  246 +
245 247 </resources>
3  packages/SystemUI/res/values/strings.xml
@@ -436,6 +436,9 @@
436 436 <!-- Notification text: when GPS has found a fix [CHAR LIMIT=50] -->
437 437 <string name="gps_notification_found_text">Location set by GPS</string>
438 438
  439 + <!-- Content description of the halo button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
  440 + <string name="accessibility_halo">Create notification halo.</string>
  441 +
439 442 <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
440 443 <string name="accessibility_clear_all">Clear all notifications.</string>
441 444
20 packages/SystemUI/src/com/android/systemui/Transparent.java
... ... @@ -0,0 +1,20 @@
  1 +package com.android.systemui;
  2 +
  3 +import android.app.Activity;
  4 +import android.os.Handler;
  5 +
  6 +public class Transparent extends Activity {
  7 +
  8 + @Override
  9 + public void onStart() {
  10 + super.onStart();
  11 +
  12 + new Handler().postDelayed(new Runnable() {
  13 +
  14 + @Override
  15 + public void run() {
  16 + Transparent.this.finish();
  17 + }
  18 + }, 500);
  19 + }
  20 +}
154 packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -25,6 +25,7 @@
25 25 import android.app.TaskStackBuilder;
26 26 import android.content.ActivityNotFoundException;
27 27 import android.content.BroadcastReceiver;
  28 +import android.content.ComponentName;
28 29 import android.content.ContentResolver;
29 30 import android.content.Context;
30 31 import android.content.Intent;
@@ -45,6 +46,7 @@
45 46 import android.graphics.PixelFormat;
46 47 import android.graphics.PorterDuff;
47 48 import android.graphics.PorterDuff.Mode;
  49 +import android.graphics.PorterDuffXfermode;
48 50 import android.graphics.Rect;
49 51 import android.net.Uri;
50 52 import android.os.Build;
@@ -90,7 +92,9 @@
90 92 import com.android.systemui.recent.RecentTasksLoader;
91 93 import com.android.systemui.recent.RecentsActivity;
92 94 import com.android.systemui.recent.TaskDescription;
  95 +import com.android.systemui.statusbar.halo.Halo;
93 96 import com.android.systemui.statusbar.phone.QuickSettingsContainerView;
  97 +import com.android.systemui.statusbar.phone.Ticker;
94 98 import com.android.systemui.statusbar.policy.BatteryController;
95 99 import com.android.systemui.statusbar.policy.Clock;
96 100 import com.android.systemui.statusbar.policy.NetworkController;
@@ -155,6 +159,14 @@
155 159 public View[] mPieDummyTrigger = new View[4];
156 160 int mIndex;
157 161
  162 + // Halo
  163 + protected Halo mHalo = null;
  164 + protected Ticker mTicker;
  165 + protected boolean mHaloActive;
  166 + protected boolean mHaloTaskerActive = false;
  167 + protected ImageView mHaloButton;
  168 + protected boolean mHaloButtonVisible = true;
  169 +
158 170 // Policy
159 171 public NetworkController mNetworkController;
160 172 public BatteryController mBatteryController;
@@ -188,6 +200,10 @@
188 200
189 201 private boolean mDeviceProvisioned = false;
190 202
  203 + public Ticker getTicker() {
  204 + return mTicker;
  205 + }
  206 +
191 207 public void collapse() {
192 208 }
193 209
@@ -366,6 +382,9 @@ public void start() {
366 382 // If the system process isn't there we're doomed anyway.
367 383 }
368 384
  385 + mHaloActive = Settings.System.getInt(mContext.getContentResolver(),
  386 + Settings.System.HALO_ACTIVE, 0) == 1;
  387 +
369 388 createAndAddWindows();
370 389
371 390 disable(switches[0]);
@@ -494,10 +513,58 @@ public void onChange(boolean selfChange) {
494 513
495 514 attachPie();
496 515
  516 + // Listen for HALO state
  517 + mContext.getContentResolver().registerContentObserver(
  518 + Settings.System.getUriFor(Settings.System.HALO_ACTIVE), false, new ContentObserver(new Handler()) {
  519 + @Override
  520 + public void onChange(boolean selfChange) {
  521 + updateHalo();
  522 + }});
  523 +
  524 + updateHalo();
  525 +
497 526 SettingsObserver settingsObserver = new SettingsObserver(new Handler());
498 527 settingsObserver.observe();
499 528 }
500 529
  530 + public void setHaloTaskerActive(boolean haloTaskerActive, boolean updateNotificationIcons) {
  531 + mHaloTaskerActive = haloTaskerActive;
  532 + if (updateNotificationIcons) {
  533 + updateNotificationIcons();
  534 + }
  535 + }
  536 +
  537 + protected void updateHaloButton() {
  538 + if (mHaloButton != null) {
  539 + mHaloButton.setVisibility(mHaloButtonVisible && !mHaloActive ? View.VISIBLE : View.GONE);
  540 + }
  541 + }
  542 +
  543 + protected void updateHalo() {
  544 + mHaloActive = Settings.System.getInt(mContext.getContentResolver(),
  545 + Settings.System.HALO_ACTIVE, 0) == 1;
  546 +
  547 + updateHaloButton();
  548 +
  549 + if (mHaloActive) {
  550 + if (mHalo == null) {
  551 + LayoutInflater inflater = (LayoutInflater) mContext
  552 + .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  553 + mHalo = (Halo)inflater.inflate(R.layout.halo_trigger, null);
  554 + mHalo.setLayerType (View.LAYER_TYPE_HARDWARE, null);
  555 + WindowManager.LayoutParams params = mHalo.getWMParams();
  556 + mWindowManager.addView(mHalo,params);
  557 + mHalo.setStatusBar(this);
  558 + }
  559 + } else {
  560 + if (mHalo != null) {
  561 + mHalo.cleanUp();
  562 + mWindowManager.removeView(mHalo);
  563 + mHalo = null;
  564 + }
  565 + }
  566 + }
  567 +
501 568 private boolean showPie() {
502 569 boolean expanded = Settings.System.getInt(mContext.getContentResolver(),
503 570 Settings.System.EXPANDED_DESKTOP_STATE, 0) == 1;
@@ -1234,11 +1301,12 @@ public NotificationClicker makeClicker(PendingIntent intent, String pkg, String
1234 1301 return new NotificationClicker(intent, pkg, tag, id);
1235 1302 }
1236 1303
1237   - private class NotificationClicker implements View.OnClickListener {
1238   - private PendingIntent mIntent;
1239   - private String mPkg;
1240   - private String mTag;
1241   - private int mId;
  1304 + public class NotificationClicker implements View.OnClickListener {
  1305 + public PendingIntent mIntent;
  1306 + public String mPkg;
  1307 + public String mTag;
  1308 + public int mId;
  1309 + public boolean mFloat;
1242 1310
1243 1311 NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
1244 1312 mIntent = intent;
@@ -1247,6 +1315,10 @@ public NotificationClicker makeClicker(PendingIntent intent, String pkg, String
1247 1315 mId = id;
1248 1316 }
1249 1317
  1318 + public void makeFloating(boolean floating) {
  1319 + mFloat = floating;
  1320 + }
  1321 +
1250 1322 public void onClick(View v) {
1251 1323 try {
1252 1324 // The intent we are sending is for the application, which
@@ -1261,9 +1333,17 @@ public void onClick(View v) {
1261 1333 }
1262 1334
1263 1335 if (mIntent != null) {
  1336 +
  1337 + if (mFloat && !"android".equals(mPkg) && !"com.paranoid.halo".equals(mPkg)) {
  1338 + Intent transparent = new Intent(mContext, com.android.systemui.Transparent.class);
  1339 + transparent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_FLOATING_WINDOW);
  1340 + mContext.startActivity(transparent);
  1341 + }
  1342 +
1264 1343 int[] pos = new int[2];
1265 1344 v.getLocationOnScreen(pos);
1266 1345 Intent overlay = new Intent();
  1346 + if (mFloat) overlay.addFlags(Intent.FLAG_FLOATING_WINDOW | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1267 1347 overlay.setSourceBounds(
1268 1348 new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
1269 1349 try {
@@ -1340,6 +1420,41 @@ protected StatusBarNotification removeNotificationViews(IBinder key) {
1340 1420 return entry.notification;
1341 1421 }
1342 1422
  1423 + private Bitmap createRoundIcon(StatusBarNotification notification) {
  1424 + // Construct the round icon
  1425 + BitmapDrawable bd = (BitmapDrawable) mContext.getResources().getDrawable(R.drawable.halo_bg);
  1426 + int iconSize = bd.getBitmap().getWidth();
  1427 + int smallIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size);
  1428 + Bitmap roundIcon = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
  1429 + Canvas canvas = new Canvas(roundIcon);
  1430 + canvas.drawARGB(0, 0, 0, 0);
  1431 +
  1432 + if (notification.notification.largeIcon != null) {
  1433 + Paint smoothingPaint = new Paint();
  1434 + smoothingPaint.setAntiAlias(true);
  1435 + smoothingPaint.setFilterBitmap(true);
  1436 + smoothingPaint.setDither(true);
  1437 + canvas.drawCircle(iconSize / 2, iconSize / 2, iconSize / 2.3f, smoothingPaint);
  1438 + smoothingPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
  1439 + Bitmap scaledBitmap = Bitmap.createScaledBitmap(notification.notification.largeIcon, iconSize, iconSize, true);
  1440 + canvas.drawBitmap(scaledBitmap, null, new Rect(0, 0,
  1441 + iconSize, iconSize), smoothingPaint);
  1442 + } else {
  1443 + try {
  1444 + Drawable icon = StatusBarIconView.getIcon(mContext,
  1445 + new StatusBarIcon(notification.pkg, notification.user, notification.notification.icon,
  1446 + notification.notification.iconLevel, 0, notification.notification.tickerText));
  1447 + if (icon == null) icon = mContext.getPackageManager().getApplicationIcon(notification.pkg);
  1448 + int margin = (iconSize - smallIconSize) / 2;
  1449 + icon.setBounds(margin, margin, iconSize - margin, iconSize - margin);
  1450 + icon.draw(canvas);
  1451 + } catch (Exception e) {
  1452 + // NameNotFoundException
  1453 + }
  1454 + }
  1455 + return roundIcon;
  1456 + }
  1457 +
1343 1458 protected StatusBarIconView addNotificationViews(IBinder key,
1344 1459 StatusBarNotification notification) {
1345 1460 if (DEBUG) {
@@ -1361,8 +1476,19 @@ protected StatusBarIconView addNotificationViews(IBinder key,
1361 1476 handleNotificationError(key, notification, "Couldn't create icon: " + ic);
1362 1477 return null;
1363 1478 }
  1479 +
  1480 + NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView,
  1481 + createRoundIcon(notification));
  1482 + entry.hide = entry.notification.pkg.equals("com.paranoid.halo");
  1483 +
  1484 + final PendingIntent contentIntent = notification.notification.contentIntent;
  1485 + if (contentIntent != null) {
  1486 + entry.floatingIntent = makeClicker(contentIntent,
  1487 + notification.pkg, notification.tag, notification.id);
  1488 + entry.floatingIntent.makeFloating(true);
  1489 + }
  1490 +
1364 1491 // Construct the expanded view.
1365   - NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
1366 1492 if (!inflateViews(entry, mPile)) {
1367 1493 handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
1368 1494 + notification);
@@ -1392,6 +1518,7 @@ protected boolean expandView(NotificationData.Entry entry, boolean expand) {
1392 1518 lp.height = rowHeight;
1393 1519 }
1394 1520 entry.row.setLayoutParams(lp);
  1521 + if (entry.hide) entry.row.setVisibility(View.GONE);
1395 1522 return expand;
1396 1523 }
1397 1524
@@ -1480,10 +1607,10 @@ public void updateNotification(IBinder key, StatusBarNotification notification)
1480 1607 boolean orderUnchanged = notification.notification.when==oldNotification.notification.when
1481 1608 && notification.score == oldNotification.score;
1482 1609 // score now encompasses/supersedes isOngoing()
1483   -
1484   - boolean updateTicker = notification.notification.tickerText != null
  1610 +
  1611 + boolean updateTicker = (notification.notification.tickerText != null
1485 1612 && !TextUtils.equals(notification.notification.tickerText,
1486   - oldEntry.notification.notification.tickerText);
  1613 + oldEntry.notification.notification.tickerText)) || mHaloActive;
1487 1614 boolean isTopAnyway = isTopNotification(rowParent, oldEntry);
1488 1615 if (contentsUnchanged && bigContentsUnchanged && (orderUnchanged || isTopAnyway)) {
1489 1616 if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
@@ -1494,15 +1621,22 @@ public void updateNotification(IBinder key, StatusBarNotification notification)
1494 1621 if (bigContentView != null && oldEntry.getLargeView() != null) {
1495 1622 bigContentView.reapply(mContext, oldEntry.getLargeView(), mOnClickHandler);
1496 1623 }
1497   - // update the contentIntent
  1624 + // update contentIntent and floatingIntent
1498 1625 final PendingIntent contentIntent = notification.notification.contentIntent;
1499 1626 if (contentIntent != null) {
1500 1627 final View.OnClickListener listener = makeClicker(contentIntent,
1501 1628 notification.pkg, notification.tag, notification.id);
1502 1629 oldEntry.content.setOnClickListener(listener);
  1630 + oldEntry.floatingIntent = makeClicker(contentIntent,
  1631 + notification.pkg, notification.tag, notification.id);
  1632 + oldEntry.floatingIntent.makeFloating(true);
1503 1633 } else {
1504 1634 oldEntry.content.setOnClickListener(null);
  1635 + oldEntry.floatingIntent = null;
1505 1636 }
  1637 + // Update the roundIcon
  1638 + oldEntry.roundIcon = createRoundIcon(notification);
  1639 +
1506 1640 // Update the icon.
1507 1641 final StatusBarIcon ic = new StatusBarIcon(notification.pkg,
1508 1642 notification.user,
17 packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -17,10 +17,12 @@
17 17 package com.android.systemui.statusbar;
18 18
19 19 import android.app.Notification;
  20 +import android.graphics.Bitmap;
20 21 import android.os.IBinder;
21 22 import android.view.View;
22 23 import android.widget.ImageView;
23 24
  25 +import com.android.systemui.statusbar.BaseStatusBar.NotificationClicker;
24 26 import com.android.internal.statusbar.StatusBarNotification;
25 27 import com.android.systemui.R;
26 28
@@ -39,13 +41,22 @@
39 41 public View content; // takes the click events and sends the PendingIntent
40 42 public View expanded; // the inflated RemoteViews
41 43 public ImageView largeIcon;
  44 + protected boolean hide = false;
  45 + protected Bitmap roundIcon;
42 46 protected View expandedLarge;
  47 + protected NotificationClicker floatingIntent;
43 48 public Entry() {}
44 49 public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
45 50 this.key = key;
46 51 this.notification = n;
47 52 this.icon = ic;
48 53 }
  54 + public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic, Bitmap ri) {
  55 + this.key = key;
  56 + this.notification = n;
  57 + this.icon = ic;
  58 + this.roundIcon = ri;
  59 + }
49 60 public void setLargeView(View expandedLarge) {
50 61 this.expandedLarge = expandedLarge;
51 62 writeBooleanTag(row, R.id.expandable_tag, expandedLarge != null);
@@ -53,6 +64,12 @@ public void setLargeView(View expandedLarge) {
53 64 public View getLargeView() {
54 65 return expandedLarge;
55 66 }
  67 + public NotificationClicker getFloatingIntent() {
  68 + return floatingIntent;
  69 + }
  70 + public Bitmap getRoundIcon() {
  71 + return roundIcon;
  72 + }
56 73 /**
57 74 * Return whether the entry can be expanded.
58 75 */
90 packages/SystemUI/src/com/android/systemui/statusbar/halo/CustomObjectAnimator.java
<