diff options
13 files changed, 821 insertions, 275 deletions
diff --git a/api/current.xml b/api/current.xml index 3ccb4e9..495d11d 100644 --- a/api/current.xml +++ b/api/current.xml @@ -32205,7 +32205,7 @@ type="android.app.Notification" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="icon" type="int"> @@ -32254,7 +32254,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > <parameter name="context" type="android.content.Context"> @@ -32524,6 +32524,16 @@ visibility="public" > </field> +<field name="largeIcon" + type="android.graphics.Bitmap" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ledARGB" type="int" transient="false" @@ -32574,19 +32584,18 @@ visibility="public" > </field> -<field name="tickerIcons" - type="android.graphics.Bitmap[]" +<field name="tickerText" + type="java.lang.CharSequence" transient="false" volatile="false" - value="null" static="false" final="false" deprecated="not deprecated" visibility="public" > </field> -<field name="tickerSubtitle" - type="java.lang.CharSequence" +<field name="tickerView" + type="android.widget.RemoteViews" transient="false" volatile="false" static="false" @@ -32595,18 +32604,19 @@ visibility="public" > </field> -<field name="tickerText" - type="java.lang.CharSequence" +<field name="vibrate" + type="long[]" transient="false" volatile="false" + value="null" static="false" final="false" deprecated="not deprecated" visibility="public" > </field> -<field name="tickerTitle" - type="java.lang.CharSequence" +<field name="when" + type="long" transient="false" volatile="false" static="false" @@ -32615,27 +32625,321 @@ visibility="public" > </field> -<field name="vibrate" - type="long[]" - transient="false" - volatile="false" - value="null" +</class> +<class name="Notification.Builder" + extends="java.lang.Object" + abstract="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="Notification.Builder" + type="android.app.Notification.Builder" static="false" final="false" deprecated="not deprecated" visibility="public" > -</field> -<field name="when" - type="long" - transient="false" - volatile="false" +<parameter name="context" type="android.content.Context"> +</parameter> +</constructor> +<method name="getNotification" + return="android.app.Notification" + abstract="false" + native="false" + synchronized="false" static="false" final="false" deprecated="not deprecated" visibility="public" > -</field> +</method> +<method name="setAutoCancel" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="autoCancel" type="boolean"> +</parameter> +</method> +<method name="setContent" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="views" type="android.widget.RemoteViews"> +</parameter> +</method> +<method name="setContentInfo" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="info" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="setContentIntent" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="intent" type="android.app.PendingIntent"> +</parameter> +</method> +<method name="setContentText" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="text" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="setContentTitle" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="title" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="setDefaults" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="defaults" type="int"> +</parameter> +</method> +<method name="setDeleteIntent" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="intent" type="android.app.PendingIntent"> +</parameter> +</method> +<method name="setFullScreenIntent" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="intent" type="android.app.PendingIntent"> +</parameter> +<parameter name="highPriority" type="boolean"> +</parameter> +</method> +<method name="setLargeIcon" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="icon" type="android.graphics.Bitmap"> +</parameter> +</method> +<method name="setLights" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="argb" type="int"> +</parameter> +<parameter name="onMs" type="int"> +</parameter> +<parameter name="offMs" type="int"> +</parameter> +</method> +<method name="setOngoing" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="ongoing" type="boolean"> +</parameter> +</method> +<method name="setOnlyAlertOnce" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="onlyAlertOnce" type="boolean"> +</parameter> +</method> +<method name="setSmallIcon" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="icon" type="int"> +</parameter> +</method> +<method name="setSmallIcon" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="icon" type="int"> +</parameter> +<parameter name="level" type="int"> +</parameter> +</method> +<method name="setSmallIconNumber" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="number" type="int"> +</parameter> +</method> +<method name="setSound" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="sound" type="android.net.Uri"> +</parameter> +<parameter name="streamType" type="int"> +</parameter> +</method> +<method name="setTicker" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="tickerText" type="java.lang.CharSequence"> +</parameter> +</method> +<method name="setTicker" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="tickerText" type="java.lang.CharSequence"> +</parameter> +<parameter name="views" type="android.widget.RemoteViews"> +</parameter> +</method> +<method name="setVibrate" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="pattern" type="long[]"> +</parameter> +</method> +<method name="setWhen" + return="android.app.Notification.Builder" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="when" type="long"> +</parameter> +</method> </class> <class name="NotificationManager" extends="java.lang.Object" diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index e602518..09319b9 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -29,6 +29,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.text.format.DateFormat; import android.text.format.DateUtils; +import android.util.Slog; import android.widget.RemoteViews; /** @@ -41,6 +42,8 @@ import android.widget.RemoteViews; */ public class Notification implements Parcelable { + private static final String TAG = "Notification"; + /** * Use all default values (where applicable). */ @@ -84,6 +87,15 @@ public class Notification implements Parcelable public int icon; /** + * If the icon in the status bar is to have more than one level, you can set this. Otherwise, + * leave it at its default value of 0. + * + * @see android.widget.ImageView#setImageLevel + * @see android.graphics.drawable#setLevel + */ + public int iconLevel; + + /** * The number of events that this notification represents. For example, in a new mail * notification, this could be the number of unread messages. This number is superimposed over * the icon in the status bar. If the number is 0 or negative, it is not shown in the status @@ -132,38 +144,15 @@ public class Notification implements Parcelable * text for when the text scrolls in and when it is displayed all at once * in conjunction with one or more icons. * - * @see #tickerTitle - * @see #tickerSubtitle - * @see #tickerIcons + * @see #tickerView */ public CharSequence tickerText; /** - * The title line for the ticker over a the fat status bar on xlarge devices. - * - * @see #tickerText - * @see #tickerSubtitle - * @see #tickerIcons + * The view to show as the ticker in the status bar when the notification + * is posted. */ - public CharSequence tickerTitle; - - /** - * The subtitle line for the ticker over a the fat status bar on xlarge devices. - * - * @see #tickerText - * @see #tickerTitle - * @see #tickerIcons - */ - public CharSequence tickerSubtitle; - - /** - * The icons to show to the left of the other ticker fields. - * - * @see #tickerText - * @see #tickerTitle - * @see #tickerSubtitle - */ - public Bitmap[] tickerIcons; + public RemoteViews tickerView; /** * The view that will represent this notification in the expanded status bar. @@ -171,13 +160,9 @@ public class Notification implements Parcelable public RemoteViews contentView; /** - * If the icon in the status bar is to have more than one level, you can set this. Otherwise, - * leave it at its default value of 0. - * - * @see android.widget.ImageView#setImageLevel - * @see android.graphics.drawable#setLevel + * The bitmap that may escape the bounds of the panel and bar. */ - public int iconLevel; + public Bitmap largeIcon; /** * The sound to play. @@ -327,6 +312,7 @@ public class Notification implements Parcelable /** * Constructs a Notification object with everything set to 0. + * You might want to consider using {@link Builder} instead. */ public Notification() { @@ -334,7 +320,6 @@ public class Notification implements Parcelable } /** - * @deprecated use {@link #Notification(int,CharSequence,long)} and {@link #setLatestEventInfo}. * @hide */ public Notification(Context context, int icon, CharSequence tickerText, long when, @@ -356,7 +341,10 @@ public class Notification implements Parcelable * activates. * @param when The time to show in the time field. In the System.currentTimeMillis * timebase. + * + * @deprecated Use {@link Builder} instead. */ + @Deprecated public Notification(int icon, CharSequence tickerText, long when) { this.icon = icon; @@ -384,19 +372,7 @@ public class Notification implements Parcelable tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); } if (parcel.readInt() != 0) { - tickerTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - } - if (parcel.readInt() != 0) { - tickerSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - } - final int tickerIconCount = parcel.readInt(); - if (tickerIconCount >= 0) { - tickerIcons = new Bitmap[tickerIconCount]; - for (int i=0; i<tickerIconCount; i++) { - if (parcel.readInt() != 0) { - tickerIcons[i] = Bitmap.CREATOR.createFromParcel(parcel); - } - } + tickerView = RemoteViews.CREATOR.createFromParcel(parcel); } if (parcel.readInt() != 0) { contentView = RemoteViews.CREATOR.createFromParcel(parcel); @@ -434,18 +410,8 @@ public class Notification implements Parcelable if (this.tickerText != null) { that.tickerText = this.tickerText.toString(); } - if (this.tickerTitle != null) { - that.tickerTitle = this.tickerTitle.toString(); - } - if (this.tickerSubtitle != null) { - that.tickerSubtitle = this.tickerSubtitle.toString(); - } - if (this.tickerIcons != null) { - final int N = this.tickerIcons.length; - that.tickerIcons = new Bitmap[N]; - for (int i=0; i<N; i++) { - that.tickerIcons[i] = Bitmap.createBitmap(this.tickerIcons[i]); - } + if (this.tickerView != null) { + that.tickerView = this.tickerView.clone(); } if (this.contentView != null) { that.contentView = this.contentView.clone(); @@ -503,32 +469,12 @@ public class Notification implements Parcelable } else { parcel.writeInt(0); } - if (tickerTitle != null) { + if (tickerView != null) { parcel.writeInt(1); - TextUtils.writeToParcel(tickerTitle, parcel, flags); + tickerView.writeToParcel(parcel, 0); } else { parcel.writeInt(0); } - if (tickerSubtitle != null) { - parcel.writeInt(1); - TextUtils.writeToParcel(tickerSubtitle, parcel, flags); - } else { - parcel.writeInt(0); - } - if (tickerIcons != null) { - final int N = tickerIcons.length; - parcel.writeInt(N); - for (int i=0; i<N; i++) { - if (tickerIcons[i] != null) { - parcel.writeInt(1); - tickerIcons[i].writeToParcel(parcel, flags); - } else { - parcel.writeInt(0); - } - } - } else { - parcel.writeInt(-1); - } if (contentView != null) { parcel.writeInt(1); contentView.writeToParcel(parcel, 0); @@ -591,7 +537,10 @@ public class Notification implements Parcelable * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires * that you take care of task management as described in * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>. + * + * @deprecated Use {@link Builder} instead. */ + @Deprecated public void setLatestEventInfo(Context context, CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) { RemoteViews contentView = new RemoteViews(context.getPackageName(), @@ -651,4 +600,214 @@ public class Notification implements Parcelable sb.append(")"); return sb.toString(); } + + public static class Builder { + private Context mContext; + + private long mWhen; + private int mSmallIcon; + private int mSmallIconLevel; + private int mSmallIconNumber; + private CharSequence mContentTitle; + private CharSequence mContentText; + private CharSequence mContentInfo; + private PendingIntent mContentIntent; + private RemoteViews mContentView; + private PendingIntent mDeleteIntent; + private PendingIntent mFullScreenIntent; + private CharSequence mTickerText; + private RemoteViews mTickerView; + private Bitmap mLargeIcon; + private Uri mSound; + private int mAudioStreamType; + private long[] mVibrate; + private int mLedArgb; + private int mLedOnMs; + private int mLedOffMs; + private int mDefaults; + private int mFlags; + + public Builder(Context context) { + mContext = context; + mWhen = System.currentTimeMillis(); + } + + public Builder setWhen(long when) { + mWhen = when; + return this; + } + + public Builder setSmallIcon(int icon) { + mSmallIcon = icon; + return this; + } + + public Builder setSmallIcon(int icon, int level) { + mSmallIcon = icon; + mSmallIconLevel = level; + return this; + } + + public Builder setSmallIconNumber(int number) { + mSmallIconNumber = number; + return this; + } + + public Builder setContentTitle(CharSequence title) { + mContentTitle = title; + return this; + } + + public Builder setContentText(CharSequence text) { + mContentText = text; + return this; + } + + public Builder setContentInfo(CharSequence info) { + mContentInfo = info; + return this; + } + + public Builder setContent(RemoteViews views) { + mContentView = views; + return this; + } + + public Builder setContentIntent(PendingIntent intent) { + mContentIntent = intent; + return this; + } + + public Builder setDeleteIntent(PendingIntent intent) { + mDeleteIntent = intent; + return this; + } + + public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { + mFullScreenIntent = intent; + setFlag(FLAG_HIGH_PRIORITY, highPriority); + return this; + } + + public Builder setTicker(CharSequence tickerText) { + mTickerText = tickerText; + return this; + } + + public Builder setTicker(CharSequence tickerText, RemoteViews views) { + mTickerText = tickerText; + mTickerView = views; + return this; + } + + public Builder setLargeIcon(Bitmap icon) { + mLargeIcon = icon; + return this; + } + + public Builder setSound(Uri sound, int streamType) { + mSound = sound; + mAudioStreamType = streamType; + return this; + } + + public Builder setVibrate(long[] pattern) { + mVibrate = pattern; + return this; + } + + public Builder setLights(int argb, int onMs, int offMs) { + mLedArgb = argb; + mLedOnMs = onMs; + mLedOffMs = offMs; + mFlags |= FLAG_SHOW_LIGHTS; + return this; + } + + public Builder setOngoing(boolean ongoing) { + setFlag(FLAG_ONGOING_EVENT, ongoing); + return this; + } + + public Builder setOnlyAlertOnce(boolean onlyAlertOnce) { + setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce); + return this; + } + + public Builder setAutoCancel(boolean autoCancel) { + setFlag(FLAG_ONLY_ALERT_ONCE, autoCancel); + return this; + } + + public Builder setDefaults(int defaults) { + mDefaults = defaults; + return this; + } + + private void setFlag(int mask, boolean value) { + if (value) { + mFlags |= mask; + } else { + mFlags &= ~mask; + } + } + + private RemoteViews makeContentView() { + if (mContentView != null) { + return mContentView; + } else { + RemoteViews contentView = new RemoteViews(mContext.getPackageName(), + com.android.internal.R.layout.status_bar_latest_event_content); + if (mSmallIcon != 0) { + contentView.setImageViewResource(com.android.internal.R.id.icon, mSmallIcon); + } + if (mContentTitle != null) { + contentView.setTextViewText(com.android.internal.R.id.title, mContentTitle); + } + if (mContentText != null) { + contentView.setTextViewText(com.android.internal.R.id.text, mContentText); + } + //TODO + //if (mContentInfo) { + // contentVeiw.setTextViewText(com.android.internal.R.id.info, mContentInfo); + //} + if (mWhen != 0) { + contentView.setLong(com.android.internal.R.id.time, "setTime", mWhen); + } + return contentView; + } + } + + private RemoteViews makeTickerView() { + if (mTickerView != null) { + return mTickerView; + } else { + return makeContentView(); + } + } + + public Notification getNotification() { + Notification n = new Notification(); + n.when = mWhen; + n.icon = mSmallIcon; + n.iconLevel = mSmallIconLevel; + n.number = mSmallIconNumber; + n.contentView = makeContentView(); + n.contentIntent = mContentIntent; + n.deleteIntent = mDeleteIntent; + n.fullScreenIntent = mFullScreenIntent; + n.tickerText = mTickerText; + n.tickerView = makeTickerView(); + n.largeIcon = mLargeIcon; + n.sound = mSound; + n.audioStreamType = mAudioStreamType; + n.vibrate = mVibrate; + n.ledARGB = mLedArgb; + n.ledOnMS = mLedOnMs; + n.ledOffMS = mLedOffMs; + n.defaults = mDefaults; + n.flags = mFlags; + return n; + } + } } diff --git a/packages/SystemUI/res/drawable/ticker_background.xml b/packages/SystemUI/res/drawable/ticker_background.xml new file mode 100644 index 0000000..7320fa0 --- /dev/null +++ b/packages/SystemUI/res/drawable/ticker_background.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2006 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. +--> + +<layer-list + xmlns:android="http://schemas.android.com/apk/res/android" + android:opacity="translucent" + > + <!-- the large icon extends 12dp beyond the edge of the status bar --> + <item + android:drawable="@drawable/notification_item_background_color" + android:top="12dp" + /> +</layer-list> + diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml index d11e6da..e9661a6 100644 --- a/packages/SystemUI/res/layout-xlarge/status_bar.xml +++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml @@ -242,7 +242,7 @@ <!-- ticker: transient incoming notification information --> <FrameLayout android:id="@+id/ticker" - android:layout_width="wrap_content" + android:layout_width="392dp" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_toRightOf="@+id/systemInfo" diff --git a/packages/SystemUI/res/layout-xlarge/ticker.xml b/packages/SystemUI/res/layout-xlarge/ticker.xml index c8d855f..1506848 100644 --- a/packages/SystemUI/res/layout-xlarge/ticker.xml +++ b/packages/SystemUI/res/layout-xlarge/ticker.xml @@ -18,36 +18,13 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" android:orientation="horizontal" android:background="#ff000000" > + <!-- + android:background="@drawable/ticker_background" + --> - <LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_gravity="center_vertical" - android:orientation="vertical" - android:paddingLeft="12dp" - > - - <TextView android:id="@+id/title" - xmlns:android="http://schemas.android.com/apk/res/android" - android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textStyle="bold" - android:maxLines="1" - /> - <TextView android:id="@+id/subtitle" - xmlns:android="http://schemas.android.com/apk/res/android" - android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:maxLines="1" - /> - </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 233ac45..b917324 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -464,7 +464,7 @@ public class TabletStatusBar extends StatusBar { boolean immersive = false; try { immersive = ActivityManagerNative.getDefault().isTopActivityImmersive(); - Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive")); + //Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive")); } catch (RemoteException ex) { } if (false && immersive) { @@ -603,9 +603,7 @@ public class TabletStatusBar extends StatusBar { } private boolean hasTicker(Notification n) { - return !TextUtils.isEmpty(n.tickerText) - || !TextUtils.isEmpty(n.tickerTitle) - || !TextUtils.isEmpty(n.tickerSubtitle); + return n.tickerView != null || !TextUtils.isEmpty(n.tickerText); } private void tick(StatusBarNotification n) { @@ -1005,7 +1003,6 @@ public class TabletStatusBar extends StatusBar { } catch (RemoteException ex) { // system process is dead if we're here. } - // animateCollapse(); } }); } else { @@ -1034,7 +1031,7 @@ public class TabletStatusBar extends StatusBar { exception = e; } if (expanded == null) { - String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id); + final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id); Slog.e(TAG, "couldn't inflate view for notification " + ident, exception); return false; } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java index 3c3139f..051c208 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java @@ -108,12 +108,16 @@ public class TabletTicker extends Handler { } // In with the new... - final StatusBarNotification next = dequeue(); - if (next != null) { + StatusBarNotification next = dequeue(); + while (next != null) { mCurrentNotification = next; mCurrentView = makeTickerView(next); - mParent.addView(mCurrentView); - sendEmptyMessageDelayed(MSG_ADVANCE, ADVANCE_DELAY); + if (mCurrentView != null) { + mParent.addView(mCurrentView); + sendEmptyMessageDelayed(MSG_ADVANCE, ADVANCE_DELAY); + break; + } + next = dequeue(); } } @@ -139,40 +143,36 @@ public class TabletTicker extends Handler { LayoutInflater inflater = (LayoutInflater)mContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE); - int layoutId; ViewGroup group; - if (n.tickerTitle != null || n.tickerSubtitle != null) { - group = (ViewGroup)inflater.inflate(R.layout.ticker, mParent, false); - if (n.tickerTitle != null) { - final TextView title = (TextView)group.findViewById(R.id.title); - title.setText(n.tickerTitle); + int layoutId; + if (n.tickerView != null) { + group = (ViewGroup)inflater.inflate(R.layout.ticker, null, false); + View expanded = null; + Exception exception = null; + try { + expanded = n.tickerView.apply(mContext, group); } - if (n.tickerSubtitle != null) { - final TextView subtitle = (TextView)group.findViewById(R.id.subtitle); - subtitle.setText(n.tickerSubtitle); + catch (RuntimeException e) { + exception = e; } - } else { + if (expanded == null) { + final String ident = notification.pkg + + "/0x" + Integer.toHexString(notification.id); + Slog.e(TAG, "couldn't inflate view for notification " + ident, exception); + return null; + } + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); + lp.gravity = Gravity.BOTTOM; + group.addView(expanded, lp); + } else if (n.tickerText != null) { group = (ViewGroup)inflater.inflate(R.layout.ticker_compat, mParent, false); TextView tv = (TextView)group.findViewById(R.id.text); tv.setText(n.tickerText); + } else { + throw new RuntimeException("tickerView==null && tickerText==null"); } - - // No more than 2 icons. - if (n.tickerIcons != null) { - int N = n.tickerIcons.length; - if (N > 2) { - N = 2; - } - for (int i=N-1; i>= 0; i--) { - Bitmap b = n.tickerIcons[i]; - if (b != null) { - ImageView iv = (ImageView)inflater.inflate(R.layout.ticker_icon, group, false); - iv.setImageBitmap(b); - group.addView(iv, 0); - } - } - } - + // TODO: Add Large icon return group; } } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 1081a20..6de7e6a 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -272,11 +272,13 @@ public class NotificationManagerService extends INotificationManager.Stub public void onNotificationClick(String pkg, String tag, int id) { cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL, - Notification.FLAG_FOREGROUND_SERVICE); + Notification.FLAG_FOREGROUND_SERVICE, true); } public void onNotificationClear(String pkg, String tag, int id) { - cancelNotification(pkg, tag, id, 0, 0); // maybe add some flags? + cancelNotification(pkg, tag, id, 0, + Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, + true); } public void onPanelRevealed() { @@ -312,7 +314,7 @@ public class NotificationManagerService extends INotificationManager.Stub int uid, int initialPid, String message) { Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); - cancelNotification(pkg, tag, id, 0, 0); + cancelNotification(pkg, tag, id, 0, 0, false); long ident = Binder.clearCallingIdentity(); try { ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, @@ -855,7 +857,20 @@ public class NotificationManagerService extends INotificationManager.Stub manager.sendAccessibilityEvent(event); } - private void cancelNotificationLocked(NotificationRecord r) { + private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) { + // tell the app + if (sendDelete) { + if (r.notification.deleteIntent != null) { + try { + r.notification.deleteIntent.send(); + } catch (PendingIntent.CanceledException ex) { + // do nothing - there's no relevant way to recover, and + // no reason to let this propagate + Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex); + } + } + } + // status bar if (r.notification.icon != 0) { long identity = Binder.clearCallingIdentity(); @@ -904,7 +919,7 @@ public class NotificationManagerService extends INotificationManager.Stub * and none of the {@code mustNotHaveFlags}. */ private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags, - int mustNotHaveFlags) { + int mustNotHaveFlags, boolean sendDelete) { EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags); synchronized (mNotificationList) { @@ -921,7 +936,7 @@ public class NotificationManagerService extends INotificationManager.Stub mNotificationList.remove(index); - cancelNotificationLocked(r); + cancelNotificationLocked(r, sendDelete); updateLightsLocked(); } } @@ -954,7 +969,7 @@ public class NotificationManagerService extends INotificationManager.Stub return true; } mNotificationList.remove(i); - cancelNotificationLocked(r); + cancelNotificationLocked(r, false); } if (canceledSomething) { updateLightsLocked(); @@ -973,7 +988,7 @@ public class NotificationManagerService extends INotificationManager.Stub // Don't allow client applications to cancel foreground service notis. cancelNotification(pkg, tag, id, 0, Binder.getCallingUid() == Process.SYSTEM_UID - ? 0 : Notification.FLAG_FOREGROUND_SERVICE); + ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false); } public void cancelAllNotifications(String pkg) { @@ -1009,17 +1024,8 @@ public class NotificationManagerService extends INotificationManager.Stub if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR)) == 0) { - if (r.notification.deleteIntent != null) { - try { - r.notification.deleteIntent.send(); - } catch (PendingIntent.CanceledException ex) { - // do nothing - there's no relevant way to recover, and - // no reason to let this propagate - Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex); - } - } mNotificationList.remove(i); - cancelNotificationLocked(r); + cancelNotificationLocked(r, true); } } diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml index c1ca618..b1734bb 100644 --- a/tests/StatusBar/AndroidManifest.xml +++ b/tests/StatusBar/AndroidManifest.xml @@ -21,6 +21,13 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <activity android:name="NotificationBuilderTest" android:label="_Notify Builder"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> <activity android:name="ToastTest" android:label="_Toasts"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -35,6 +42,8 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <activity android:name="ConfirmationActivity" android:theme="@android:style/Theme.Dialog"> + </activity> <activity android:name="TestAlertActivity" android:theme="@android:style/Theme.Dialog"> </activity> </application> diff --git a/tests/StatusBar/res/layout/confirmation_activity.xml b/tests/StatusBar/res/layout/confirmation_activity.xml new file mode 100644 index 0000000..50d1a49 --- /dev/null +++ b/tests/StatusBar/res/layout/confirmation_activity.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:gravity="center_horizontal" + android:orientation="vertical" + > + + <TextView android:id="@+id/text" + style="?android:attr/textAppearanceLarge" + android:padding="5dip" + android:singleLine="true" + android:ellipsize="end" + android:gravity="center" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <Button + android:id="@+id/ok" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="3" + android:onClick="dismiss" + android:text="Ok" /> + +</LinearLayout> diff --git a/tests/StatusBar/src/com/android/statusbartest/ConfirmationActivity.java b/tests/StatusBar/src/com/android/statusbartest/ConfirmationActivity.java new file mode 100644 index 0000000..5ce8f3f --- /dev/null +++ b/tests/StatusBar/src/com/android/statusbartest/ConfirmationActivity.java @@ -0,0 +1,32 @@ +package com.android.statusbartest; + +import android.app.Activity; +import android.view.View; +import android.widget.TextView; + +public class ConfirmationActivity extends Activity { + public static final String EXTRA_TITLE = "title"; + public static final String EXTRA_TEXT = "text"; + + @Override + public void onResume() { + super.onResume(); + setContentView(R.layout.confirmation_activity); + setTitle(getTextExtra(EXTRA_TITLE, "Title")); + ((TextView)findViewById(R.id.text)).setText(getTextExtra(EXTRA_TEXT, "text")); + findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + finish(); + } + }); + } + + private String getTextExtra(String extra, String def) { + final String text = getIntent().getStringExtra(extra); + if (text == null) { + return def; + } else { + return text; + } + } +} diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java new file mode 100644 index 0000000..b871197 --- /dev/null +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 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.statusbartest; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.ContentResolver; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.net.Uri; +import android.os.Environment; +import android.os.Vibrator; +import android.os.Handler; +import android.util.Log; +import android.net.Uri; +import android.os.SystemClock; +import android.widget.RemoteViews; +import android.os.PowerManager; + +public class NotificationBuilderTest extends TestActivity +{ + private final static String TAG = "NotificationTestList"; + + NotificationManager mNM; + + @Override + protected String tag() { + return TAG; + } + + @Override + protected Test[] tests() { + mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + + return mTests; + } + + private Test[] mTests = new Test[] { + new Test("Cancel (1)") { + public void run() { + mNM.cancel(1); + } + }, + + new Test("Basic Content (1)") { + public void run() { + int id = 1; + + Notification.Builder b = new Notification.Builder(NotificationBuilderTest.this); + + b.setWhen(System.currentTimeMillis()); + b.setSmallIcon(R.drawable.ic_statusbar_chat); + b.setContentTitle("Title"); + b.setContentText("text\nline2"); + b.setContentIntent(makeContentIntent(id)); + b.setDeleteIntent(makeDeleteIntent(id)); + + mNM.notify(id, b.getNotification()); + } + }, + }; + + private PendingIntent makeContentIntent(int id) { + Intent intent = new Intent(this, ConfirmationActivity.class); + intent.setData(Uri.fromParts("content", "//status_bar_test/content/" + id, null)); + intent.putExtra(ConfirmationActivity.EXTRA_TITLE, "Content intent"); + intent.putExtra(ConfirmationActivity.EXTRA_TEXT, "id: " + id); + return PendingIntent.getActivity(this, 0, intent, 0); + } + + private PendingIntent makeDeleteIntent(int id) { + Intent intent = new Intent(this, ConfirmationActivity.class); + intent.setData(Uri.fromParts("content", "//status_bar_test/delete/" + id, null)); + intent.putExtra(ConfirmationActivity.EXTRA_TITLE, "Delete intent"); + intent.putExtra(ConfirmationActivity.EXTRA_TEXT, "id: " + id); + return PendingIntent.getActivity(this, 0, intent, 0); + } +} + diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java index 2df97dc..0f0637f 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java @@ -135,95 +135,6 @@ public class NotificationTestList extends TestActivity } }, - new Test("Ticker 1 line & icon") { - public void run() { - Notification n = new Notification(R.drawable.icon1, "tick tick tick", - mActivityCreateTime); - n.setLatestEventInfo(NotificationTestList.this, "Persistent #1", - "This is a notification!!!", makeIntent()); - n.tickerIcons = new Bitmap[1]; - n.tickerIcons[0] = loadBitmap(R.drawable.icon3); - mNM.notify(1, n); - } - }, - - new Test("Ticker 2 lines") { - public void run() { - Notification n = new Notification(R.drawable.icon1, "tick tick tick\ntock tock", - mActivityCreateTime); - n.setLatestEventInfo(NotificationTestList.this, "Persistent #1", - "This is a notification!!!", makeIntent()); - mNM.notify(1, n); - } - }, - - new Test("Ticker title") { - public void run() { - Notification n = new Notification(R.drawable.icon1, null, - mActivityCreateTime); - n.setLatestEventInfo(NotificationTestList.this, "Persistent #1", - "This is a notification!!!", makeIntent()); - n.tickerTitle = "This is a title"; - mNM.notify(1, n); - } - }, - - new Test("Ticker subtitle") { - public void run() { - Notification n = new Notification(R.drawable.icon1, null, - mActivityCreateTime); - n.setLatestEventInfo(NotificationTestList.this, "Persistent #1", - "This is a notification!!!", makeIntent()); - n.tickerSubtitle = "and a subtitle"; - mNM.notify(1, n); - } - }, - - new Test("Ticker title & subtitle") { - public void run() { - Notification n = new Notification(R.drawable.icon1, null, - mActivityCreateTime); - n.setLatestEventInfo(NotificationTestList.this, "Persistent #1", - "This is a notification!!!", makeIntent()); - n.tickerTitle = "This is a title it is really really longggggg long long long long"; - n.tickerSubtitle = "and a subtitle it is really really longggggg long long long long long long long long long long long long long long long long"; - mNM.notify(1, n); - } - }, - - new Test("Ticker text, title & subtitle") { - public void run() { - Notification n = new Notification(R.drawable.icon1, "not visible", - mActivityCreateTime); - n.setLatestEventInfo(NotificationTestList.this, "Persistent #1", - "This is a notification!!!", makeIntent()); - n.tickerTitle = "This is a title"; - n.tickerSubtitle = "and a subtitle"; - mNM.notify(1, n); - } - }, - - new Test("Ticker title, subtitle & 2 icons") { - public void run() { - Notification n = new Notification(R.drawable.icon1, null, - mActivityCreateTime); - n.setLatestEventInfo(NotificationTestList.this, "Persistent #1", - "This is a notification!!!", makeIntent()); - n.tickerTitle = "This is a title"; - n.tickerSubtitle = "and a subtitle"; - - n.tickerIcons = new Bitmap[2]; - n.tickerIcons[0] = loadBitmap(R.drawable.icon3); - n.tickerIcons[1] = loadBitmap(R.drawable.app_gmail); - - mNM.notify(1, n); - /* - n.tickerIcons[0].recycle(); - n.tickerIcons[1].recycle(); - */ - } - }, - new Test("No view") { public void run() { Notification n = new Notification(R.drawable.icon1, "No view", |
