summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/BackupRestoreConfirmation/AndroidManifest.xml29
-rw-r--r--packages/DocumentsUI/AndroidManifest.xml2
-rw-r--r--packages/DocumentsUI/res/values-sw720dp/styles.xml4
-rw-r--r--packages/DocumentsUI/res/values/styles.xml4
-rw-r--r--packages/Keyguard/res/values/styles.xml2
-rw-r--r--packages/Keyguard/test/AndroidManifest.xml2
-rw-r--r--packages/PrintSpooler/res/layout/select_printer_activity.xml2
-rw-r--r--packages/PrintSpooler/res/values/themes.xml6
-rw-r--r--packages/Shell/AndroidManifest.xml20
-rw-r--r--packages/SystemUI/AndroidManifest.xml30
-rw-r--r--packages/SystemUI/res/layout/recents_task_view.xml18
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml25
-rw-r--r--packages/SystemUI/res/values/dimens.xml7
-rw-r--r--packages/SystemUI/res/values/styles.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Constants.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java367
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java186
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/Task.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java153
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java424
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java289
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ScrollAdapter.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java9
-rw-r--r--packages/VpnDialogs/AndroidManifest.xml22
-rw-r--r--packages/WallpaperCropper/AndroidManifest.xml18
-rw-r--r--packages/WallpaperCropper/res/layout/wallpaper_cropper.xml2
-rw-r--r--packages/WallpaperCropper/res/values/styles.xml4
37 files changed, 1077 insertions, 859 deletions
diff --git a/packages/BackupRestoreConfirmation/AndroidManifest.xml b/packages/BackupRestoreConfirmation/AndroidManifest.xml
index 4fb26ae..8141fa7 100644
--- a/packages/BackupRestoreConfirmation/AndroidManifest.xml
+++ b/packages/BackupRestoreConfirmation/AndroidManifest.xml
@@ -1,20 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
-->
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.backupconfirm" >
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 179bcd1..6b77a7c 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -42,7 +42,7 @@
<activity
android:name=".SettingsActivity"
android:label="@string/menu_settings"
- android:theme="@android:style/Theme.Holo.Light.DialogWhenLarge"
+ android:theme="@android:style/Theme.DeviceDefault.Light.DialogWhenLarge"
android:exported="false" />
<provider
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
index 19d2ebe..8d31444 100644
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/styles.xml
@@ -15,11 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="Theme" parent="@android:style/Theme.Holo.Light">
+ <style name="Theme" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionOverflowButtonStyle">@style/DarkerOverflow</item>
<item name="android:windowBackground">@*android:drawable/dialog_full_holo_light</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
- <item name="android:windowAnimationStyle">@*android:style/Animation.Holo.Dialog</item>
+ <item name="android:windowAnimationStyle">@*android:style/Animation.DeviceDefault.Dialog</item>
</style>
</resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 0c8f712..a416eb4 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -29,11 +29,11 @@
<!-- Normally just a redirection, but this is used to make ourselves a
dialog on large tablets -->
- <style name="Theme" parent="@android:style/Theme.Holo.Light">
+ <style name="Theme" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionOverflowButtonStyle">@style/DarkerOverflow</item>
</style>
- <style name="DarkerOverflow" parent="@android:style/Widget.Holo.Light.ActionButton.Overflow">
+ <style name="DarkerOverflow" parent="@android:style/Widget.DeviceDefault.Light.ActionButton.Overflow">
<item name="android:src">@drawable/ic_menu_overflow</item>
</style>
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index d4f98af..80fcf75 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -68,7 +68,7 @@
<item name="android:textSize">@dimen/widget_big_font_size</item>
</style>
- <style name="Widget.TransportControl.SeekBar" parent="@android:style/Widget.Holo.SeekBar">
+ <style name="Widget.TransportControl.SeekBar" parent="@android:style/Widget.DeviceDefault.Light.SeekBar">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@drawable/scrubber_progress_horizontal_holo_light</item>
<item name="android:indeterminateDrawable">@drawable/scrubber_progress_horizontal_holo_light</item>
diff --git a/packages/Keyguard/test/AndroidManifest.xml b/packages/Keyguard/test/AndroidManifest.xml
index b801e4b..1638127 100644
--- a/packages/Keyguard/test/AndroidManifest.xml
+++ b/packages/Keyguard/test/AndroidManifest.xml
@@ -23,7 +23,7 @@
<application android:label="@string/app_name" android:icon="@drawable/app_icon">
<activity android:name=".KeyguardTestActivity"
android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo">
+ android:theme="@android:style/Theme.DeviceDefault.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/packages/PrintSpooler/res/layout/select_printer_activity.xml b/packages/PrintSpooler/res/layout/select_printer_activity.xml
index 6fc77df..4488b6a 100644
--- a/packages/PrintSpooler/res/layout/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/layout/select_printer_activity.xml
@@ -61,7 +61,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
- style="@android:style/Widget.Holo.ProgressBar.Horizontal">
+ style="@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal">
</ProgressBar>
</LinearLayout>
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index 86f4a37..94ab895 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -16,7 +16,7 @@
<resources>
- <style name="PrintJobConfigActivityTheme" parent="@android:style/Theme.Holo.Light.NoActionBar">
+ <style name="PrintJobConfigActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowSoftInputMode">stateAlwaysHidden|adjustResize</item>
<item name="android:windowIsTranslucent">true</item>
@@ -25,11 +25,11 @@
<item name="android:windowIsFloating">true</item>
</style>
- <style name="SelectPrinterActivityTheme" parent="@android:style/Theme.Holo.Light">
+ <style name="SelectPrinterActivityTheme" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionBarStyle">@style/SelectPrinterActivityActionBarStyle</item>
</style>
- <style name="SelectPrinterActivityActionBarStyle" parent="@android:style/Widget.Holo.ActionBar">
+ <style name="SelectPrinterActivityActionBarStyle" parent="@android:style/Widget.DeviceDefault.Light.ActionBar">
<item name="android:displayOptions">showTitle</item>
</style>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 29e8d1d..19286c8 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -1,3 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.shell"
coreApp="true"
@@ -83,7 +101,7 @@
<activity
android:name=".BugreportWarningActivity"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:exported="false" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b09cc1d..3424eed 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1,3 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.systemui"
@@ -157,7 +175,7 @@
<activity android:name=".usb.UsbConfirmActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -166,7 +184,7 @@
<activity android:name=".usb.UsbPermissionActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -175,7 +193,7 @@
<activity android:name=".usb.UsbResolverActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -184,7 +202,7 @@
<activity android:name=".usb.UsbAccessoryUriActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -192,7 +210,7 @@
<!-- started from UsbDebuggingManager -->
<activity android:name=".usb.UsbDebuggingActivity"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -202,7 +220,7 @@
android:name=".net.NetworkOverLimitActivity"
android:exported="true"
android:permission="android.permission.MANAGE_NETWORK_POLICY"
- android:theme="@android:style/Theme.Holo.Panel"
+ android:theme="@android:style/Theme.DeviceDefault.Light.Panel"
android:finishOnCloseSystemDialogs="true"
android:launchMode="singleTop"
android:taskAffinity="com.android.systemui.net"
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f5ce222..96da21f 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -28,21 +28,29 @@
android:layout_gravity="top|center_horizontal"
android:background="#e6444444">
<ImageView
- android:id="@+id/activity_icon"
- android:layout_width="@dimen/recents_task_view_icon_size"
- android:layout_height="@dimen/recents_task_view_icon_size"
- android:layout_gravity="top|left"
+ android:id="@+id/application_icon"
+ android:layout_width="@dimen/recents_task_view_application_icon_size"
+ android:layout_height="@dimen/recents_task_view_application_icon_size"
+ android:layout_gravity="center_vertical|left"
android:padding="8dp" />
<TextView
android:id="@+id/activity_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|left"
- android:layout_marginLeft="@dimen/recents_task_view_icon_size"
+ android:layout_marginLeft="@dimen/recents_task_view_application_icon_size"
+ android:layout_marginRight="@dimen/recents_task_view_activity_icon_size"
android:textSize="24sp"
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
android:fontFamily="sans-serif-thin" />
+ <ImageView
+ android:id="@+id/activity_icon"
+ android:layout_width="@dimen/recents_task_view_activity_icon_size"
+ android:layout_height="@dimen/recents_task_view_activity_icon_size"
+ android:layout_gravity="center_vertical|right"
+ android:padding="12dp"
+ android:visibility="invisible" />
</com.android.systemui.recents.views.TaskBarView>
</com.android.systemui.recents.views.TaskView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1da66bb..a7ec064 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -24,19 +24,10 @@
android:id="@+id/notification_panel"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:background="@drawable/notification_panel_bg"
android:paddingTop="@dimen/notification_panel_padding_top"
android:layout_marginStart="@dimen/notification_panel_margin_left"
>
- <View
- android:id="@+id/handle"
- android:layout_width="match_parent"
- android:layout_height="@dimen/close_handle_height"
- android:background="@drawable/status_bar_close"
- android:visibility="invisible"
- />
-
<include
layout="@layout/carrier_label"
android:layout_height="@dimen/carrier_label_height"
@@ -69,6 +60,7 @@
/>
<FrameLayout
+ android:id="@+id/notification_container_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
@@ -77,21 +69,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
-
- <ScrollView
- android:id="@+id/scroll"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:fadingEdge="none"
- android:overScrollMode="ifContentScrolls"
- >
- <com.android.systemui.statusbar.policy.NotificationRowLayout
- android:id="@+id/latestItems"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- systemui:rowHeight="@dimen/notification_row_min_height"
- />
- </ScrollView>
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 38e1083..1c6d5ad 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -230,8 +230,11 @@
<!-- Default distance from each snap target that GlowPadView considers a "hit" -->
<dimen name="glowpadview_inner_radius">15dip</dimen>
- <!-- The size of the icon in the recents task view. -->
- <dimen name="recents_task_view_icon_size">60dp</dimen>
+ <!-- The size of the application icon in the recents task view. -->
+ <dimen name="recents_task_view_application_icon_size">60dp</dimen>
+
+ <!-- The size of the activity icon in the recents task view. -->
+ <dimen name="recents_task_view_activity_icon_size">60dp</dimen>
<!-- Space below the notification stack -->
<dimen name="notification_stack_margin_bottom">0dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 14af020..76cadd7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,12 +16,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="RecentsStyle" parent="@android:style/Theme.Holo.Wallpaper.NoTitleBar">
+ <style name="RecentsStyle" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
<item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
</style>
<!-- Alternate Recents theme -->
- <style name="RecentsTheme" parent="@android:style/Theme.Holo.Wallpaper.NoTitleBar">
+ <style name="RecentsTheme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 90b0c49..1832d37 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -34,6 +34,8 @@ import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import com.android.systemui.statusbar.policy.ScrollAdapter;
+
public class ExpandHelper implements Gefingerpoken, OnClickListener {
public interface Callback {
View getChildAtRawPosition(float x, float y);
@@ -609,19 +611,5 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
}
mVibrator.vibrate(duration, AudioManager.STREAM_SYSTEM);
}
-
- public interface ScrollAdapter {
-
- /**
- * @return Whether the view returned by {@link #getHostView()} is scrolled to the top
- * and can therefore be expanded by a single finger drag
- */
- public boolean isScrolledToTop();
-
- /**
- * @return The view in which the scrolling is performed
- */
- public View getHostView();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 227e19d..8543b97 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -23,35 +23,26 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
-import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
-import com.android.systemui.SystemUI;
import java.util.List;
@@ -113,6 +104,7 @@ public class AlternateRecentsComponent {
final static String sRecentsService = "com.android.systemui.recents.RecentsService";
Context mContext;
+ SystemServicesProxy mSystemServicesProxy;
// Recents service binding
Messenger mService = null;
@@ -127,6 +119,7 @@ public class AlternateRecentsComponent {
public AlternateRecentsComponent(Context context) {
mContext = context;
+ mSystemServicesProxy = new SystemServicesProxy(context);
mMessenger = new Messenger(new RecentsMessageHandler());
}
@@ -219,17 +212,16 @@ public class AlternateRecentsComponent {
/** Loads the first task thumbnail */
Bitmap loadFirstTaskThumbnail() {
- ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1,
- ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES,
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
UserHandle.CURRENT.getIdentifier());
for (ActivityManager.RecentTaskInfo t : tasks) {
// Skip tasks in the home stack
- if (am.isInHomeStack(t.persistentId)) {
+ if (ssp.isInHomeStack(t.persistentId)) {
return null;
}
- Bitmap thumbnail = am.getTaskTopThumbnail(t.persistentId);
+ Bitmap thumbnail = ssp.getTaskThumbnail(t.persistentId);
return thumbnail;
}
return null;
@@ -237,13 +229,12 @@ public class AlternateRecentsComponent {
/** Returns whether there is a first task */
boolean hasFirstTask() {
- ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1,
- ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES,
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
UserHandle.CURRENT.getIdentifier());
for (ActivityManager.RecentTaskInfo t : tasks) {
// Skip tasks in the home stack
- if (am.isInHomeStack(t.persistentId)) {
+ if (ssp.isInHomeStack(t.persistentId)) {
continue;
}
@@ -294,8 +285,8 @@ public class AlternateRecentsComponent {
// If Recents is the front most activity, then we should just communicate with it directly
// to launch the first task or dismiss itself
- ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 2b08141..8c5c8fa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -31,6 +31,12 @@ public class Constants {
public static final boolean EnableToggleNewRecentsActivity = false;
// This disables the bitmap and icon caches to
public static final boolean DisableBackgroundCache = false;
+ // For debugging, this enables us to create mock recents tasks
+ public static final boolean EnableSystemServicesProxy = false;
+ // For debugging, this defines the number of mock recents packages to create
+ public static final int SystemServicesProxyMockPackageCount = 12;
+ // For debugging, this defines the number of mock recents tasks to create
+ public static final int SystemServicesProxyMockTaskCount = 75;
// Timing certain paths
public static final String TimeRecentsStartupKey = "startup";
@@ -73,8 +79,6 @@ public class Constants {
public static class RecentsTaskLoader {
// XXX: This should be calculated on the first load
public static final int PreloadFirstTasksCount = 5;
- // For debugging, this allows us to multiply the number of cards for each task
- public static final int TaskEntryMultiplier = 1;
}
public static class TaskStackView {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 928c732..e193a95 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -20,7 +20,6 @@ import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -109,18 +108,20 @@ class TaskResourceLoader implements Runnable {
Handler mLoadThreadHandler;
Handler mMainThreadHandler;
+ SystemServicesProxy mSystemServicesProxy;
TaskResourceLoadQueue mLoadQueue;
- DrawableLruCache mIconCache;
+ DrawableLruCache mApplicationIconCache;
BitmapLruCache mThumbnailCache;
boolean mCancelled;
boolean mWaitingOnLoadQueue;
/** Constructor, creates a new loading thread that loads task resources in the background */
- public TaskResourceLoader(TaskResourceLoadQueue loadQueue, DrawableLruCache iconCache,
+ public TaskResourceLoader(TaskResourceLoadQueue loadQueue,
+ DrawableLruCache applicationIconCache,
BitmapLruCache thumbnailCache) {
mLoadQueue = loadQueue;
- mIconCache = iconCache;
+ mApplicationIconCache = applicationIconCache;
mThumbnailCache = thumbnailCache;
mMainThreadHandler = new Handler();
mLoadThread = new HandlerThread("Recents-TaskResourceLoader");
@@ -135,6 +136,7 @@ class TaskResourceLoader implements Runnable {
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|start]");
mContext = context;
mCancelled = false;
+ mSystemServicesProxy = new SystemServicesProxy(context);
// Notify the load thread to start loading
synchronized(mLoadThread) {
mLoadThread.notifyAll();
@@ -146,6 +148,7 @@ class TaskResourceLoader implements Runnable {
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]");
// Mark as cancelled for the thread to pick up
mCancelled = true;
+ mSystemServicesProxy = null;
// If we are waiting for the load queue for more tasks, then we can just reset the
// Context now, since nothing is using it
if (mWaitingOnLoadQueue) {
@@ -175,66 +178,60 @@ class TaskResourceLoader implements Runnable {
}
}
} else {
+ SystemServicesProxy ssp = mSystemServicesProxy;
+
// Load the next item from the queue
Pair<Task, Boolean> nextTaskData = mLoadQueue.nextTask();
final Task t = nextTaskData.first;
final boolean forceLoadTask = nextTaskData.second;
if (t != null) {
- try {
- Drawable loadIcon = mIconCache.get(t.key);
- Bitmap loadThumbnail = mThumbnailCache.get(t.key);
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [TaskResourceLoader|load]",
- t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
- " forceLoad: " + forceLoadTask);
- // Load the icon
- if (loadIcon == null || forceLoadTask) {
- PackageManager pm = mContext.getPackageManager();
- ActivityInfo info = pm.getActivityInfo(t.key.baseIntent.getComponent(),
- PackageManager.GET_META_DATA);
- Drawable icon = info.loadIcon(pm);
- if (!mCancelled) {
- if (icon != null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [TaskResourceLoader|loadIcon]",
- icon);
- loadIcon = icon;
- mIconCache.put(t.key, icon);
- }
- }
- }
- // Load the thumbnail
- if (loadThumbnail == null || forceLoadTask) {
- ActivityManager am = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
- Bitmap thumbnail = am.getTaskTopThumbnail(t.key.id);
- if (!mCancelled) {
- if (thumbnail != null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [TaskResourceLoader|loadThumbnail]",
- thumbnail);
- loadThumbnail = thumbnail;
- mThumbnailCache.put(t.key, thumbnail);
- } else {
- Console.logError(mContext,
- "Failed to load task top thumbnail for: " +
- t.key.baseIntent.getComponent().getPackageName());
- }
+ Drawable loadIcon = mApplicationIconCache.get(t.key);
+ Bitmap loadThumbnail = mThumbnailCache.get(t.key);
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [TaskResourceLoader|load]",
+ t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
+ " forceLoad: " + forceLoadTask);
+ // Load the application icon
+ if (loadIcon == null || forceLoadTask) {
+ ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent());
+ Drawable icon = ssp.getActivityIcon(info);
+ if (!mCancelled) {
+ if (icon != null) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [TaskResourceLoader|loadIcon]",
+ icon);
+ loadIcon = icon;
+ mApplicationIconCache.put(t.key, icon);
}
}
+ }
+ // Load the thumbnail
+ if (loadThumbnail == null || forceLoadTask) {
+ Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id);
if (!mCancelled) {
- // Notify that the task data has changed
- final Drawable newIcon = loadIcon;
- final Bitmap newThumbnail = loadThumbnail;
- mMainThreadHandler.post(new Runnable() {
- @Override
- public void run() {
- t.notifyTaskDataLoaded(newThumbnail, newIcon, forceLoadTask);
- }
- });
+ if (thumbnail != null) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [TaskResourceLoader|loadThumbnail]",
+ thumbnail);
+ loadThumbnail = thumbnail;
+ mThumbnailCache.put(t.key, thumbnail);
+ } else {
+ Console.logError(mContext,
+ "Failed to load task top thumbnail for: " +
+ t.key.baseIntent.getComponent().getPackageName());
+ }
}
- } catch (PackageManager.NameNotFoundException ne) {
- ne.printStackTrace();
+ }
+ if (!mCancelled) {
+ // Notify that the task data has changed
+ final Drawable newIcon = loadIcon;
+ final Bitmap newThumbnail = loadThumbnail;
+ mMainThreadHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ t.notifyTaskDataLoaded(newThumbnail, newIcon, forceLoadTask);
+ }
+ });
}
}
@@ -296,7 +293,8 @@ class BitmapLruCache extends LruCache<Task.TaskKey, Bitmap> {
public class RecentsTaskLoader {
static RecentsTaskLoader sInstance;
- DrawableLruCache mIconCache;
+ SystemServicesProxy mSystemServicesProxy;
+ DrawableLruCache mApplicationIconCache;
BitmapLruCache mThumbnailCache;
TaskResourceLoadQueue mLoadQueue;
TaskResourceLoader mLoader;
@@ -304,7 +302,7 @@ public class RecentsTaskLoader {
int mMaxThumbnailCacheSize;
int mMaxIconCacheSize;
- BitmapDrawable mDefaultIcon;
+ BitmapDrawable mDefaultApplicationIcon;
Bitmap mDefaultThumbnail;
/** Private Constructor */
@@ -324,11 +322,12 @@ public class RecentsTaskLoader {
"[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
" iconCache: " + iconCacheSize);
- // Initialize the cache and loaders
+ // Initialize the proxy, cache and loaders
+ mSystemServicesProxy = new SystemServicesProxy(context);
mLoadQueue = new TaskResourceLoadQueue();
- mIconCache = new DrawableLruCache(iconCacheSize);
+ mApplicationIconCache = new DrawableLruCache(iconCacheSize);
mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
- mLoader = new TaskResourceLoader(mLoadQueue, mIconCache, mThumbnailCache);
+ mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache);
// Create the default assets
Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
@@ -339,10 +338,10 @@ public class RecentsTaskLoader {
c.setBitmap(mDefaultThumbnail);
c.drawColor(0x00000000);
c.setBitmap(null);
- mDefaultIcon = new BitmapDrawable(context.getResources(), icon);
+ mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
Console.log(Constants.DebugFlags.App.TaskDataLoader,
"[RecentsTaskLoader|defaultBitmaps]",
- "icon: " + mDefaultIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
+ "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
}
/** Initializes the recents task loader */
@@ -358,6 +357,11 @@ public class RecentsTaskLoader {
return sInstance;
}
+ /** Returns the system services proxy */
+ public SystemServicesProxy getSystemServicesProxy() {
+ return mSystemServicesProxy;
+ }
+
/** Reload the set of recent tasks */
SpaceNode reload(Context context, int preloadCount) {
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
@@ -367,141 +371,118 @@ public class RecentsTaskLoader {
SpaceNode root = new SpaceNode(context);
root.setStack(stack);
- try {
- long t1 = System.currentTimeMillis();
-
- PackageManager pm = context.getPackageManager();
- ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ long t1 = System.currentTimeMillis();
- // Get the recent tasks
- List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(25,
- ActivityManager.RECENT_IGNORE_UNAVAILABLE |
- ActivityManager.RECENT_INCLUDE_PROFILES, UserHandle.CURRENT.getIdentifier());
- Collections.reverse(tasks);
- Console.log(Constants.DebugFlags.App.TimeSystemCalls,
- "[RecentsTaskLoader|getRecentTasks]",
- "" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- "[RecentsTaskLoader|tasks]", "" + tasks.size());
+ // Get the recent tasks
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RecentTaskInfo> tasks =
+ ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
+ Collections.reverse(tasks);
+ Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+ "[RecentsTaskLoader|getRecentTasks]",
+ "" + (System.currentTimeMillis() - t1) + "ms");
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ "[RecentsTaskLoader|tasks]", "" + tasks.size());
- // Remove home/recents tasks
- Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
- while (iter.hasNext()) {
- ActivityManager.RecentTaskInfo t = iter.next();
+ // Remove home/recents tasks
+ Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
+ while (iter.hasNext()) {
+ ActivityManager.RecentTaskInfo t = iter.next();
- // Skip tasks in the home stack
- if (am.isInHomeStack(t.persistentId)) {
- iter.remove();
- continue;
- }
- // Skip tasks from this Recents package
- if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) {
- iter.remove();
- continue;
- }
+ // Skip tasks in the home stack
+ if (ssp.isInHomeStack(t.persistentId)) {
+ iter.remove();
+ continue;
}
+ // Skip tasks from this Recents package
+ if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) {
+ iter.remove();
+ continue;
+ }
+ }
- // Add each task to the task stack
- t1 = System.currentTimeMillis();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- ActivityManager.RecentTaskInfo t = tasks.get(i);
- ActivityInfo info = pm.getActivityInfo(t.baseIntent.getComponent(),
- PackageManager.GET_META_DATA);
- String title = info.loadLabel(pm).toString();
- boolean isForemostTask = (i == (taskCount - 1));
-
- // Preload the specified number of apps
- if (i >= (taskCount - preloadCount)) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- "[RecentsTaskLoader|preloadTask]",
- "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
-
- String label = (t.activityLabel == null ? title : t.activityLabel.toString());
- BitmapDrawable bd = null;
- if (t.activityIcon != null) {
- bd = new BitmapDrawable(res, t.activityIcon);
+ // Add each task to the task stack
+ t1 = System.currentTimeMillis();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ ActivityManager.RecentTaskInfo t = tasks.get(i);
+ ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent());
+ String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
+ t.activityLabel.toString());
+ Bitmap activityIcon = t.activityIcon;
+ boolean isForemostTask = (i == (taskCount - 1));
+
+ // Create a new task
+ Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, activityLabel,
+ activityIcon);
+
+ // Preload the specified number of apps
+ if (i >= (taskCount - preloadCount)) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ "[RecentsTaskLoader|preloadTask]",
+ "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
+
+ // Load the icon (if possible and not the foremost task, from the cache)
+ if (!isForemostTask) {
+ task.applicationIcon = mApplicationIconCache.get(task.key);
+ if (task.applicationIcon != null) {
+ // Even though we get things from the cache, we should update them
+ // if they've changed in the bg
+ tasksToForceLoad.add(task);
}
- Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, label, bd);
-
- // Load the icon (if possible and not the foremost task, from the cache)
- if (task.icon != null) {
- mIconCache.put(task.key, task.icon);
+ }
+ if (task.applicationIcon == null) {
+ task.applicationIcon = ssp.getActivityIcon(info);
+ if (task.applicationIcon != null) {
+ mApplicationIconCache.put(task.key, task.applicationIcon);
} else {
- if (!isForemostTask) {
- task.icon = mIconCache.get(task.key);
- if (task.icon != null) {
- // Even though we get things from the cache, we should update them
- // if they've changed in the bg
- tasksToForceLoad.add(task);
- }
- }
- if (task.icon == null) {
- task.icon = info.loadIcon(pm);
- if (task.icon != null) {
- mIconCache.put(task.key, task.icon);
- } else {
- task.icon = mDefaultIcon;
- }
- }
- }
-
- // Load the thumbnail (if possible and not the foremost task, from the cache)
- if (!isForemostTask) {
- task.thumbnail = mThumbnailCache.get(task.key);
- if (task.thumbnail != null) {
- // Even though we get things from the cache, we should update them if
- // they've changed in the bg
- tasksToForceLoad.add(task);
- }
- }
- if (task.thumbnail == null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- "[RecentsTaskLoader|loadingTaskThumbnail]");
- task.thumbnail = am.getTaskTopThumbnail(t.id);
- if (task.thumbnail != null) {
- mThumbnailCache.put(task.key, task.thumbnail);
- } else {
- task.thumbnail = mDefaultThumbnail;
- }
+ task.applicationIcon = mDefaultApplicationIcon;
}
+ }
- // Create as many tasks a we want to multiply by
- for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
- stack.addTask(task);
+ // Load the thumbnail (if possible and not the foremost task, from the cache)
+ if (!isForemostTask) {
+ task.thumbnail = mThumbnailCache.get(task.key);
+ if (task.thumbnail != null) {
+ // Even though we get things from the cache, we should update them if
+ // they've changed in the bg
+ tasksToForceLoad.add(task);
}
- } else {
- // Create as many tasks a we want to multiply by
- for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
- stack.addTask(new Task(t.persistentId, (t.id > -1), t.baseIntent, title,
- null, null));
+ }
+ if (task.thumbnail == null) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ "[RecentsTaskLoader|loadingTaskThumbnail]");
+ task.thumbnail = ssp.getTaskThumbnail(task.key.id);
+ if (task.thumbnail != null) {
+ mThumbnailCache.put(task.key, task.thumbnail);
+ } else {
+ task.thumbnail = mDefaultThumbnail;
}
}
}
- Console.log(Constants.DebugFlags.App.TimeSystemCalls,
- "[RecentsTaskLoader|getAllTaskTopThumbnail]",
- "" + (System.currentTimeMillis() - t1) + "ms");
-
- /*
- // Get all the stacks
- t1 = System.currentTimeMillis();
- List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
- Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
- for (ActivityManager.StackInfo s : stackInfos) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
- if (stacks.containsKey(s.stackId)) {
- stacks.get(s.stackId).setRect(s.bounds);
- }
+
+ // Add the task to the stack
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
+ stack.addTask(task);
+ }
+ Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+ "[RecentsTaskLoader|getAllTaskTopThumbnail]",
+ "" + (System.currentTimeMillis() - t1) + "ms");
+
+ /*
+ // Get all the stacks
+ t1 = System.currentTimeMillis();
+ List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
+ Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
+ Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
+ for (ActivityManager.StackInfo s : stackInfos) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
+ if (stacks.containsKey(s.stackId)) {
+ stacks.get(s.stackId).setRect(s.bounds);
}
- */
- } catch (Exception e) {
- e.printStackTrace();
}
+ */
// Start the task loader
mLoader.start(context);
@@ -516,16 +497,16 @@ public class RecentsTaskLoader {
/** Acquires the task resource data from the pool. */
public void loadTaskData(Task t) {
- Drawable icon = mIconCache.get(t.key);
+ Drawable applicationIcon = mApplicationIconCache.get(t.key);
Bitmap thumbnail = mThumbnailCache.get(t.key);
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
- t + " icon: " + icon + " thumbnail: " + thumbnail +
+ t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
" thumbnailCacheSize: " + mThumbnailCache.size());
boolean requiresLoad = false;
- if (icon == null) {
- icon = mDefaultIcon;
+ if (applicationIcon == null) {
+ applicationIcon = mDefaultApplicationIcon;
requiresLoad = true;
}
if (thumbnail == null) {
@@ -535,7 +516,7 @@ public class RecentsTaskLoader {
if (requiresLoad) {
mLoadQueue.addTask(t, false);
}
- t.notifyTaskDataLoaded(thumbnail, icon, false);
+ t.notifyTaskDataLoaded(thumbnail, applicationIcon, false);
}
/** Releases the task resource data back into the pool. */
@@ -545,7 +526,7 @@ public class RecentsTaskLoader {
" thumbnailCacheSize: " + mThumbnailCache.size());
mLoadQueue.removeTask(t);
- t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultIcon);
+ t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
}
/** Completely removes the resource data from the pool. */
@@ -555,8 +536,8 @@ public class RecentsTaskLoader {
mLoadQueue.removeTask(t);
mThumbnailCache.remove(t.key);
- mIconCache.remove(t.key);
- t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultIcon);
+ mApplicationIconCache.remove(t.key);
+ t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
}
/** Stops the task loader and clears all pending tasks */
@@ -579,19 +560,19 @@ public class RecentsTaskLoader {
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
// We are leaving recents, so trim the data a bit
mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 2);
- mIconCache.trimToSize(mMaxIconCacheSize / 2);
+ mApplicationIconCache.trimToSize(mMaxIconCacheSize / 2);
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
// We are going to be low on memory
mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 4);
- mIconCache.trimToSize(mMaxIconCacheSize / 4);
+ mApplicationIconCache.trimToSize(mMaxIconCacheSize / 4);
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
// We are low on memory, so release everything
mThumbnailCache.evictAll();
- mIconCache.evictAll();
+ mApplicationIconCache.evictAll();
break;
default:
break;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
new file mode 100644
index 0000000..f147fbc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Acts as a shim around the real system services that we need to access data from, and provides
+ * a point of injection when testing UI.
+ */
+public class SystemServicesProxy {
+ ActivityManager mAm;
+ PackageManager mPm;
+ String mPackage;
+
+ Bitmap mDummyIcon;
+
+ /** Private constructor */
+ public SystemServicesProxy(Context context) {
+ mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mPm = context.getPackageManager();
+ mPackage = context.getPackageName();
+
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ // Create a dummy icon
+ mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+ Canvas c = new Canvas(mDummyIcon);
+ c.drawColor(0xFFFF0000);
+ c.setBitmap(null);
+ }
+ }
+
+ /** Returns a list of the recents tasks */
+ public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+ if (mAm == null) return null;
+
+ // If we are mocking, then create some recent tasks
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ ArrayList<ActivityManager.RecentTaskInfo> tasks =
+ new ArrayList<ActivityManager.RecentTaskInfo>();
+ int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
+ for (int i = 0; i < count; i++) {
+ // Create a dummy component name
+ int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
+ ComponentName cn = new ComponentName("com.android.test" + packageIndex,
+ "com.android.test" + i + ".Activity");
+ // Create the recent task info
+ ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
+ rti.id = rti.persistentId = i;
+ rti.baseIntent = new Intent();
+ rti.baseIntent.setComponent(cn);
+ rti.description = rti.activityLabel =
+ Long.toString(Math.abs(new Random().nextLong()), 36);
+ if (i % 2 == 0) {
+ rti.activityIcon = Bitmap.createBitmap(mDummyIcon);
+ }
+ tasks.add(rti);
+ }
+ return tasks;
+ }
+
+ return mAm.getRecentTasksForUser(numTasks,
+ ActivityManager.RECENT_IGNORE_UNAVAILABLE |
+ ActivityManager.RECENT_INCLUDE_PROFILES, userId);
+ }
+
+ /** Returns a list of the running tasks */
+ public List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
+ if (mAm == null) return null;
+ return mAm.getRunningTasks(numTasks);
+ }
+
+ /** Returns whether the specified task is in the home stack */
+ public boolean isInHomeStack(int taskId) {
+ if (mAm == null) return false;
+
+ // If we are mocking, then just return false
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ return false;
+ }
+
+ return mAm.isInHomeStack(taskId);
+ }
+
+ /** Returns the top task thumbnail for the given task id */
+ public Bitmap getTaskThumbnail(int taskId) {
+ if (mAm == null) return null;
+
+ // If we are mocking, then just return a dummy thumbnail
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(thumbnail);
+ c.drawColor(0xFF00ff00);
+ c.setBitmap(null);
+ return thumbnail;
+ }
+
+ return mAm.getTaskTopThumbnail(taskId);
+ }
+
+ /** Moves a task to the front with the specified activity options */
+ public void moveTaskToFront(int taskId, ActivityOptions opts) {
+ if (mAm == null) return;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
+
+ if (opts != null) {
+ mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME,
+ opts.toBundle());
+ } else {
+ mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME);
+ }
+ }
+
+ /** Removes the task and kills the process */
+ public void removeTask(int taskId) {
+ if (mAm == null) return;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
+
+ mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ }
+
+ /** Returns the activity info for a given component name */
+ public ActivityInfo getActivityInfo(ComponentName cn) {
+ if (mPm == null) return null;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
+
+ try {
+ return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /** Returns the activity label */
+ public String getActivityLabel(ActivityInfo info) {
+ if (mPm == null) return null;
+
+ // If we are mocking, then return a mock label
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ return "Recent Task";
+ }
+
+ return info.loadLabel(mPm).toString();
+ }
+
+ /** Returns the activity icon */
+ public Drawable getActivityIcon(ActivityInfo info) {
+ if (mPm == null) return null;
+
+ // If we are mocking, then return a mock label
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ return new ColorDrawable(0xFFff0000);
+ }
+
+ return info.loadIcon(mPm);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 677334d..ed2ab2a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -19,7 +19,6 @@ package com.android.systemui.recents.model;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import com.android.systemui.recents.Constants;
/**
@@ -61,23 +60,19 @@ public class Task {
}
public TaskKey key;
- public String title;
- public Drawable icon;
+ public Drawable applicationIcon;
+ public String activityLabel;
+ public Bitmap activityIcon;
public Bitmap thumbnail;
public boolean isActive;
TaskCallbacks mCb;
- public Task(int id, boolean isActive, Intent intent, String activityTitle, Drawable icon) {
- this(id, isActive, intent, activityTitle, icon, null);
- }
-
- public Task(int id, boolean isActive, Intent intent, String activityTitle, Drawable icon,
- Bitmap thumbnail) {
+ public Task(int id, boolean isActive, Intent intent, String activityTitle,
+ Bitmap activityIcon) {
this.key = new TaskKey(id, intent);
- this.title = activityTitle;
- this.icon = icon;
- this.thumbnail = thumbnail;
+ this.activityLabel = activityTitle;
+ this.activityIcon = activityIcon;
this.isActive = isActive;
}
@@ -87,8 +82,9 @@ public class Task {
}
/** Notifies the callback listeners that this task has been loaded */
- public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable icon, boolean reloadingTaskData) {
- this.icon = icon;
+ public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon,
+ boolean reloadingTaskData) {
+ this.applicationIcon = applicationIcon;
this.thumbnail = thumbnail;
if (mCb != null) {
mCb.onTaskDataLoaded(reloadingTaskData);
@@ -96,8 +92,8 @@ public class Task {
}
/** Notifies the callback listeners that this task has been unloaded */
- public void notifyTaskDataUnloaded(Bitmap defaultThumbnail, Drawable defaultIcon) {
- icon = defaultIcon;
+ public void notifyTaskDataUnloaded(Bitmap defaultThumbnail, Drawable defaultApplicationIcon) {
+ applicationIcon = defaultApplicationIcon;
thumbnail = defaultThumbnail;
if (mCb != null) {
mCb.onTaskDataUnloaded();
@@ -106,14 +102,7 @@ public class Task {
@Override
public boolean equals(Object o) {
- // If we have multiple task entries for the same task, then we do the simple object
- // equality check
- if (Constants.Values.RecentsTaskLoader.TaskEntryMultiplier > 1) {
- return super.equals(o);
- }
-
- // Otherwise, check that the id and intent match (the other fields can be asynchronously
- // loaded and is unsuitable to testing the identity of this Task)
+ // Check that the id matches
Task t = (Task) o;
return key.equals(t.key);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index e89bde5..cb52794 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents.views;
-import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -30,6 +29,7 @@ import android.widget.FrameLayout;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsTaskLoader;
import com.android.systemui.recents.model.SpaceNode;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
@@ -246,14 +246,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
if (task.isActive) {
// Bring an active task to the foreground
- ActivityManager am = (ActivityManager)
- stackView.getContext().getSystemService(Context.ACTIVITY_SERVICE);
- if (opts != null) {
- am.moveTaskToFront(task.key.id, ActivityManager.MOVE_TASK_WITH_HOME,
- opts.toBundle());
- } else {
- am.moveTaskToFront(task.key.id, ActivityManager.MOVE_TASK_WITH_HOME);
- }
+ RecentsTaskLoader.getInstance().getSystemServicesProxy()
+ .moveTaskToFront(task.key.id, opts);
} else {
// Launch the activity with the desired animation
Intent i = new Intent(task.key.baseIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index 235c6cc..c9a6d67 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -17,21 +17,12 @@
package com.android.systemui.recents.views;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.model.Task;
@@ -39,6 +30,7 @@ import com.android.systemui.recents.model.Task;
class TaskBarView extends FrameLayout {
Task mTask;
+ ImageView mApplicationIcon;
ImageView mActivityIcon;
TextView mActivityDescription;
@@ -61,6 +53,7 @@ class TaskBarView extends FrameLayout {
@Override
protected void onFinishInflate() {
// Initialize the icon and description views
+ mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
mActivityIcon = (ImageView) findViewById(R.id.activity_icon);
mActivityDescription = (TextView) findViewById(R.id.activity_description);
}
@@ -68,9 +61,13 @@ class TaskBarView extends FrameLayout {
/** Binds the bar view to the task */
void rebindToTask(Task t, boolean animate) {
mTask = t;
- if (t.icon != null) {
- mActivityIcon.setImageDrawable(t.icon);
- mActivityDescription.setText(t.title);
+ if (t.applicationIcon != null) {
+ mApplicationIcon.setImageDrawable(t.applicationIcon);
+ mActivityDescription.setText(t.activityLabel);
+ if (t.activityIcon != null) {
+ mActivityIcon.setImageBitmap(t.activityIcon);
+ mActivityIcon.setVisibility(View.VISIBLE);
+ }
if (animate) {
// XXX: Investigate how expensive it will be to create a second bitmap and crossfade
}
@@ -80,7 +77,9 @@ class TaskBarView extends FrameLayout {
/** Unbinds the bar view from the task */
void unbindFromTask() {
mTask = null;
- mActivityIcon.setImageDrawable(null);
+ mApplicationIcon.setImageDrawable(null);
+ mActivityIcon.setImageBitmap(null);
+ mActivityIcon.setVisibility(View.INVISIBLE);
mActivityDescription.setText("");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index aeb571d..dfd608c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -22,7 +22,6 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
-import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -40,6 +39,7 @@ import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsTaskLoader;
+import com.android.systemui.recents.SystemServicesProxy;
import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
@@ -234,7 +234,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// When we are picking up a new view from the view pool, prepare it for any
// following animation by putting it in a reasonable place
if (mStackViewsAnimationDuration > 0 && i != 0) {
- int fromIndex = (transform.t < 0) ? (i - 1) : (i + 1);
+ int fromIndex = (transform.t < 0) ? (visibleRange[0] - 1) :
+ (visibleRange[1] + 1);
tv.updateViewPropertiesToTaskTransform(null,
getStackTransform(fromIndex, stackScroll), 0);
}
@@ -1268,12 +1269,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
loader.deleteTaskData(task);
// Remove the task from activity manager
- final ActivityManager am = (ActivityManager)
- activity.getSystemService(Context.ACTIVITY_SERVICE);
- if (am != null) {
- am.removeTask(tv.getTask().key.id,
- ActivityManager.REMOVE_TASK_KILL_PROCESS);
- }
+ RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(tv.getTask().key.id);
// If there are no remaining tasks, then either unfilter the current stack, or just close
// the activity if there are no filtered stacks
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index e04a1b2..2c27d44 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -75,7 +75,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, Task.
// Bind the views
mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
- mBarView.mActivityIcon.setOnClickListener(this);
+ mBarView.mApplicationIcon.setOnClickListener(this);
if (mTaskDataLoaded) {
onTaskDataLoaded(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index d584043..c99f691 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -83,22 +83,7 @@ public class ToggleSlider extends RelativeLayout
}
public void onCheckedChanged(CompoundButton toggle, boolean checked) {
- Drawable thumb;
- Drawable slider;
- final Resources res = getContext().getResources();
- if (checked) {
- thumb = res.getDrawable(
- com.android.internal.R.drawable.scrubber_control_disabled_holo);
- slider = res.getDrawable(
- R.drawable.status_bar_settings_slider_disabled);
- } else {
- thumb = res.getDrawable(
- com.android.internal.R.drawable.scrubber_control_selector_holo);
- slider = res.getDrawable(
- com.android.internal.R.drawable.scrubber_progress_horizontal_holo_dark);
- }
- mSlider.setThumb(thumb);
- mSlider.setProgressDrawable(slider);
+ mSlider.setEnabled(checked);
if (mListener != null) {
mListener.onChanged(this, mTracking, checked, mSlider.getProgress());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index e5e287d..f349036 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -41,7 +41,6 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -78,6 +77,7 @@ import com.android.systemui.RecentsComponent;
import com.android.systemui.SearchPanelView;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
import java.util.Locale;
@@ -98,8 +98,6 @@ public abstract class BaseStatusBar extends SystemUI implements
protected static final int MSG_HIDE_HEADS_UP = 1027;
protected static final int MSG_ESCALATE_HEADS_UP = 1028;
- public static final boolean ENABLE_NOTIFICATION_STACK = SystemProperties
- .getBoolean("persist.notifications.use_stack", false);
protected static final boolean ENABLE_HEADS_UP = true;
// scores above this threshold should be displayed in heads up mode.
protected static final int INTERRUPTION_THRESHOLD = 10;
@@ -120,7 +118,7 @@ public abstract class BaseStatusBar extends SystemUI implements
// all notifications
protected NotificationData mNotificationData = new NotificationData();
- protected ViewGroup mPile;
+ protected NotificationStackScrollLayout mStackScroller;
protected NotificationData.Entry mInterruptingNotificationEntry;
protected long mInterruptingNotificationTime;
@@ -1033,7 +1031,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
// Construct the expanded view.
NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
- if (!inflateViews(entry, mPile)) {
+ if (!inflateViews(entry, mStackScroller)) {
handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+ notification);
return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 6be6d4d..2d2f2f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -17,45 +17,51 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.util.EventLog;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
public class NotificationPanelView extends PanelView {
public static final boolean DEBUG_GESTURES = true;
- Drawable mHandleBar;
- int mHandleBarHeight;
- View mHandleView;
- int mFingers;
PhoneStatusBar mStatusBar;
- boolean mOkToFlip;
+ private NotificationStackScrollLayout mNotificationStackScroller;
+ private int[] mTempLocation = new int[2];
+ private int[] mTempChildLocation = new int[2];
+ private View mNotificationParent;
+
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setStatusBar(PhoneStatusBar bar) {
+ if (mStatusBar != null) {
+ mStatusBar.setOnFlipRunnable(null);
+ }
mStatusBar = bar;
+ if (bar != null) {
+ mStatusBar.setOnFlipRunnable(new Runnable() {
+ @Override
+ public void run() {
+ requestPanelHeightUpdate();
+ }
+ });
+ }
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- Resources resources = getContext().getResources();
- mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
- mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height);
- mHandleView = findViewById(R.id.handle);
+ mNotificationStackScroller = (NotificationStackScrollLayout)
+ findViewById(R.id.notification_stack_scroller);
+ mNotificationParent = findViewById(R.id.notification_container_parent);
}
@Override
@@ -80,61 +86,86 @@ public class NotificationPanelView extends PanelView {
return super.dispatchPopulateAccessibilityEvent(event);
}
- // We draw the handle ourselves so that it's always glued to the bottom of the window.
+ /**
+ * Gets the relative position of a view on the screen in regard to this view.
+ *
+ * @param requestedView the view we want to find the relative position for
+ * @return
+ */
+ private int getRelativeTop(View requestedView) {
+ getLocationOnScreen(mTempLocation);
+ requestedView.getLocationOnScreen(mTempChildLocation);
+ return mTempChildLocation[1] - mTempLocation[1];
+ }
+
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (changed) {
- final int pl = getPaddingLeft();
- final int pr = getPaddingRight();
- mHandleBar.setBounds(pl, 0, getWidth() - pr, (int) mHandleBarHeight);
- }
+ public boolean onTouchEvent(MotionEvent event) {
+ // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
+ // implementation.
+ return super.onTouchEvent(event);
}
@Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- final int off = (int) (getHeight() - mHandleBarHeight - getPaddingBottom());
- canvas.translate(0, off);
- mHandleBar.setState(mHandleView.getDrawableState());
- mHandleBar.draw(canvas);
- canvas.translate(0, -off);
+ protected boolean isScrolledToBottom() {
+ if (!isInSettings()) {
+ return mNotificationStackScroller.isScrolledToBottom();
+ }
+ return super.isScrolledToBottom();
}
@Override
- public boolean onTouchEvent(MotionEvent event) {
- if (DEBUG_GESTURES) {
- if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
- EventLog.writeEvent(EventLogTags.SYSUI_NOTIFICATIONPANEL_TOUCH,
- event.getActionMasked(), (int) event.getX(), (int) event.getY());
- }
+ protected int getMaxPanelHeight() {
+ if (!isInSettings()) {
+ int maxPanelHeight = super.getMaxPanelHeight();
+ int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
+ return maxPanelHeight - emptyBottomMargin;
}
- if (PhoneStatusBar.SETTINGS_DRAG_SHORTCUT && mStatusBar.mHasFlipSettings) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- mOkToFlip = getExpandedHeight() == 0;
- break;
- case MotionEvent.ACTION_POINTER_DOWN:
- if (mOkToFlip) {
- float miny = event.getY(0);
- float maxy = miny;
- for (int i=1; i<event.getPointerCount(); i++) {
- final float y = event.getY(i);
- if (y < miny) miny = y;
- if (y > maxy) maxy = y;
- }
- if (maxy - miny < mHandleBarHeight) {
- if (getMeasuredHeight() < mHandleBarHeight) {
- mStatusBar.switchToSettings();
- } else {
- mStatusBar.flipToSettings();
- }
- mOkToFlip = false;
- }
- }
- break;
- }
+ return super.getMaxPanelHeight();
+ }
+
+ private boolean isInSettings() {
+ return mStatusBar != null && mStatusBar.isFlippedToSettings();
+ }
+
+ @Override
+ protected void onHeightUpdated(float expandedHeight) {
+ updateNotificationStackHeight(expandedHeight);
+ }
+
+ /**
+ * Update the height of the {@link #mNotificationStackScroller} to the new expanded height.
+ * This is much more efficient than doing it over the layout pass.
+ *
+ * @param expandedHeight the new expanded height
+ */
+ private void updateNotificationStackHeight(float expandedHeight) {
+ float childOffset = getRelativeTop(mNotificationStackScroller)
+ - mNotificationParent.getTranslationY();
+ int newStackHeight = (int) (expandedHeight - childOffset);
+ int itemHeight = mNotificationStackScroller.getItemHeight();
+ int bottomStackPeekSize = mNotificationStackScroller.getBottomStackPeekSize();
+ int minStackHeight = itemHeight + bottomStackPeekSize;
+ if (newStackHeight >= minStackHeight) {
+ mNotificationParent.setTranslationY(0);
+ mNotificationStackScroller.setCurrentStackHeight(newStackHeight);
+ } else {
+
+ // We did not reach the position yet where we actually start growing,
+ // so we translate the stack upwards.
+ int translationY = (newStackHeight - minStackHeight);
+ // A slight parallax effect is introduced in order for the stack to catch up with
+ // the top card.
+ float partiallyThere = (float) newStackHeight / minStackHeight;
+ partiallyThere = Math.max(0, partiallyThere);
+ translationY += (1 - partiallyThere) * bottomStackPeekSize;
+ mNotificationParent.setTranslationY(translationY);
+ mNotificationStackScroller.setCurrentStackHeight(
+ (int) (expandedHeight - (childOffset + translationY)));
}
- return mHandleView.dispatchTouchEvent(event);
+ }
+
+ @Override
+ protected int getDesiredMeasureHeight() {
+ return mMaxPanelHeight;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 4b2c3e1..3c8af30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -25,6 +25,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.widget.FrameLayout;
import com.android.systemui.R;
@@ -69,7 +70,7 @@ public class PanelView extends FrameLayout {
private View mHandleView;
private float mPeekHeight;
- private float mTouchOffset;
+ private float mInitialOffsetOnTouch;
private float mExpandedFraction = 0;
private float mExpandedHeight = 0;
private boolean mJustPeeked;
@@ -77,6 +78,7 @@ public class PanelView extends FrameLayout {
private boolean mRubberbanding;
private boolean mTracking;
private int mTrackingPointer;
+ private int mTouchSlop;
private TimeAnimator mTimeAnimator;
private ObjectAnimator mPeekAnimator;
@@ -198,7 +200,6 @@ public class PanelView extends FrameLayout {
}
}
- private int[] mAbsPos = new int[2];
PanelBar mBar;
private final TimeListener mAnimationCallback = new TimeListener() {
@@ -220,7 +221,7 @@ public class PanelView extends FrameLayout {
};
private float mVel, mAccel;
- private int mFullHeight = 0;
+ protected int mMaxPanelHeight = 0;
private String mViewName;
protected float mInitialTouchY;
protected float mFinalTouchY;
@@ -253,13 +254,13 @@ public class PanelView extends FrameLayout {
mTimeAnimator.start();
mRubberbanding = mRubberbandingEnabled // is it enabled at all?
- && mExpandedHeight > getFullHeight() // are we past the end?
+ && mExpandedHeight > getMaxPanelHeight() // are we past the end?
&& mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture?
if (mRubberbanding) {
mClosing = true;
} else if (mVel == 0) {
// if the panel is less than halfway open, close it
- mClosing = (mFinalTouchY / getFullHeight()) < 0.5f;
+ mClosing = (mFinalTouchY / getMaxPanelHeight()) < 0.5f;
} else {
mClosing = mExpandedHeight > 0 && mVel < 0;
}
@@ -268,7 +269,7 @@ public class PanelView extends FrameLayout {
if (DEBUG) logf("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
if (DEBUG) logf("tick: before: h=%d", (int) mExpandedHeight);
- final float fh = getFullHeight();
+ final float fh = getMaxPanelHeight();
boolean braking = false;
if (BRAKES) {
if (mClosing) {
@@ -351,6 +352,9 @@ public class PanelView extends FrameLayout {
mPeekHeight = res.getDimension(R.dimen.peek_height)
+ getPaddingBottom() // our window might have a dropshadow
- (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow
+
+ final ViewConfiguration configuration = ViewConfiguration.get(getContext());
+ mTouchSlop = configuration.getScaledTouchSlop();
}
private void trackMovement(MotionEvent event) {
@@ -363,10 +367,221 @@ public class PanelView extends FrameLayout {
event.offsetLocation(-deltaX, -deltaY);
}
- // Pass all touches along to the handle, allowing the user to drag the panel closed from its interior
@Override
public boolean onTouchEvent(MotionEvent event) {
- return mHandleView.dispatchTouchEvent(event);
+
+ /*
+ * We capture touch events here and update the expand height here in case according to
+ * the users fingers. This also handles multi-touch.
+ *
+ * If the user just clicks shortly, we give him a quick peek of the shade.
+ *
+ * Flinging is also enabled in order to open or close the shade.
+ */
+
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
+ }
+ final float y = event.getY(pointerIndex);
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mTracking = true;
+ if (mHandleView != null) {
+ mHandleView.setPressed(true);
+ postInvalidate(); // catch the press state change
+ }
+
+ mInitialTouchY = y;
+ initVelocityTracker();
+ trackMovement(event);
+ mTimeAnimator.cancel(); // end any outstanding animations
+ mBar.onTrackingStarted(PanelView.this);
+ mInitialOffsetOnTouch = mExpandedHeight;
+ if (mExpandedHeight == 0) {
+ mJustPeeked = true;
+ runPeekAnimation();
+ }
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ final float newY = event.getY(newIndex);
+ mTrackingPointer = event.getPointerId(newIndex);
+ mInitialOffsetOnTouch = mExpandedHeight;
+ mInitialTouchY = newY;
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY + mInitialOffsetOnTouch;
+ if (h > mPeekHeight) {
+ if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
+ mPeekAnimator.cancel();
+ }
+ mJustPeeked = false;
+ }
+ if (!mJustPeeked) {
+ setExpandedHeightInternal(h);
+ mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
+ }
+
+ trackMovement(event);
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mFinalTouchY = y;
+ mTracking = false;
+ mTrackingPointer = -1;
+ if (mHandleView != null) {
+ mHandleView.setPressed(false);
+ postInvalidate(); // catch the press state change
+ }
+ mBar.onTrackingStopped(PanelView.this);
+ trackMovement(event);
+
+ float vel = getCurrentVelocity();
+ fling(vel, true);
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ break;
+ }
+ return true;
+ }
+
+ private float getCurrentVelocity() {
+ float vel = 0;
+ float yVel = 0, xVel = 0;
+ boolean negative = false;
+
+ // the velocitytracker might be null if we got a bad input stream
+ if (mVelocityTracker == null) {
+ return 0;
+ }
+
+ mVelocityTracker.computeCurrentVelocity(1000);
+
+ yVel = mVelocityTracker.getYVelocity();
+ negative = yVel < 0;
+
+ xVel = mVelocityTracker.getXVelocity();
+ if (xVel < 0) {
+ xVel = -xVel;
+ }
+ if (xVel > mFlingGestureMaxXVelocityPx) {
+ xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
+ }
+
+ vel = (float) Math.hypot(yVel, xVel);
+ if (vel > mFlingGestureMaxOutputVelocityPx) {
+ vel = mFlingGestureMaxOutputVelocityPx;
+ }
+
+ // if you've barely moved your finger, we treat the velocity as 0
+ // preventing spurious flings due to touch screen jitter
+ final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
+ if (deltaY < mFlingGestureMinDistPx
+ || vel < mFlingExpandMinVelocityPx
+ ) {
+ vel = 0;
+ }
+
+ if (negative) {
+ vel = -vel;
+ }
+
+ if (DEBUG) {
+ logf("gesture: dy=%f vel=(%f,%f) vlinear=%f",
+ deltaY,
+ xVel, yVel,
+ vel);
+ }
+ return vel;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+
+ /*
+ * If the user drags anywhere inside the panel we intercept it if he moves his finger
+ * upwards. This allows closing the shade from anywhere inside the panel.
+ *
+ * We only do this if the current content is scrolled to the bottom,
+ * i.e isScrolledToBottom() is true and therefore there is no conflicting scrolling gesture
+ * possible.
+ */
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
+ }
+ final float y = event.getY(pointerIndex);
+ boolean scrolledToBottom = isScrolledToBottom();
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mTracking = true;
+ if (mHandleView != null) {
+ mHandleView.setPressed(true);
+ // catch the press state change
+ postInvalidate();
+ }
+ mInitialTouchY = y;
+ initVelocityTracker();
+ trackMovement(event);
+ mTimeAnimator.cancel(); // end any outstanding animations
+ if (mExpandedHeight == 0 || y > getContentHeight()) {
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ mTrackingPointer = event.getPointerId(newIndex);
+ final float newY = event.getY(newIndex);
+ mInitialTouchY = newY;
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ trackMovement(event);
+ if (scrolledToBottom) {
+ if (h < -mTouchSlop) {
+ mInitialOffsetOnTouch = mExpandedHeight;
+ mInitialTouchY = y;
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+ }
+
+ private void initVelocityTracker() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ }
+ mVelocityTracker = FlingTracker.obtain();
+ }
+
+ protected boolean isScrolledToBottom() {
+ return false;
+ }
+
+ protected float getContentHeight() {
+ return mExpandedHeight;
}
@Override
@@ -375,134 +590,6 @@ public class PanelView extends FrameLayout {
mHandleView = findViewById(R.id.handle);
loadDimens();
-
- if (DEBUG) logf("handle view: " + mHandleView);
- if (mHandleView != null) {
- mHandleView.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- int pointerIndex = event.findPointerIndex(mTrackingPointer);
- if (pointerIndex < 0) {
- pointerIndex = 0;
- mTrackingPointer = event.getPointerId(pointerIndex);
- }
- final float y = event.getY(pointerIndex);
- final float rawDelta = event.getRawY() - event.getY();
- final float rawY = y + rawDelta;
- if (DEBUG) logf("handle.onTouch: a=%s p=[%d,%d] y=%.1f rawY=%.1f off=%.1f",
- MotionEvent.actionToString(event.getAction()),
- mTrackingPointer, pointerIndex,
- y, rawY, mTouchOffset);
- PanelView.this.getLocationOnScreen(mAbsPos);
-
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- mTracking = true;
- mHandleView.setPressed(true);
- postInvalidate(); // catch the press state change
- mInitialTouchY = y;
- mVelocityTracker = FlingTracker.obtain();
- trackMovement(event);
- mTimeAnimator.cancel(); // end any outstanding animations
- mBar.onTrackingStarted(PanelView.this);
- mTouchOffset = (rawY - mAbsPos[1]) - mExpandedHeight;
- if (mExpandedHeight == 0) {
- mJustPeeked = true;
- runPeekAnimation();
- }
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- final int upPointer = event.getPointerId(event.getActionIndex());
- if (mTrackingPointer == upPointer) {
- // gesture is ongoing, find a new pointer to track
- final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
- final float newY = event.getY(newIndex);
- final float newRawY = newY + rawDelta;
- mTrackingPointer = event.getPointerId(newIndex);
- mTouchOffset = (newRawY - mAbsPos[1]) - mExpandedHeight;
- mInitialTouchY = newY;
- }
- break;
-
- case MotionEvent.ACTION_MOVE:
- final float h = rawY - mAbsPos[1] - mTouchOffset;
- if (h > mPeekHeight) {
- if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
- mPeekAnimator.cancel();
- }
- mJustPeeked = false;
- }
- if (!mJustPeeked) {
- PanelView.this.setExpandedHeightInternal(h);
- mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
- }
-
- trackMovement(event);
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mFinalTouchY = y;
- mTracking = false;
- mTrackingPointer = -1;
- mHandleView.setPressed(false);
- postInvalidate(); // catch the press state change
- mBar.onTrackingStopped(PanelView.this);
- trackMovement(event);
-
- float vel = 0, yVel = 0, xVel = 0;
- boolean negative = false;
-
- if (mVelocityTracker != null) {
- // the velocitytracker might be null if we got a bad input stream
- mVelocityTracker.computeCurrentVelocity(1000);
-
- yVel = mVelocityTracker.getYVelocity();
- negative = yVel < 0;
-
- xVel = mVelocityTracker.getXVelocity();
- if (xVel < 0) {
- xVel = -xVel;
- }
- if (xVel > mFlingGestureMaxXVelocityPx) {
- xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
- }
-
- vel = (float)Math.hypot(yVel, xVel);
- if (vel > mFlingGestureMaxOutputVelocityPx) {
- vel = mFlingGestureMaxOutputVelocityPx;
- }
-
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
-
- // if you've barely moved your finger, we treat the velocity as 0
- // preventing spurious flings due to touch screen jitter
- final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
- if (deltaY < mFlingGestureMinDistPx
- || vel < mFlingExpandMinVelocityPx
- ) {
- vel = 0;
- }
-
- if (negative) {
- vel = -vel;
- }
-
- if (DEBUG) logf("gesture: dy=%f vel=(%f,%f) vlinear=%f",
- deltaY,
- xVel, yVel,
- vel);
-
- fling(vel, true);
-
- break;
- }
- return true;
- }});
- }
}
public void fling(float vel, boolean always) {
@@ -543,19 +630,18 @@ public class PanelView extends FrameLayout {
// Did one of our children change size?
int newHeight = getMeasuredHeight();
- if (newHeight != mFullHeight) {
- mFullHeight = newHeight;
- // If the user isn't actively poking us, let's rubberband to the content
- if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
- && mExpandedHeight > 0 && mExpandedHeight != mFullHeight) {
- mExpandedHeight = mFullHeight;
- }
+ if (newHeight != mMaxPanelHeight) {
+ mMaxPanelHeight = newHeight;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- (int) mExpandedHeight, MeasureSpec.AT_MOST); // MeasureSpec.getMode(heightMeasureSpec));
+ getDesiredMeasureHeight(), MeasureSpec.AT_MOST);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
+ protected int getDesiredMeasureHeight() {
+ return (int) mExpandedHeight;
+ }
+
public void setExpandedHeight(float height) {
if (DEBUG) logf("setExpandedHeight(%.1f)", height);
@@ -569,8 +655,20 @@ public class PanelView extends FrameLayout {
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
- if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, mFullHeight);
+ if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom,
+ (int)mExpandedHeight, mMaxPanelHeight);
super.onLayout(changed, left, top, right, bottom);
+ requestPanelHeightUpdate();
+ }
+
+ protected void requestPanelHeightUpdate() {
+ float currentMaxPanelHeight = getMaxPanelHeight();
+
+ // If the user isn't actively poking us, let's update the height
+ if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
+ && mExpandedHeight > 0 && currentMaxPanelHeight != mExpandedHeight) {
+ setExpandedHeightInternal(currentMaxPanelHeight);
+ }
}
public void setExpandedHeightInternal(float h) {
@@ -583,7 +681,7 @@ public class PanelView extends FrameLayout {
h = 0;
}
- float fh = getFullHeight();
+ float fh = getMaxPanelHeight();
if (fh == 0) {
// Hmm, full height hasn't been computed yet
}
@@ -593,9 +691,13 @@ public class PanelView extends FrameLayout {
mExpandedHeight = h;
- if (DEBUG) logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
+ if (DEBUG) {
+ logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh,
+ mTracking ? "T" : "f", mRubberbanding ? "T" : "f");
+ }
+
+ onHeightUpdated(mExpandedHeight);
- requestLayout();
// FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
// lp.height = (int) mExpandedHeight;
// setLayoutParams(lp);
@@ -603,13 +705,23 @@ public class PanelView extends FrameLayout {
mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh);
}
- private float getFullHeight() {
- if (mFullHeight <= 0) {
- if (DEBUG) logf("Forcing measure() since fullHeight=" + mFullHeight);
+ protected void onHeightUpdated(float expandedHeight) {
+ requestLayout();
+ }
+
+ /**
+ * This returns the maximum height of the panel. Children should override this if their
+ * desired height is not the full height.
+ *
+ * @return the default implementation simply returns the maximum height.
+ */
+ protected int getMaxPanelHeight() {
+ if (mMaxPanelHeight <= 0) {
+ if (DEBUG) logf("Forcing measure() since mMaxPanelHeight=" + mMaxPanelHeight);
measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
}
- return mFullHeight;
+ return mMaxPanelHeight;
}
public void setExpandedFraction(float frac) {
@@ -621,7 +733,7 @@ public class PanelView extends FrameLayout {
}
frac = 0;
}
- setExpandedHeight(getFullHeight() * frac);
+ setExpandedHeight(getMaxPanelHeight() * frac);
}
public float getExpandedHeight() {
@@ -633,7 +745,7 @@ public class PanelView extends FrameLayout {
}
public boolean isFullyExpanded() {
- return mExpandedHeight >= getFullHeight();
+ return mExpandedHeight >= getMaxPanelHeight();
}
public boolean isFullyCollapsed() {
@@ -681,12 +793,12 @@ public class PanelView extends FrameLayout {
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(String.format("[PanelView(%s): expandedHeight=%f fullHeight=%f closing=%s"
+ pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%f closing=%s"
+ " tracking=%s rubberbanding=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s"
+ "]",
this.getClass().getSimpleName(),
getExpandedHeight(),
- getFullHeight(),
+ getMaxPanelHeight(),
mClosing?"T":"f",
mTracking?"T":"f",
mRubberbanding?"T":"f",
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 2257aaa..4730f2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -86,7 +86,6 @@ import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.DemoMode;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
@@ -101,8 +100,6 @@ import com.android.systemui.statusbar.policy.DateView;
import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NotificationRowLayout;
-import com.android.systemui.statusbar.policy.OnSizeChangedListener;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -172,7 +169,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
Display mDisplay;
Point mCurrentDisplaySize = new Point();
private float mHeadsUpVerticalOffset;
- private int[] mPilePosition = new int[2];
+ private int[] mStackScrollerPosition = new int[2];
StatusBarWindowView mStatusBarWindow;
PhoneStatusBarView mStatusBarView;
@@ -198,7 +195,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
// expanded notifications
NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
- View mNotificationScroller;
View mExpandedContents;
int mNotificationPanelGravity;
int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
@@ -350,6 +346,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
}};
+ private Runnable mOnFlipRunnable;
+
+ public void setOnFlipRunnable(Runnable onFlipRunnable) {
+ mOnFlipRunnable = onFlipRunnable;
+ }
+
@Override
public void setZenMode(int mode) {
super.setZenMode(mode);
@@ -417,7 +419,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
mStatusBarView.setPanelHolder(holder);
- mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
+ mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
+ R.id.notification_panel);
mNotificationPanel.setStatusBar(this);
mNotificationPanelIsFullScreenWidth =
(mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
@@ -443,7 +446,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
mHeadsUpNotificationView.setBar(this);
}
if (MULTIUSER_DEBUG) {
- mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(R.id.header_debug_info);
+ mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
+ R.id.header_debug_info);
mNotificationPanelDebugText.setVisibility(View.VISIBLE);
}
@@ -482,33 +486,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
mTickerView = mStatusBarView.findViewById(R.id.ticker);
- View legacyScrollView = mStatusBarWindow.findViewById(R.id.scroll);
- NotificationStackScrollLayout notificationStack
- = (NotificationStackScrollLayout) mStatusBarWindow
- .findViewById(R.id.notification_stack_scroller);
- if (ENABLE_NOTIFICATION_STACK) {
- notificationStack.setLongPressListener(getNotificationLongClicker());
- mPile = notificationStack;
- legacyScrollView.setVisibility(View.GONE);
-
- // The scrollview and the notification container are unified now!
- // TODO: remove mNotificationScroller entirely once we fully switch to the new Layout
- mNotificationScroller = notificationStack;
- } else {
- mNotificationScroller = legacyScrollView;
- // less drawing during pulldowns
- mNotificationScroller.setVerticalScrollBarEnabled(false);
- NotificationRowLayout rowLayout
- = (NotificationRowLayout) mStatusBarWindow.findViewById(R.id.latestItems);
- rowLayout.setLayoutTransitionsEnabled(false);
- rowLayout.setLongPressListener(getNotificationLongClicker());
- mPile = rowLayout;
- notificationStack.setVisibility(View.GONE);
- }
-
- mExpandedContents = mPile; // was: expanded.findViewById(R.id.notificationLinearLayout);
-
+ mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
+ R.id.notification_stack_scroller);
+ mStackScroller.setLongPressListener(getNotificationLongClicker());
+ mExpandedContents = mStackScroller;
mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
@@ -551,7 +533,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
}
if (mHasFlipSettings) {
- mNotificationButton = (ImageView) mStatusBarWindow.findViewById(R.id.notification_button);
+ mNotificationButton = (ImageView) mStatusBarWindow.findViewById(
+ R.id.notification_button);
if (mNotificationButton != null) {
mNotificationButton.setOnClickListener(mNotificationButtonListener);
}
@@ -593,17 +576,18 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (isAPhone) {
mEmergencyCallLabel =
(TextView) mStatusBarWindow.findViewById(R.id.emergency_calls_only);
- if (mEmergencyCallLabel != null) {
- mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
- mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) { }});
- mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- updateCarrierLabelVisibility(false);
- }});
- }
+ // TODO: Uncomment when correctly positioned
+// if (mEmergencyCallLabel != null) {
+// mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
+// mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
+// public void onClick(View v) { }});
+// mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+// @Override
+// public void onLayoutChange(View v, int left, int top, int right, int bottom,
+// int oldLeft, int oldTop, int oldRight, int oldBottom) {
+// updateCarrierLabelVisibility(false);
+// }});
+// }
}
mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
@@ -621,13 +605,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
// set up the dynamic hide/show of the label
- if (!ENABLE_NOTIFICATION_STACK)
- ((NotificationRowLayout) mPile).setOnSizeChangedListener(new OnSizeChangedListener() {
- @Override
- public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
- updateCarrierLabelVisibility(false);
- }
- });
+ // TODO: uncomment, handle this for the Stack scroller aswell
+// ((NotificationRowLayout) mStackScroller)
+// .setOnSizeChangedListener(new OnSizeChangedListener() {
+// @Override
+// public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
+// updateCarrierLabelVisibility(false);
}
// Quick Settings (where available, some restrictions apply)
@@ -1066,7 +1049,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
private void loadNotificationShade() {
- if (mPile == null) return;
+ if (mStackScroller == null) return;
int N = mNotificationData.size();
@@ -1092,21 +1075,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
ArrayList<View> toRemove = new ArrayList<View>();
- for (int i=0; i<mPile.getChildCount(); i++) {
- View child = mPile.getChildAt(i);
+ for (int i=0; i< mStackScroller.getChildCount(); i++) {
+ View child = mStackScroller.getChildAt(i);
if (!toShow.contains(child)) {
toRemove.add(child);
}
}
for (View remove : toRemove) {
- mPile.removeView(remove);
+ mStackScroller.removeView(remove);
}
for (int i=0; i<toShow.size(); i++) {
View v = toShow.get(i);
if (v.getParent() == null) {
- mPile.addView(v, i);
+ mStackScroller.addView(v, i);
}
}
@@ -1178,15 +1161,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
// The idea here is to only show the carrier label when there is enough room to see it,
// i.e. when there aren't enough notifications to fill the panel.
if (SPEW) {
- Log.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d",
- mPile.getHeight(), mNotificationScroller.getHeight(), mCarrierLabelHeight));
+ Log.d(TAG, String.format("stackScrollerh=%d scrollh=%d carrierh=%d",
+ mStackScroller.getHeight(), mStackScroller.getHeight(),
+ mCarrierLabelHeight));
}
final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null;
final boolean makeVisible =
!(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
- && mPile.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight)
- && mNotificationScroller.getVisibility() == View.VISIBLE;
+ && mStackScroller.getHeight() < (mNotificationPanel.getHeight()
+ - mCarrierLabelHeight - mNotificationHeaderHeight)
+ && mStackScroller.getVisibility() == View.VISIBLE;
if (force || mCarrierLabelVisible != makeVisible) {
mCarrierLabelVisible = makeVisible;
@@ -1229,7 +1214,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (mHasFlipSettings
&& mFlipSettingsView != null
&& mFlipSettingsView.getVisibility() == View.VISIBLE
- && mNotificationScroller.getVisibility() != View.VISIBLE) {
+ && mStackScroller.getVisibility() != View.VISIBLE) {
// the flip settings panel is unequivocally showing; we should not be shown
mClearButton.setVisibility(View.INVISIBLE);
} else if (mClearButton.isShown()) {
@@ -1483,9 +1468,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
mExpandedVisible = true;
- if (!ENABLE_NOTIFICATION_STACK) {
- ((NotificationRowLayout) mPile).setLayoutTransitionsEnabled(true);
- }
if (mNavigationBarView != null)
mNavigationBarView.setSlippery(true);
@@ -1600,7 +1582,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
mNotificationPanel.expand();
- if (mHasFlipSettings && mNotificationScroller.getVisibility() != View.VISIBLE) {
+ if (mHasFlipSettings && mStackScroller.getVisibility() != View.VISIBLE) {
flipToNotifications();
}
@@ -1614,11 +1596,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
- mNotificationScroller.setVisibility(View.VISIBLE);
+ mStackScroller.setVisibility(View.VISIBLE);
mScrollViewAnim = start(
startDelay(FLIP_DURATION_OUT,
interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mNotificationScroller, View.SCALE_X, 0f, 1f)
+ ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 0f, 1f)
.setDuration(FLIP_DURATION_IN)
)));
mFlipSettingsViewAnim = start(
@@ -1645,6 +1627,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
updateCarrierLabelVisibility(false);
}
}, FLIP_DURATION - 150);
+ if (mOnFlipRunnable != null) {
+ mOnFlipRunnable.run();
+ }
}
@Override
@@ -1676,11 +1661,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
mFlipSettingsView.setScaleX(1f);
mFlipSettingsView.setVisibility(View.VISIBLE);
mSettingsButton.setVisibility(View.GONE);
- mNotificationScroller.setVisibility(View.GONE);
- mNotificationScroller.setScaleX(0f);
+ mStackScroller.setVisibility(View.GONE);
+ mStackScroller.setScaleX(0f);
mNotificationButton.setVisibility(View.VISIBLE);
mNotificationButton.setAlpha(1f);
mClearButton.setVisibility(View.GONE);
+ if (mOnFlipRunnable != null) {
+ mOnFlipRunnable.run();
+ }
+ }
+
+ public boolean isFlippedToSettings() {
+ if (mFlipSettingsView != null) {
+ return mFlipSettingsView.getVisibility() == View.VISIBLE;
+ }
+ return false;
}
public void flipToSettings() {
@@ -1704,15 +1699,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
mScrollViewAnim = start(
setVisibilityWhenDone(
interpolator(mAccelerateInterpolator,
- ObjectAnimator.ofFloat(mNotificationScroller, View.SCALE_X, 1f, 0f)
+ ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 1f, 0f)
)
.setDuration(FLIP_DURATION_OUT),
- mNotificationScroller, View.INVISIBLE));
+ mStackScroller, View.INVISIBLE));
mSettingsButtonAnim = start(
setVisibilityWhenDone(
ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
.setDuration(FLIP_DURATION),
- mNotificationScroller, View.INVISIBLE));
+ mStackScroller, View.INVISIBLE));
mNotificationButton.setVisibility(View.VISIBLE);
mNotificationButtonAnim = start(
ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
@@ -1727,6 +1722,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
updateCarrierLabelVisibility(false);
}
}, FLIP_DURATION - 150);
+ if (mOnFlipRunnable != null) {
+ mOnFlipRunnable.run();
+ }
}
public void flipPanels() {
@@ -1766,8 +1764,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
- mNotificationScroller.setScaleX(1f);
- mNotificationScroller.setVisibility(View.VISIBLE);
+ mStackScroller.setScaleX(1f);
+ mStackScroller.setVisibility(View.VISIBLE);
mSettingsButton.setAlpha(1f);
mSettingsButton.setVisibility(View.VISIBLE);
mNotificationPanel.setVisibility(View.GONE);
@@ -1777,9 +1775,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
}
mExpandedVisible = false;
- if (!ENABLE_NOTIFICATION_STACK) {
- ((NotificationRowLayout) mPile).setLayoutTransitionsEnabled(false);
- }
if (mNavigationBarView != null)
mNavigationBarView.setSlippery(false);
visibilityChanged(false);
@@ -1806,53 +1801,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
}
- /**
- * Enables or disables layers on the children of the notifications pile.
- *
- * When layers are enabled, this method attempts to enable layers for the minimal
- * number of children. Only children visible when the notification area is fully
- * expanded will receive a layer. The technique used in this method might cause
- * more children than necessary to get a layer (at most one extra child with the
- * current UI.)
- *
- * @param layerType {@link View#LAYER_TYPE_NONE} or {@link View#LAYER_TYPE_HARDWARE}
- */
- private void setPileLayers(int layerType) {
- final int count = mPile.getChildCount();
-
- switch (layerType) {
- case View.LAYER_TYPE_NONE:
- for (int i = 0; i < count; i++) {
- mPile.getChildAt(i).setLayerType(layerType, null);
- }
- break;
- case View.LAYER_TYPE_HARDWARE:
- final int[] location = new int[2];
- mNotificationPanel.getLocationInWindow(location);
-
- final int left = location[0];
- final int top = location[1];
- final int right = left + mNotificationPanel.getWidth();
- final int bottom = top + getExpandedViewMaxHeight();
-
- final Rect childBounds = new Rect();
-
- for (int i = 0; i < count; i++) {
- final View view = mPile.getChildAt(i);
- view.getLocationInWindow(location);
-
- childBounds.set(location[0], location[1],
- location[0] + view.getWidth(), location[1] + view.getHeight());
-
- if (childBounds.intersects(left, top, right, bottom)) {
- view.setLayerType(layerType, null);
- }
- }
-
- break;
- }
- }
-
public boolean interceptTouchEvent(MotionEvent event) {
if (DEBUG_GESTURES) {
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
@@ -2230,11 +2178,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
pw.println(" mTicking=" + mTicking);
pw.println(" mTracking=" + mTracking);
pw.println(" mDisplayMetrics=" + mDisplayMetrics);
- pw.println(" mPile: " + viewInfo(mPile));
+ pw.println(" mStackScroller: " + viewInfo(mStackScroller));
pw.println(" mTickerView: " + viewInfo(mTickerView));
- pw.println(" mNotificationScroller: " + viewInfo(mNotificationScroller)
- + " scroll " + mNotificationScroller.getScrollX()
- + "," + mNotificationScroller.getScrollY());
+ pw.println(" mStackScroller: " + viewInfo(mStackScroller)
+ + " scroll " + mStackScroller.getScrollX()
+ + "," + mStackScroller.getScrollY());
}
pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
@@ -2409,8 +2357,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
- mPile.getLocationOnScreen(mPilePosition);
- mHeadsUpVerticalOffset = mPilePosition[1] - mNaturalBarHeight;
+ mStackScroller.getLocationOnScreen(mStackScrollerPosition);
+ mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight;
}
updateCarrierLabelVisibility(false);
@@ -2428,7 +2376,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
public void onClick(View v) {
- // TODO: Handle this better with notification stack scroller
synchronized (mNotificationData) {
mPostCollapseCleanup = new Runnable() {
@Override
@@ -2437,86 +2384,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
Log.v(TAG, "running post-collapse cleanup");
}
try {
- if (!ENABLE_NOTIFICATION_STACK) {
- ((NotificationRowLayout) mPile).setViewRemoval(true);
- }
mBarService.onClearAllNotifications(mCurrentUserId);
} catch (Exception ex) { }
}
};
- if(ENABLE_NOTIFICATION_STACK) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- return;
- }
-
- // animate-swipe all dismissable notifications, then animate the shade closed
- int numChildren = mPile.getChildCount();
-
- int scrollTop = mNotificationScroller.getScrollY();
- int scrollBottom = scrollTop + mNotificationScroller.getHeight();
- final ArrayList<View> snapshot = new ArrayList<View>(numChildren);
- for (int i=0; i<numChildren; i++) {
- final View child = mPile.getChildAt(i);
- if (((SwipeHelper.Callback) mPile).canChildBeDismissed(child)
- && child.getBottom() > scrollTop && child.getTop() < scrollBottom) {
- snapshot.add(child);
- }
- }
- if (snapshot.isEmpty()) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- return;
- }
- new Thread(new Runnable() {
- @Override
- public void run() {
- // Decrease the delay for every row we animate to give the sense of
- // accelerating the swipes
- final int ROW_DELAY_DECREMENT = 10;
- int currentDelay = 140;
- int totalDelay = 0;
-
-
- if (!ENABLE_NOTIFICATION_STACK) {
- // Set the shade-animating state to avoid doing other work during
- // all of these animations. In particular, avoid layout and
- // redrawing when collapsing the shade.
- ((NotificationRowLayout) mPile).setViewRemoval(false);
- }
-
- View sampleView = snapshot.get(0);
- int width = sampleView.getWidth();
- final int dir = sampleView.isLayoutRtl() ? -1 : +1;
- final int velocity = dir * width * 8; // 1000/8 = 125 ms duration
- for (final View _v : snapshot) {
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (!ENABLE_NOTIFICATION_STACK) {
- ((NotificationRowLayout) mPile).dismissRowAnimated(
- _v, velocity);
- } else {
- ((NotificationStackScrollLayout) mPile).dismissRowAnimated(
- _v, velocity);
- }
- }
- }, totalDelay);
- currentDelay = Math.max(50, currentDelay - ROW_DELAY_DECREMENT);
- totalDelay += currentDelay;
- }
- // Delay the collapse animation until after all swipe animations have
- // finished. Provide some buffer because there may be some extra delay
- // before actually starting each swipe animation. Ideally, we'd
- // synchronize the end of those animations with the start of the collaps
- // exactly.
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- }
- }, totalDelay + 225);
- }
- }).start();
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ return;
+ // TODO: Handle this better with notification stack scroller
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index eeae081..a7121c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -24,13 +24,13 @@ import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.widget.FrameLayout;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -40,9 +40,8 @@ public class StatusBarWindowView extends FrameLayout
public static final boolean DEBUG = BaseStatusBar.DEBUG;
private ExpandHelper mExpandHelper;
- private ViewGroup latestItems;
+ private NotificationStackScrollLayout mStackScrollLayout;
private NotificationPanelView mNotificationPanel;
- private View mNotificationScroller;
PhoneStatusBar mService;
@@ -56,37 +55,15 @@ public class StatusBarWindowView extends FrameLayout
protected void onAttachedToWindow () {
super.onAttachedToWindow();
- ExpandHelper.ScrollAdapter scrollAdapter;
- if (BaseStatusBar.ENABLE_NOTIFICATION_STACK) {
- NotificationStackScrollLayout stackScrollLayout =
- (NotificationStackScrollLayout) findViewById(R.id.notification_stack_scroller);
-
- // ScrollView and notification container are unified in a single view now.
- latestItems = stackScrollLayout;
- scrollAdapter = stackScrollLayout;
- mNotificationScroller = stackScrollLayout;
- } else {
- latestItems = (ViewGroup) findViewById(R.id.latestItems);
- mNotificationScroller = findViewById(R.id.scroll);
- scrollAdapter = new ExpandHelper.ScrollAdapter() {
- @Override
- public boolean isScrolledToTop() {
- return mNotificationScroller.getScrollY() == 0;
- }
-
- @Override
- public View getHostView() {
- return mNotificationScroller;
- }
- };
- }
+ mStackScrollLayout = (NotificationStackScrollLayout) findViewById(
+ R.id.notification_stack_scroller);
mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel);
int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
- mExpandHelper = new ExpandHelper(getContext(), (ExpandHelper.Callback) latestItems,
+ mExpandHelper = new ExpandHelper(getContext(), mStackScrollLayout,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
- mExpandHelper.setScrollAdapter(scrollAdapter);
+ mExpandHelper.setScrollAdapter(mStackScrollLayout);
// We really need to be able to animate while window animations are going on
// so that activities may be started asynchronously from panel animations
@@ -113,7 +90,7 @@ public class StatusBarWindowView extends FrameLayout
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercept = false;
if (mNotificationPanel.isFullyExpanded()
- && mNotificationScroller.getVisibility() == View.VISIBLE) {
+ && mStackScrollLayout.getVisibility() == View.VISIBLE) {
intercept = mExpandHelper.onInterceptTouchEvent(ev);
}
if (!intercept) {
@@ -122,7 +99,7 @@ public class StatusBarWindowView extends FrameLayout
if (intercept) {
MotionEvent cancellation = MotionEvent.obtain(ev);
cancellation.setAction(MotionEvent.ACTION_CANCEL);
- latestItems.onInterceptTouchEvent(cancellation);
+ mStackScrollLayout.onInterceptTouchEvent(cancellation);
cancellation.recycle();
}
return intercept;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ScrollAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ScrollAdapter.java
new file mode 100644
index 0000000..f35e22d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ScrollAdapter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.view.View;
+
+/**
+ * A scroll adapter which can be queried for meta information about the scroll state
+ */
+public interface ScrollAdapter {
+
+ /**
+ * @return Whether the view returned by {@link #getHostView()} is scrolled to the top
+ */
+ public boolean isScrolledToTop();
+
+ /**
+ * @return Whether the view returned by {@link #getHostView()} is scrolled to the bottom
+ */
+ public boolean isScrolledToBottom();
+
+ /**
+ * @return The view in which the scrolling is performed
+ */
+ public View getHostView();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index f6eeb6d..04b7f53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -39,12 +39,13 @@ import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
+import com.android.systemui.statusbar.policy.ScrollAdapter;
/**
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
public class NotificationStackScrollLayout extends ViewGroup
- implements SwipeHelper.Callback, ExpandHelper.Callback, ExpandHelper.ScrollAdapter {
+ implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter {
private static final String TAG = "NotificationStackScrollLayout";
private static final boolean DEBUG = false;
@@ -55,7 +56,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private static final int INVALID_POINTER = -1;
private SwipeHelper mSwipeHelper;
- private boolean mAllowScrolling = true;
+ private boolean mSwipingInProgress = true;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private int mOwnScrollY;
private int mMaxLayoutHeight;
@@ -89,7 +90,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* The current State this Layout is in
*/
private final StackScrollState mCurrentStackScrollState = new StackScrollState(this);
-
+
private OnChildLocationsChangedListener mListener;
public NotificationStackScrollLayout(Context context) {
@@ -279,7 +280,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
/**
- * Get the current height of the view. This is at most the size of the view given by a the
+ * Get the current height of the view. This is at most the msize of the view given by a the
* layout but it can also be made smaller by setting {@link #mCurrentStackHeight}
*
* @return either the layout height or the externally defined height, whichever is smaller
@@ -288,6 +289,14 @@ public class NotificationStackScrollLayout extends ViewGroup
return Math.min(mMaxLayoutHeight, mCurrentStackHeight);
}
+ public int getItemHeight() {
+ return mCollapsedSize;
+ }
+
+ public int getBottomStackPeekSize() {
+ return mBottomStackPeekSize;
+ }
+
public void setLongPressListener(View.OnLongClickListener listener) {
mSwipeHelper.setLongPressListener(listener);
}
@@ -298,15 +307,15 @@ public class NotificationStackScrollLayout extends ViewGroup
if (veto != null && veto.getVisibility() != View.GONE) {
veto.performClick();
}
- allowScrolling(true);
+ setSwipingInProgress(false);
}
public void onBeginDrag(View v) {
- allowScrolling(false);
+ setSwipingInProgress(true);
}
public void onDragCancelled(View v) {
- allowScrolling(true);
+ setSwipingInProgress(false);
}
public View getChildAtPosition(MotionEvent ev) {
@@ -365,8 +374,11 @@ public class NotificationStackScrollLayout extends ViewGroup
return (veto != null && veto.getVisibility() != View.GONE);
}
- private void allowScrolling(boolean allow) {
- mAllowScrolling = allow;
+ private void setSwipingInProgress(boolean isSwiped) {
+ mSwipingInProgress = isSwiped;
+ if(isSwiped) {
+ requestDisallowInterceptTouchEvent(true);
+ }
}
@Override
@@ -386,7 +398,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean scrollerWantsIt = false;
- if (mAllowScrolling) {
+ if (!mSwipingInProgress) {
scrollerWantsIt = onScrollTouch(ev);
}
boolean horizontalSwipeWantsIt = false;
@@ -409,12 +421,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
boolean isBeingDragged = !mScroller.isFinished();
setIsBeingDragged(isBeingDragged);
- if (isBeingDragged) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- }
/*
* If being flinged and user touches, stop the fling. isFinished
@@ -439,10 +445,6 @@ public class NotificationStackScrollLayout extends ViewGroup
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
setIsBeingDragged(true);
if (deltaY > 0) {
deltaY -= mTouchSlop;
@@ -642,7 +644,7 @@ public class NotificationStackScrollLayout extends ViewGroup
if (getChildCount() > 0) {
int contentHeight = getContentHeight();
scrollRange = Math.max(0,
- contentHeight - mMaxLayoutHeight + mCollapsedSize);
+ contentHeight - mMaxLayoutHeight + mBottomStackPeekSize);
}
return scrollRange;
}
@@ -697,7 +699,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean scrollWantsIt = false;
- if (mAllowScrolling) {
+ if (!mSwipingInProgress) {
scrollWantsIt = onInterceptTouchEventScroll(ev);
}
boolean swipeWantsIt = false;
@@ -763,10 +765,6 @@ public class NotificationStackScrollLayout extends ViewGroup
mLastMotionY = y;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
}
break;
}
@@ -823,6 +821,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private void setIsBeingDragged(boolean isDragged) {
mIsBeingDragged = isDragged;
if (isDragged) {
+ requestDisallowInterceptTouchEvent(true);
mSwipeHelper.removeLongPressCallback();
}
}
@@ -841,10 +840,19 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
+ public boolean isScrolledToBottom() {
+ return mOwnScrollY >= getScrollRange();
+ }
+
+ @Override
public View getHostView() {
return this;
}
+ public int getEmptyBottomMargin() {
+ return Math.max(getHeight() - mContentHeight, 0);
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 6d2ba6a..4745f3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -86,7 +86,7 @@ public class StackScrollAlgorithm {
// First we reset the view states to their default values.
resultState.resetViewStates();
- // The first element is always in there so it's initialized with 1.0f.
+ // The first element is always in there so it's initialized with 1.0f;
algorithmState.itemsInTopStack = 1.0f;
algorithmState.partialInTop = 0.0f;
algorithmState.lastTopStackIndex = 0;
@@ -102,7 +102,7 @@ public class StackScrollAlgorithm {
// Phase 3:
updateZValuesForState(resultState, algorithmState);
- // Write the algorithm state to the result.
+ // write the algorithm state to the result
resultState.setScrollY(algorithmState.scrollY);
}
@@ -151,7 +151,7 @@ public class StackScrollAlgorithm {
// Case 2:
// First element of regular scrollview comes next, so the position is just the
// scrolling position
- nextYPosition = scrollOffset;
+ nextYPosition = Math.min(scrollOffset, transitioningPositionStart);
childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
} else if (nextYPosition >= transitioningPositionStart) {
if (currentYPosition >= transitioningPositionStart) {
@@ -180,6 +180,7 @@ public class StackScrollAlgorithm {
if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
+ nextYPosition = Math.max(0, nextYPosition);
currentYPosition = nextYPosition;
yPositionInScrollView = yPositionInScrollViewAfterElement;
}
@@ -253,6 +254,8 @@ public class StackScrollAlgorithm {
nextYPosition = mCollapsedSize + mPaddingBetweenElements -
mTopStackIndentationFunctor.getValue(
algorithmState.itemsInTopStack - i - 1);
+ nextYPosition = Math.min(nextYPosition, mLayoutHeight - mCollapsedSize
+ - mBottomStackPeekSize);
if (paddedIndex == 0) {
childViewState.alpha = 1.0f - algorithmState.partialInTop;
childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index ef640d5..03d920a 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -1,10 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.vpndialogs">
<application android:label="VpnDialogs"
android:allowBackup="false" >
<activity android:name=".ConfirmDialog"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert">
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -12,7 +30,7 @@
</activity>
<activity android:name=".ManageDialog"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/packages/WallpaperCropper/AndroidManifest.xml b/packages/WallpaperCropper/AndroidManifest.xml
index 27755bd..81d1085 100644
--- a/packages/WallpaperCropper/AndroidManifest.xml
+++ b/packages/WallpaperCropper/AndroidManifest.xml
@@ -1,3 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.wallpapercropper" >
<uses-permission android:name="android.permission.SET_WALLPAPER" />
diff --git a/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
index 97d7001..cf78989 100644
--- a/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
+++ b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
@@ -28,7 +28,7 @@
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/loading"
- style="@android:style/Widget.Holo.ProgressBar.Large"
+ style="@android:style/Widget.DeviceDefault.Light.ProgressBar.Large"
android:visibility="invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
index 2b63fe0..b27a387 100644
--- a/packages/WallpaperCropper/res/values/styles.xml
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -15,13 +15,13 @@
-->
<resources>
- <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Holo">
+ <style name="Theme.WallpaperCropper" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowActionBarOverlay">true</item>
</style>
- <style name="WallpaperCropperActionBar" parent="android:style/Widget.Holo.ActionBar">
+ <style name="WallpaperCropperActionBar" parent="android:style/Widget.DeviceDefault.Light.ActionBar">
<item name="android:displayOptions">showCustom</item>
<item name="android:background">#88000000</item>
</style>