OSDN Git Service

Gestures for expanding notifications.
authorDaniel Sandler <dsandler@android.com>
Mon, 12 Mar 2012 18:38:58 +0000 (14:38 -0400)
committerChris Wren <cwren@android.com>
Wed, 18 Apr 2012 15:21:19 +0000 (11:21 -0400)
Change-Id: I104c157ffcc2d60b3f0a95c59d4322b07103b69f

17 files changed:
core/java/android/app/Notification.java
core/res/res/layout/adaptive_notification_wrapper.xml [new file with mode: 0644]
core/res/res/layout/notification_template_base.xml
core/res/res/layout/notification_template_big_picture.xml
core/res/res/layout/notification_template_big_text.xml [new file with mode: 0644]
core/res/res/values/public.xml
packages/SystemUI/res/layout/notification_adaptive_wrapper.xml [new file with mode: 0644]
packages/SystemUI/res/layout/status_bar_notification_row.xml
packages/SystemUI/res/values/dimens.xml
packages/SystemUI/src/com/android/systemui/ExpandHelper.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/Gefingerpoken.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/SwipeHelper.java
packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java

index dc796bf..22d84f0 100644 (file)
@@ -1681,7 +1681,7 @@ public class Notification implements Parcelable
         }
 
         private RemoteViews makeBigContentView() {
-            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_base);
+            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_big_text);
 
             contentView.setTextViewText(R.id.big_text, mBigText);
             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
diff --git a/core/res/res/layout/adaptive_notification_wrapper.xml b/core/res/res/layout/adaptive_notification_wrapper.xml
new file mode 100644 (file)
index 0000000..df9d720
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:textAppearance="?android:attr/dropDownHintAppearance"
+    android:singleLine="true"
+    android:layout_marginLeft="3dip"
+    android:layout_marginTop="3dip"
+    android:layout_marginRight="3dip"
+    android:layout_marginBottom="3dip"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" />
index b9710d6..74b3fa9 100644 (file)
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:background="@android:color/background_dark"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    internal:layout_minHeight="64dp"
+    internal:layout_maxHeight="64dp"
     >
     <ImageView android:id="@+id/icon"
         android:layout_width="@dimen/notification_large_icon_width"
index 8be84bd..2150096 100644 (file)
 -->
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:background="@android:color/background_dark"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    internal:layout_minHeight="65dp"
+    internal:layout_maxHeight="unbounded"
     >
     <ImageView
         android:id="@+id/big_picture"
@@ -30,4 +34,4 @@
         android:layout_height="wrap_content"
         android:layout_marginTop="192dp"
         />
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
new file mode 100644 (file)
index 0000000..6a64cf8
--- /dev/null
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:background="@android:color/background_dark"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    internal:layout_minHeight="65dp"
+    internal:layout_maxHeight="unbounded"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+        android:background="@android:drawable/notify_panel_notification_icon_bg_tile"
+        android:scaleType="center"
+        />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="fill_vertical"
+        android:layout_marginLeft="@dimen/notification_large_icon_width"
+        android:minHeight="@dimen/notification_large_icon_height"
+        android:orientation="vertical"
+        android:paddingLeft="12dp"
+        android:paddingRight="12dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:gravity="center_vertical"
+        >
+        <LinearLayout
+            android:id="@+id/line1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            >
+            <TextView android:id="@+id/title"
+                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:fadingEdge="horizontal"
+                android:layout_weight="1"
+                />
+            <ViewStub android:id="@+id/time"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:layout_weight="0"
+                android:visibility="gone"
+                android:layout="@layout/notification_template_part_time"
+                />
+            <ViewStub android:id="@+id/chronometer"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:layout_weight="0"
+                android:visibility="gone"
+                android:layout="@layout/notification_template_part_chronometer"
+                />
+        </LinearLayout>
+        <TextView android:id="@+id/text2"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="-2dp"
+            android:layout_mgarginBottom="-2dp"
+            android:singleLine="true"
+            android:fadingEdge="horizontal"
+            android:ellipsize="marquee"
+            android:visibility="gone"
+            />
+        <TextView android:id="@+id/big_text"
+            android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="false"
+            android:visibility="gone"
+            />
+        <LinearLayout
+            android:id="@+id/line3"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            >
+            <TextView android:id="@+id/text"
+                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:layout_gravity="center"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:fadingEdge="horizontal"
+                />
+            <TextView android:id="@+id/info"
+                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:layout_weight="0"
+                android:singleLine="true"
+                android:gravity="center"
+                android:paddingLeft="8dp"
+                />
+            <ImageView android:id="@+id/right_icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:layout_weight="0"
+                android:scaleType="center"
+                android:paddingLeft="8dp"
+                android:visibility="gone"
+                android:drawableAlpha="180"
+                />
+        </LinearLayout>
+        <ProgressBar
+            android:id="@android:id/progress"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?android:attr/progressBarStyleHorizontal"
+            />
+        <LinearLayout
+                android:id="@+id/actions"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+                >
+                <!-- actions will be added here -->
+        </LinearLayout>
+    </LinearLayout>
+</FrameLayout>
index 6266726..b564b97 100644 (file)
   <java-symbol type="layout" name="notification_intruder_content" />
   <java-symbol type="layout" name="notification_template_base" />
   <java-symbol type="layout" name="notification_template_big_picture" />
+  <java-symbol type="layout" name="notification_template_big_text" />
   <java-symbol type="layout" name="notification_template_part_time" />
   <java-symbol type="layout" name="notification_template_part_chronometer" />
   <java-symbol type="layout" name="notification_template_inbox" />
diff --git a/packages/SystemUI/res/layout/notification_adaptive_wrapper.xml b/packages/SystemUI/res/layout/notification_adaptive_wrapper.xml
new file mode 100644 (file)
index 0000000..15d0890
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<SizeAdaptiveLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:background="@android:color/background_dark"
+    android:id="@+id/notification_adaptive_wrapper"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" />
index c307c6e..a0d1b08 100644 (file)
@@ -1,6 +1,6 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_height"
+    android:layout_height="wrap_content"
     >
 
     <Button
         android:focusable="true"
         android:clickable="true"
         android:background="@drawable/notification_row_bg"
-        />
+        >
+
+        <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/adaptive"
+           android:background="@android:color/background_dark"
+           android:layout_width="match_parent"
+           android:layout_height="wrap_content" />
+
+    </com.android.systemui.statusbar.LatestItemView>
 
     <View
         android:layout_width="match_parent"
index 4441ca6..f786e86 100644 (file)
     <!-- Height of notification icons in the status bar -->
     <dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
 
+    <!-- Height of a small notification in the status bar -->
+    <dimen name="notification_min_height">@android:dimen/notification_large_icon_height</dimen>
+
+    <!-- Height of a small notification in the status bar -->
+    <!-- TODO: change this back to 256dp once we deal with actions. -->
+    <dimen name="notification_max_height">320dp</dimen>
+
     <!-- size at which Notification icons will be drawn in the status bar -->
     <dimen name="status_bar_icon_drawing_size">18dip</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
new file mode 100644 (file)
index 0000000..aa289da
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2012 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;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.RectF;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import com.android.internal.widget.SizeAdaptiveLayout;
+
+public class ExpandHelper implements Gefingerpoken, OnClickListener {
+    public interface Callback {
+        View getChildAtPosition(MotionEvent ev);
+        View getChildAtPosition(float x, float y);
+    }
+
+    private static final String TAG = "ExpandHelper";
+    protected static final boolean DEBUG = false;
+    private static final long EXPAND_DURATION = 250;
+
+    @SuppressWarnings("unused")
+    private Context mContext;
+
+    private boolean mStretching;
+    private View mCurrView;
+    private float mOldHeight;
+    private float mNaturalHeight;
+    private float mInitialTouchSpan;
+    private Callback mCallback;
+    private ScaleGestureDetector mDetector;
+    private ViewScaler mScaler;
+    private ObjectAnimator mAnimation;
+
+    private int mSmallSize;
+    private int mLargeSize;
+
+
+    private class ViewScaler {
+        View mView;
+        public ViewScaler() {}
+        public void setView(View v) {
+            mView = v;
+        }
+        public void setHeight(float h) {
+            Log.v(TAG, "SetHeight: setting to " + h);
+            ViewGroup.LayoutParams lp = mView.getLayoutParams();
+            lp.height = (int)h;
+            mView.setLayoutParams(lp);
+           mView.requestLayout();
+        }
+        public float getHeight() {
+            int height = mView.getLayoutParams().height;
+            if (height < 0) {
+                height = mView.getMeasuredHeight();
+            }
+            return (float) height;
+        }
+        public int getNaturalHeight(int maximum) {
+            ViewGroup.LayoutParams lp = mView.getLayoutParams();
+           if (DEBUG) Log.v(TAG, "Inspecting a child of type: " + mView.getClass().getName());
+            int oldHeight = lp.height;
+            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+            mView.setLayoutParams(lp);
+            mView.measure(
+                    View.MeasureSpec.makeMeasureSpec(mView.getMeasuredWidth(),
+                                                    View.MeasureSpec.EXACTLY),
+                    View.MeasureSpec.makeMeasureSpec(maximum,
+                                                    View.MeasureSpec.AT_MOST));
+            lp.height = oldHeight;
+            mView.setLayoutParams(lp);
+            return mView.getMeasuredHeight();
+        }
+    }
+
+    public ExpandHelper(Context context, Callback callback, int small, int large) {
+        mSmallSize = small;
+        mLargeSize = large;
+        mContext = context;
+        mCallback = callback;
+        mScaler = new ViewScaler();
+        mDetector =
+                new ScaleGestureDetector(context,
+                                         new ScaleGestureDetector.SimpleOnScaleGestureListener() {
+            @Override
+            public boolean onScaleBegin(ScaleGestureDetector detector) {
+                if (DEBUG) Log.v(TAG, "onscalebegin()");
+                View v = mCallback.getChildAtPosition(detector.getFocusX(), detector.getFocusY());
+
+                // your fingers have to be somewhat close to the bounds of the view in question
+                mInitialTouchSpan = Math.abs(detector.getCurrentSpanY());
+                if (DEBUG) Log.d(TAG, "got mInitialTouchSpan: " + mInitialTouchSpan);
+
+                mStretching = initScale(v);
+                return mStretching;
+            }
+
+            @Override
+            public boolean onScale(ScaleGestureDetector detector) {
+                if (DEBUG) Log.v(TAG, "onscale() on " + mCurrView);
+                float h = Math.abs(detector.getCurrentSpanY());
+                if (DEBUG) Log.d(TAG, "current span is: " + h);
+                h = h + mOldHeight - mInitialTouchSpan;
+                h = h<mSmallSize?mSmallSize:(h>mLargeSize?mLargeSize:h);
+                h = h>mNaturalHeight?mNaturalHeight:h;
+                if (DEBUG) Log.d(TAG, "scale continues: h=" + h);
+                mScaler.setHeight(h);
+                return true;
+            }
+
+            @Override
+            public void onScaleEnd(ScaleGestureDetector detector) {
+                if (DEBUG) Log.v(TAG, "onscaleend()");
+                // I guess we're alone now
+                if (DEBUG) Log.d(TAG, "scale end");
+                finishScale(false);
+            }
+        });
+    }
+
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (DEBUG) Log.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
+                         " stretching=" + mStretching);
+        mDetector.onTouchEvent(ev);
+        return mStretching;
+    }
+
+    public boolean onTouchEvent(MotionEvent ev) {
+        final int action = ev.getAction();
+        if (DEBUG) Log.d(TAG, "touch: act=" + (action) + " stretching=" + mStretching);
+        if (mStretching) {
+            mDetector.onTouchEvent(ev);
+        }
+        switch (action) {
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mStretching = false;
+                mCurrView = null;
+                break;
+        }
+        return true;
+    }
+    private boolean initScale(View v) {
+        if (v != null) {
+            if (DEBUG) Log.d(TAG, "scale begins on view: " + v);
+            mStretching = true;
+            mCurrView = v;
+            mScaler.setView(v);
+            mOldHeight = mScaler.getHeight();
+            mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
+            if (DEBUG) Log.d(TAG, "got mOldHeight: " + mOldHeight +
+                        " mNaturalHeight: " + mNaturalHeight);
+            v.getParent().requestDisallowInterceptTouchEvent(true);
+            if (DEBUG) v.setBackgroundColor(0xFFFFFF00);
+        }
+        return mStretching;
+    }
+
+    private void finishScale(boolean force) {
+        float h = mScaler.getHeight();
+        final boolean wasClosed = (mOldHeight == mSmallSize);
+        if (wasClosed) {
+            h = (force || h > mSmallSize) ? mNaturalHeight : mSmallSize;
+        } else {
+            h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight;
+        }
+        if (DEBUG) mCurrView.setBackgroundColor(0);
+        mAnimation = ObjectAnimator.ofFloat(mScaler, "height", h).setDuration(EXPAND_DURATION);
+        mAnimation.start();
+        mStretching = false;
+        mCurrView = null;
+    }
+
+    @Override
+    public void onClick(View v) {
+        initScale(v);
+        finishScale(true);
+
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Gefingerpoken.java b/packages/SystemUI/src/com/android/systemui/Gefingerpoken.java
new file mode 100644 (file)
index 0000000..b2d5c21
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 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;
+
+import android.view.MotionEvent;
+
+// ACHTUNG!
+public interface Gefingerpoken {
+    boolean onInterceptTouchEvent(MotionEvent ev);
+    boolean onTouchEvent(MotionEvent ev);
+}
index 276ca21..19657a9 100644 (file)
@@ -29,7 +29,7 @@ import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 
-public class SwipeHelper {
+public class SwipeHelper implements Gefingerpoken {
     static final String TAG = "com.android.systemui.SwipeHelper";
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_INVALIDATE = false;
index 8d7afc8..ede8e7a 100644 (file)
@@ -18,9 +18,14 @@ package com.android.systemui.statusbar;
 
 import java.util.ArrayList;
 
+import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Rect;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -34,15 +39,18 @@ import android.view.IWindowManager;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 import android.widget.LinearLayout;
+import android.widget.RemoteViews;
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
 import com.android.internal.statusbar.StatusBarNotification;
+import com.android.internal.widget.SizeAdaptiveLayout;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recent.RecentsPanelView;
 import com.android.systemui.recent.RecentTasksLoader;
@@ -66,12 +74,15 @@ public abstract class BaseStatusBar extends SystemUI implements
     protected IStatusBarService mBarService;
     protected H mHandler = createHandler();
 
+    // used to notify status bar for suppressing notification LED
+    protected boolean mPanelSlightlyVisible;
+
     // Recent apps
     protected RecentsPanelView mRecentsPanel;
     protected RecentTasksLoader mRecentTasksLoader;
 
     // UI-specific methods
-    
+
     /**
      * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
      * and add them to the window manager.
@@ -81,15 +92,15 @@ public abstract class BaseStatusBar extends SystemUI implements
     protected Display mDisplay;
     private IWindowManager mWindowManager;
 
-    
+
     public IWindowManager getWindowManager() {
         return mWindowManager;
     }
-    
+
     public Display getDisplay() {
         return mDisplay;
     }
-    
+
     public IStatusBarService getStatusBarService() {
         return mBarService;
     }
@@ -109,7 +120,7 @@ public abstract class BaseStatusBar extends SystemUI implements
         ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
         ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
         mCommandQueue = new CommandQueue(this, iconList);
-        
+
         int[] switches = new int[7];
         ArrayList<IBinder> binders = new ArrayList<IBinder>();
         try {
@@ -118,7 +129,7 @@ public abstract class BaseStatusBar extends SystemUI implements
         } catch (RemoteException ex) {
             // If the system process isn't there we're doomed anyway.
         }
-        
+
         createAndAddWindows();
 
         disable(switches[0]);
@@ -152,7 +163,7 @@ public abstract class BaseStatusBar extends SystemUI implements
 
         if (DEBUG) {
             Slog.d(TAG, String.format(
-                    "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x", 
+                    "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
                    iconList.size(),
                    switches[0],
                    switches[1],
@@ -161,7 +172,7 @@ public abstract class BaseStatusBar extends SystemUI implements
                    ));
         }
     }
-    
+
     protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
         View vetoButton = row.findViewById(R.id.veto);
         if (n.isClearable()) {
@@ -183,7 +194,7 @@ public abstract class BaseStatusBar extends SystemUI implements
         }
         return vetoButton;
     }
-    
+
 
     protected void applyLegacyRowBackground(StatusBarNotification sbn, View content) {
         if (sbn.notification.contentView.getLayoutId() !=
@@ -323,4 +334,178 @@ public abstract class BaseStatusBar extends SystemUI implements
             return false;
         }
     }
+
+    protected void workAroundBadLayerDrawableOpacity(View v) {
+    }
+
+    protected  boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
+        int minHeight =
+                mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
+        int maxHeight =
+                mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+        StatusBarNotification sbn = entry.notification;
+        RemoteViews oneU = sbn.notification.contentView;
+        RemoteViews large = sbn.notification.bigContentView;
+        if (oneU == null) {
+            return false;
+        }
+
+        // create the row view
+        LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
+        // XXX: temporary: while testing big notifications, auto-expand all of them
+        ViewGroup.LayoutParams lp = row.getLayoutParams();
+        if (sbn.notification.bigContentView != null) {
+            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        } else {
+            lp.height = minHeight;
+        }
+        row.setLayoutParams(lp);
+        workAroundBadLayerDrawableOpacity(row);
+        View vetoButton = updateNotificationVetoButton(row, sbn);
+        vetoButton.setContentDescription(mContext.getString(
+                R.string.accessibility_remove_notification));
+
+        // NB: the large icon is now handled entirely by the template
+
+        // bind the click event to the content area
+        ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
+        ViewGroup adaptive = (ViewGroup)row.findViewById(R.id.adaptive);
+        // XXX: update to allow controls within notification views
+        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+//        content.setOnFocusChangeListener(mFocusChangeListener);
+        PendingIntent contentIntent = sbn.notification.contentIntent;
+        if (contentIntent != null) {
+            final View.OnClickListener listener = new NotificationClicker(contentIntent,
+                    sbn.pkg, sbn.tag, sbn.id);
+            content.setOnClickListener(listener);
+        } else {
+            content.setOnClickListener(null);
+        }
+
+        View expandedOneU = null;
+        View expandedLarge = null;
+        Exception exception = null;
+        try {
+            expandedOneU = oneU.apply(mContext, adaptive);
+            if (large != null) {
+                expandedLarge = large.apply(mContext, adaptive);
+            }
+        }
+        catch (RuntimeException e) {
+            exception = e;
+        }
+        if (expandedOneU == null && expandedLarge == null) {
+            final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
+            Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
+            return false;
+        } else {
+            if (expandedOneU != null) {
+                SizeAdaptiveLayout.LayoutParams params =
+                        new SizeAdaptiveLayout.LayoutParams(expandedOneU.getLayoutParams());
+                params.minHeight = minHeight;
+                params.maxHeight = minHeight;
+                adaptive.addView(expandedOneU, params);
+            }
+            if (expandedLarge != null) {
+                SizeAdaptiveLayout.LayoutParams params =
+                        new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams());
+                params.minHeight = minHeight+1;
+                params.maxHeight = SizeAdaptiveLayout.LayoutParams.UNBOUNDED;
+                adaptive.addView(expandedLarge, params);
+            }
+            row.setDrawingCacheEnabled(true);
+        }
+
+        applyLegacyRowBackground(sbn, content);
+
+        entry.row = row;
+        entry.content = content;
+        entry.expanded = expandedOneU;
+        entry.expandedLarge = expandedOneU;
+
+        return true;
+    }
+
+    public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
+        return new NotificationClicker(intent, pkg, tag, id);
+    }
+
+    private class NotificationClicker implements View.OnClickListener {
+        private PendingIntent mIntent;
+        private String mPkg;
+        private String mTag;
+        private int mId;
+
+        NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
+            mIntent = intent;
+            mPkg = pkg;
+            mTag = tag;
+            mId = id;
+        }
+
+        public void onClick(View v) {
+            try {
+                // The intent we are sending is for the application, which
+                // won't have permission to immediately start an activity after
+                // the user switches to home.  We know it is safe to do at this
+                // point, so make sure new activity switches are now allowed.
+                ActivityManagerNative.getDefault().resumeAppSwitches();
+                // Also, notifications can be launched from the lock screen,
+                // so dismiss the lock screen when the activity starts.
+                ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+            } catch (RemoteException e) {
+            }
+
+            if (mIntent != null) {
+                int[] pos = new int[2];
+                v.getLocationOnScreen(pos);
+                Intent overlay = new Intent();
+                overlay.setSourceBounds(
+                        new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+                try {
+                    mIntent.send(mContext, 0, overlay);
+                } catch (PendingIntent.CanceledException e) {
+                    // the stack trace isn't very helpful here.  Just log the exception message.
+                    Slog.w(TAG, "Sending contentIntent failed: " + e);
+                }
+
+                KeyguardManager kgm =
+                    (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+                if (kgm != null) kgm.exitKeyguardSecurely(null);
+            }
+
+            try {
+                mBarService.onNotificationClick(mPkg, mTag, mId);
+            } catch (RemoteException ex) {
+                // system process is dead if we're here.
+            }
+
+            // close the shade if it was open
+            animateCollapse();
+            visibilityChanged(false);
+
+            // If this click was on the intruder alert, hide that instead
+//            mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+        }
+    }
+    /**
+     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+     * This was added last-minute and is inconsistent with the way the rest of the notifications
+     * are handled, because the notification isn't really cancelled.  The lights are just
+     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
+     * this is what he wants. (see bug 1131461)
+     */
+    protected void visibilityChanged(boolean visible) {
+        if (mPanelSlightlyVisible != visible) {
+            mPanelSlightlyVisible = visible;
+            try {
+                mBarService.onPanelRevealed();
+            } catch (RemoteException ex) {
+                // Won't fail unless the world has ended.
+            }
+        }
+    }
+
 }
index 6fbcd64..3ff85d9 100644 (file)
@@ -38,6 +38,7 @@ public class NotificationData {
         public View content; // takes the click events and sends the PendingIntent
         public View expanded; // the inflated RemoteViews
         public ImageView largeIcon;
+        public View expandedLarge;
         public Entry() {}
         public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
             this.key = key;
index 3f611fc..f45b3ad 100644 (file)
@@ -28,14 +28,11 @@ import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
-import android.os.Build;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
@@ -50,11 +47,9 @@ import android.view.Display;
 import android.view.Gravity;
 import android.view.IWindowManager;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.Window;
@@ -68,26 +63,25 @@ import android.widget.RemoteViews;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
 import com.android.systemui.recent.RecentTasksLoader;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.IntruderAlertView;
 import com.android.systemui.statusbar.policy.DateView;
+import com.android.systemui.statusbar.policy.IntruderAlertView;
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NotificationRowLayout;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
 public class PhoneStatusBar extends BaseStatusBar {
     static final String TAG = "PhoneStatusBar";
     public static final boolean DEBUG = false;
@@ -832,73 +826,6 @@ public class PhoneStatusBar extends BaseStatusBar {
         }
     }
 
-    private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
-        StatusBarNotification sbn = entry.notification;
-        // XXX: temporary: while testing big notifications, auto-expand all of them
-        final boolean big = (sbn.notification.bigContentView != null);
-        RemoteViews remoteViews = big ? sbn.notification.bigContentView
-                                      : sbn.notification.contentView;
-        if (remoteViews == null) {
-            return false;
-        }
-
-        // create the row view
-        LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
-        ViewGroup.LayoutParams lp = row.getLayoutParams();
-        if (big) {
-            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-        } else {
-            lp.height = mContext.getResources().getDimensionPixelSize(R.dimen.notification_height);
-        }
-        row.setLayoutParams(lp);
-        View vetoButton = updateNotificationVetoButton(row, sbn);
-        vetoButton.setContentDescription(mContext.getString(
-                R.string.accessibility_remove_notification));
-
-        // NB: the large icon is now handled entirely by the template
-
-        // bind the click event to the content area
-        ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
-        // XXX: update to allow controls within notification views
-        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-//        content.setOnFocusChangeListener(mFocusChangeListener);
-        PendingIntent contentIntent = sbn.notification.contentIntent;
-        if (contentIntent != null) {
-            final View.OnClickListener listener = new NotificationClicker(contentIntent,
-                    sbn.pkg, sbn.tag, sbn.id);
-            content.setOnClickListener(listener);
-        } else {
-            content.setOnClickListener(null);
-        }
-
-        View expanded = null;
-        Exception exception = null;
-        try {
-            expanded = remoteViews.apply(mContext, content);
-        }
-        catch (RuntimeException e) {
-            exception = e;
-        }
-        if (expanded == null) {
-            final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
-            Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
-            return false;
-        } else {
-            content.addView(expanded);
-            row.setDrawingCacheEnabled(true);
-        }
-
-        applyLegacyRowBackground(sbn, content);
-
-        entry.row = row;
-        entry.content = content;
-        entry.expanded = expanded;
-
-        return true;
-    }
-
     StatusBarNotification removeNotificationViews(IBinder key) {
         NotificationData.Entry entry = mNotificationData.remove(key);
         if (entry == null) {
@@ -1520,10 +1447,6 @@ public class PhoneStatusBar extends BaseStatusBar {
     @Override
     public void setHardKeyboardStatus(boolean available, boolean enabled) { }
 
-    public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
-        return new NotificationClicker(intent, pkg, tag, id);
-    }
-
     private class NotificationClicker implements View.OnClickListener {
         private PendingIntent mIntent;
         private String mPkg;
@@ -1538,12 +1461,6 @@ public class PhoneStatusBar extends BaseStatusBar {
         }
 
         public void onClick(View v) {
-            if (DEBUG) {
-                Slog.v(TAG, "NotificationClicker: intent=" + mIntent
-                        + " pkg=" + mPkg
-                        + " tag=" + mTag
-                        + " id=" + mId);
-            }
             try {
                 // The intent we are sending is for the application, which
                 // won't have permission to immediately start an activity after
@@ -1976,24 +1893,6 @@ public class PhoneStatusBar extends BaseStatusBar {
         }
     }
 
-    /**
-     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
-     * This was added last-minute and is inconsistent with the way the rest of the notifications
-     * are handled, because the notification isn't really cancelled.  The lights are just
-     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
-     * this is what he wants. (see bug 1131461)
-     */
-    void visibilityChanged(boolean visible) {
-        if (mPanelSlightlyVisible != visible) {
-            mPanelSlightlyVisible = visible;
-            try {
-                mBarService.onPanelRevealed();
-            } catch (RemoteException ex) {
-                // Won't fail unless the world has ended.
-            }
-        }
-    }
-
     void performDisableActions(int net) {
         int old = mDisabled;
         int diff = net ^ old;
index 9fd89ed..5369317 100644 (file)
@@ -34,12 +34,17 @@ import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 
 import java.util.HashMap;
 
-public class NotificationRowLayout extends LinearLayout implements SwipeHelper.Callback {
+public class NotificationRowLayout 
+        extends LinearLayout 
+        implements SwipeHelper.Callback, ExpandHelper.Callback 
+{
     private static final String TAG = "NotificationRowLayout";
     private static final boolean DEBUG = false;
     private static final boolean SLOW_ANIMATIONS = DEBUG;
@@ -55,6 +60,9 @@ public class NotificationRowLayout extends LinearLayout implements SwipeHelper.C
     HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
 
     private SwipeHelper mSwipeHelper;
+    private ExpandHelper mExpandHelper;
+
+    private Gefingerpoken mCurrentHelper;
 
     // Flag set during notification removal animation to avoid causing too much work until
     // animation is done
@@ -71,6 +79,8 @@ public class NotificationRowLayout extends LinearLayout implements SwipeHelper.C
         
         setOrientation(LinearLayout.VERTICAL);
 
+        setMotionEventSplittingEnabled(false);
+
         if (DEBUG) {
             setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
                 @Override
@@ -89,23 +99,61 @@ public class NotificationRowLayout extends LinearLayout implements SwipeHelper.C
         float densityScale = getResources().getDisplayMetrics().density;
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+        int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
+        int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+        mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight);
     }
 
     public void setAnimateBounds(boolean anim) {
         mAnimateBounds = anim;
     }
 
+    private void logLayoutTransition() {
+        Log.v(TAG, "layout " +
+              (getLayoutTransition().isChangingLayout() ? "is " : "is not ") +
+              "in transition and animations " +
+              (getLayoutTransition().isRunning() ? "are " : "are not ") +
+              "running.");
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
-        return mSwipeHelper.onInterceptTouchEvent(ev) ||
-            super.onInterceptTouchEvent(ev);
+        if (DEBUG) logLayoutTransition();
+
+        MotionEvent cancellation = MotionEvent.obtain(ev);
+        cancellation.setAction(MotionEvent.ACTION_CANCEL);
+
+        if (mSwipeHelper.onInterceptTouchEvent(ev)) {
+            if (DEBUG) Log.v(TAG, "will swipe");
+            mCurrentHelper = mSwipeHelper;
+            mExpandHelper.onInterceptTouchEvent(cancellation);
+            return true;
+        } else if (mExpandHelper.onInterceptTouchEvent(ev)) {
+            if (DEBUG) Log.v(TAG, "will stretch");
+            mCurrentHelper = mExpandHelper;
+            mSwipeHelper.onInterceptTouchEvent(cancellation);
+            return true;
+        } else {
+            mCurrentHelper = null;
+            if (super.onInterceptTouchEvent(ev)) {
+                if (DEBUG) Log.v(TAG, "intercepting ourselves");
+                mSwipeHelper.onInterceptTouchEvent(cancellation);
+                mExpandHelper.onInterceptTouchEvent(cancellation);
+                return true;
+            }
+        }
+        return false;
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        return mSwipeHelper.onTouchEvent(ev) ||
-            super.onTouchEvent(ev);
+        if (DEBUG) Log.v(TAG, "onTouchEvent()");
+        if (DEBUG) logLayoutTransition();
+        if (mCurrentHelper != null) {
+            return mCurrentHelper.onTouchEvent(ev);
+        }
+        return super.onTouchEvent(ev);
     }
 
     public boolean canChildBeDismissed(View v) {
@@ -130,10 +178,12 @@ public class NotificationRowLayout extends LinearLayout implements SwipeHelper.C
     }
 
     public View getChildAtPosition(MotionEvent ev) {
+        return getChildAtPosition(ev.getX(), ev.getY());
+    }
+    public View getChildAtPosition(float touchX, float touchY) {
         // find the view under the pointer, accounting for GONE views
         final int count = getChildCount();
         int y = 0;
-        int touchY = (int) ev.getY();
         int childIdx = 0;
         View slidingChild;
         for (; childIdx < count; childIdx++) {
@@ -188,6 +238,7 @@ public class NotificationRowLayout extends LinearLayout implements SwipeHelper.C
     @Override
     public void onDraw(android.graphics.Canvas c) {
         super.onDraw(c);
+        if (DEBUG) logLayoutTransition();
         if (DEBUG) {
             //Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
             //        + getMeasuredHeight() + "px");
index ba51108..8c1509b 100644 (file)
 
 package com.android.systemui.statusbar.tablet;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.app.ActivityManagerNative;
-import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -32,17 +27,13 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.inputmethodservice.InputMethodService;
-import android.os.Build;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
@@ -53,7 +44,6 @@ import android.view.Display;
 import android.view.Gravity;
 import android.view.IWindowManager;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.SoundEffectConstants;
 import android.view.VelocityTracker;
@@ -86,6 +76,10 @@ import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.Prefs;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
 public class TabletStatusBar extends BaseStatusBar implements
         InputMethodsPanel.OnHardKeyboardEnabledChangeListener,
         RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
@@ -187,8 +181,6 @@ public class TabletStatusBar extends BaseStatusBar implements
     private CompatModePanel mCompatModePanel;
 
     private int mSystemUiVisibility = 0;
-    // used to notify status bar for suppressing notification LED
-    private boolean mPanelSlightlyVisible;
 
     private int mNavigationIconHints = 0;
 
@@ -912,7 +904,7 @@ public class TabletStatusBar extends BaseStatusBar implements
                 // update the contentIntent
                 final PendingIntent contentIntent = notification.notification.contentIntent;
                 if (contentIntent != null) {
-                    final View.OnClickListener listener = new NotificationClicker(contentIntent,
+                    final View.OnClickListener listener = makeClicker(contentIntent,
                             notification.pkg, notification.tag, notification.id);
                     oldEntry.content.setOnClickListener(listener);
                 } else {
@@ -1105,24 +1097,6 @@ public class TabletStatusBar extends BaseStatusBar implements
         }
     }
 
-    /**
-     * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
-     * This was added last-minute and is inconsistent with the way the rest of the notifications
-     * are handled, because the notification isn't really cancelled.  The lights are just
-     * turned off.  If any other notifications happen, the lights will turn back on.  Steve says
-     * this is what he wants. (see bug 1131461)
-     */
-    void visibilityChanged(boolean visible) {
-        if (mPanelSlightlyVisible != visible) {
-            mPanelSlightlyVisible = visible;
-            try {
-                mBarService.onPanelRevealed();
-            } catch (RemoteException ex) {
-                // Won't fail unless the world has ended.
-            }
-        }
-    }
-
     @Override // CommandQueue
     public void setNavigationIconHints(int hints) {
         if (hints == mNavigationIconHints) return;
@@ -1364,70 +1338,6 @@ public class TabletStatusBar extends BaseStatusBar implements
         mHandler.sendEmptyMessage(msg);
     }
 
-    public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
-        return new NotificationClicker(intent, pkg, tag, id);
-    }
-
-    private class NotificationClicker implements View.OnClickListener {
-        private PendingIntent mIntent;
-        private String mPkg;
-        private String mTag;
-        private int mId;
-
-        NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
-            mIntent = intent;
-            mPkg = pkg;
-            mTag = tag;
-            mId = id;
-        }
-
-        public void onClick(View v) {
-            try {
-                // The intent we are sending is for the application, which
-                // won't have permission to immediately start an activity after
-                // the user switches to home.  We know it is safe to do at this
-                // point, so make sure new activity switches are now allowed.
-                ActivityManagerNative.getDefault().resumeAppSwitches();
-                // Also, notifications can be launched from the lock screen,
-                // so dismiss the lock screen when the activity starts.
-                ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
-            } catch (RemoteException e) {
-            }
-
-            if (mIntent != null) {
-                int[] pos = new int[2];
-                v.getLocationOnScreen(pos);
-                Intent overlay = new Intent();
-                overlay.setSourceBounds(
-                        new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
-                try {
-                    mIntent.send(mContext, 0, overlay);
-
-                } catch (PendingIntent.CanceledException e) {
-                    // the stack trace isn't very helpful here.  Just log the exception message.
-                    Slog.w(TAG, "Sending contentIntent failed: " + e);
-                }
-
-                KeyguardManager kgm =
-                    (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-                if (kgm != null) kgm.exitKeyguardSecurely(null);
-            }
-
-            try {
-                mBarService.onNotificationClick(mPkg, mTag, mId);
-            } catch (RemoteException ex) {
-                // system process is dead if we're here.
-            }
-
-            // close the shade if it was open
-            animateCollapse();
-            visibilityChanged(false);
-
-            // If this click was on the intruder alert, hide that instead
-//            mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
-        }
-    }
-
     StatusBarNotification removeNotificationViews(IBinder key) {
         NotificationData.Entry entry = mNotificationData.remove(key);
         if (entry == null) {
@@ -1801,7 +1711,8 @@ public class TabletStatusBar extends BaseStatusBar implements
         mNotificationPanel.setNotificationCount(N);
     }
 
-    void workAroundBadLayerDrawableOpacity(View v) {
+    @Override
+    protected void workAroundBadLayerDrawableOpacity(View v) {
         Drawable bgd = v.getBackground();
         if (!(bgd instanceof LayerDrawable)) return;
 
@@ -1811,64 +1722,6 @@ public class TabletStatusBar extends BaseStatusBar implements
         v.setBackgroundDrawable(d);
     }
 
-    private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
-        StatusBarNotification sbn = entry.notification;
-        RemoteViews remoteViews = sbn.notification.contentView;
-        if (remoteViews == null) {
-            return false;
-        }
-
-        // create the row view
-        LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
-        workAroundBadLayerDrawableOpacity(row);
-        View vetoButton = updateNotificationVetoButton(row, entry.notification);
-        vetoButton.setContentDescription(mContext.getString(
-                R.string.accessibility_remove_notification));
-
-        // NB: the large icon is now handled entirely by the template
-
-        // bind the click event to the content area
-        ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
-        // XXX: update to allow controls within notification views
-        content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-//        content.setOnFocusChangeListener(mFocusChangeListener);
-        PendingIntent contentIntent = sbn.notification.contentIntent;
-        if (contentIntent != null) {
-            final View.OnClickListener listener = new NotificationClicker(
-                    contentIntent, sbn.pkg, sbn.tag, sbn.id);
-            content.setOnClickListener(listener);
-        } else {
-            content.setOnClickListener(null);
-        }
-
-        View expanded = null;
-        Exception exception = null;
-        try {
-            expanded = remoteViews.apply(mContext, content);
-        }
-        catch (RuntimeException e) {
-            exception = e;
-        }
-        if (expanded == null) {
-            final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
-            Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
-            return false;
-        } else {
-            content.addView(expanded);
-            row.setDrawingCacheEnabled(true);
-        }
-
-        applyLegacyRowBackground(sbn, content);
-
-        entry.row = row;
-        entry.content = content;
-        entry.expanded = expanded;
-
-        return true;
-    }
-
     public void clearAll() {
         try {
             mBarService.onClearAllNotifications();