From 089de88fc2f08d284cf8031aa33cff06011a4162 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Mon, 12 Apr 2010 08:18:45 -0700 Subject: StatusBarService -> StatusBarManagerService Change-Id: I7efc245395bd91a656b30d420c9b080877162360 --- .../android/server/InputMethodManagerService.java | 6 +- .../android/server/NotificationManagerService.java | 20 +- services/java/com/android/server/SystemServer.java | 10 +- .../com/android/server/UiModeManagerService.java | 2 +- .../com/android/server/status/CloseDragHandle.java | 2 +- .../com/android/server/status/ExpandedView.java | 6 +- .../java/com/android/server/status/IconMerger.java | 2 +- .../server/status/NotificationViewList.java | 18 +- .../com/android/server/status/StatusBarIcon.java | 6 +- .../server/status/StatusBarManagerService.java | 1896 ++++++++++++++++++++ .../com/android/server/status/StatusBarPolicy.java | 6 +- .../android/server/status/StatusBarService.java | 1896 -------------------- .../com/android/server/status/StatusBarView.java | 4 +- .../com/android/server/status/TrackingView.java | 2 +- 14 files changed, 1938 insertions(+), 1938 deletions(-) create mode 100644 services/java/com/android/server/status/StatusBarManagerService.java delete mode 100644 services/java/com/android/server/status/StatusBarService.java (limited to 'services/java/com/android/server') diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 5bf66e4..47e8082 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -27,7 +27,7 @@ import com.android.internal.view.IInputMethodSession; import com.android.internal.view.InputBindResult; import com.android.server.status.IconData; -import com.android.server.status.StatusBarService; +import com.android.server.status.StatusBarManagerService; import org.xmlpull.v1.XmlPullParserException; @@ -110,7 +110,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final Context mContext; final Handler mHandler; final SettingsObserver mSettingsObserver; - final StatusBarService mStatusBar; + final StatusBarManagerService mStatusBar; final IBinder mInputMethodIcon; final IconData mInputMethodData; final IWindowManager mIWindowManager; @@ -447,7 +447,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - public InputMethodManagerService(Context context, StatusBarService statusBar) { + public InputMethodManagerService(Context context, StatusBarManagerService statusBar) { mContext = context; mHandler = new Handler(this); mIWindowManager = IWindowManager.Stub.asInterface( diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 73d17ea..bd93eb9 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -18,7 +18,7 @@ package com.android.server; import com.android.server.status.IconData; import com.android.server.status.NotificationData; -import com.android.server.status.StatusBarService; +import com.android.server.status.StatusBarManagerService; import android.app.ActivityManagerNative; import android.app.IActivityManager; @@ -86,7 +86,7 @@ class NotificationManagerService extends INotificationManager.Stub final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; - private StatusBarService mStatusBarService; + private StatusBarManagerService mStatusBar; private LightsService mLightsService; private LightsService.Light mBatteryLight; private LightsService.Light mNotificationLight; @@ -238,8 +238,8 @@ class NotificationManagerService extends INotificationManager.Stub } } - private StatusBarService.NotificationCallbacks mNotificationCallbacks - = new StatusBarService.NotificationCallbacks() { + private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks + = new StatusBarManagerService.NotificationCallbacks() { public void onSetDisabled(int status) { synchronized (mNotificationList) { @@ -405,7 +405,7 @@ class NotificationManagerService extends INotificationManager.Stub } } - NotificationManagerService(Context context, StatusBarService statusBar, + NotificationManagerService(Context context, StatusBarManagerService statusBar, LightsService lights) { super(); @@ -417,7 +417,7 @@ class NotificationManagerService extends INotificationManager.Stub mToastQueue = new ArrayList(); mHandler = new WorkerHandler(); - mStatusBarService = statusBar; + mStatusBar = statusBar; statusBar.setNotificationCallbacks(mNotificationCallbacks); mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY); @@ -734,7 +734,7 @@ class NotificationManagerService extends INotificationManager.Stub r.statusBarKey = old.statusBarKey; long identity = Binder.clearCallingIdentity(); try { - mStatusBarService.updateIcon(r.statusBarKey, icon, n); + mStatusBar.updateIcon(r.statusBarKey, icon, n); } finally { Binder.restoreCallingIdentity(identity); @@ -742,7 +742,7 @@ class NotificationManagerService extends INotificationManager.Stub } else { long identity = Binder.clearCallingIdentity(); try { - r.statusBarKey = mStatusBarService.addIcon(icon, n); + r.statusBarKey = mStatusBar.addIcon(icon, n); mAttentionLight.pulse(); } finally { @@ -756,7 +756,7 @@ class NotificationManagerService extends INotificationManager.Stub if (old != null && old.statusBarKey != null) { long identity = Binder.clearCallingIdentity(); try { - mStatusBarService.removeIcon(old.statusBarKey); + mStatusBar.removeIcon(old.statusBarKey); } finally { Binder.restoreCallingIdentity(identity); @@ -864,7 +864,7 @@ class NotificationManagerService extends INotificationManager.Stub if (r.notification.icon != 0) { long identity = Binder.clearCallingIdentity(); try { - mStatusBarService.removeIcon(r.statusBarKey); + mStatusBar.removeIcon(r.statusBarKey); } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 65becb6..d7948ec 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -17,7 +17,7 @@ package com.android.server; import com.android.server.am.ActivityManagerService; -import com.android.server.status.StatusBarService; +import com.android.server.status.StatusBarManagerService; import com.android.internal.os.BinderInternal; import com.android.internal.os.SamplingProfilerIntegration; @@ -206,7 +206,7 @@ class ServerThread extends Thread { } DevicePolicyManagerService devicePolicy = null; - StatusBarService statusBar = null; + StatusBarManagerService statusBar = null; InputMethodManagerService imm = null; AppWidgetService appWidget = null; NotificationManagerService notification = null; @@ -224,10 +224,10 @@ class ServerThread extends Thread { try { Slog.i(TAG, "Status Bar"); - statusBar = new StatusBarService(context); + statusBar = new StatusBarManagerService(context); ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar); } catch (Throwable e) { - Slog.e(TAG, "Failure starting StatusBarService", e); + Slog.e(TAG, "Failure starting StatusBarManagerService", e); } try { @@ -464,7 +464,7 @@ class ServerThread extends Thread { } // These are needed to propagate to the runnable below. - final StatusBarService statusBarF = statusBar; + final StatusBarManagerService statusBarF = statusBar; final BatteryService batteryF = battery; final ConnectivityService connectivityF = connectivity; final DockObserver dockF = dock; diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index 3606629..9493161 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -545,7 +545,7 @@ class UiModeManagerService extends IUiModeManager.Stub { mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); } - // Fear not: StatusBarService manages a list of requests to disable + // Fear not: StatusBarManagerService manages a list of requests to disable // features of the status bar; these are ORed together to form the // active disabled list. So if (for example) the device is locked and // the status bar should be totally disabled, the calls below will diff --git a/services/java/com/android/server/status/CloseDragHandle.java b/services/java/com/android/server/status/CloseDragHandle.java index ad1ac4d..d11ab10 100644 --- a/services/java/com/android/server/status/CloseDragHandle.java +++ b/services/java/com/android/server/status/CloseDragHandle.java @@ -23,7 +23,7 @@ import android.widget.LinearLayout; public class CloseDragHandle extends LinearLayout { - StatusBarService mService; + StatusBarManagerService mService; public CloseDragHandle(Context context, AttributeSet attrs) { super(context, attrs); diff --git a/services/java/com/android/server/status/ExpandedView.java b/services/java/com/android/server/status/ExpandedView.java index cb37f90..af85bce 100644 --- a/services/java/com/android/server/status/ExpandedView.java +++ b/services/java/com/android/server/status/ExpandedView.java @@ -27,7 +27,7 @@ import android.util.Slog; public class ExpandedView extends LinearLayout { - StatusBarService mService; + StatusBarManagerService mService; int mPrevHeight = -1; public ExpandedView(Context context, AttributeSet attrs) { @@ -50,9 +50,9 @@ public class ExpandedView extends LinearLayout { super.onLayout(changed, left, top, right, bottom); int height = bottom - top; if (height != mPrevHeight) { - //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight + " new=" + height); + //Slog.d(StatusBarManagerService.TAG, "height changed old=" + mPrevHeight + " new=" + height); mPrevHeight = height; - mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE); + mService.updateExpandedViewPos(StatusBarManagerService.EXPANDED_LEAVE_ALONE); } } } diff --git a/services/java/com/android/server/status/IconMerger.java b/services/java/com/android/server/status/IconMerger.java index aa702ae..86f1e34 100644 --- a/services/java/com/android/server/status/IconMerger.java +++ b/services/java/com/android/server/status/IconMerger.java @@ -24,7 +24,7 @@ import android.widget.LinearLayout; public class IconMerger extends LinearLayout { - StatusBarService service; + StatusBarManagerService service; StatusBarIcon moreIcon; public IconMerger(Context context, AttributeSet attrs) { diff --git a/services/java/com/android/server/status/NotificationViewList.java b/services/java/com/android/server/status/NotificationViewList.java index 1bb56a7..a24e239 100644 --- a/services/java/com/android/server/status/NotificationViewList.java +++ b/services/java/com/android/server/status/NotificationViewList.java @@ -135,8 +135,8 @@ class NotificationViewList { index++; } } - Slog.e(StatusBarService.TAG, "Couldn't find notification in NotificationViewList."); - Slog.e(StatusBarService.TAG, "notification=" + notification); + Slog.e(StatusBarManagerService.TAG, "Couldn't find notification in NotificationViewList."); + Slog.e(StatusBarManagerService.TAG, "notification=" + notification); dump(notification); return 0; } @@ -173,8 +173,8 @@ class NotificationViewList { } void add(StatusBarNotification notification) { - if (StatusBarService.SPEW) { - Slog.d(StatusBarService.TAG, "before add NotificationViewList" + if (StatusBarManagerService.SPEW) { + Slog.d(StatusBarManagerService.TAG, "before add NotificationViewList" + " notification.data.ongoingEvent=" + notification.data.ongoingEvent); dump(notification); } @@ -192,14 +192,14 @@ class NotificationViewList { } list.add(index, notification); - if (StatusBarService.SPEW) { - Slog.d(StatusBarService.TAG, "after add NotificationViewList index=" + index); + if (StatusBarManagerService.SPEW) { + Slog.d(StatusBarManagerService.TAG, "after add NotificationViewList index=" + index); dump(notification); } } void dump(StatusBarNotification notification) { - if (StatusBarService.SPEW) { + if (StatusBarManagerService.SPEW) { boolean showTime = false; String s = ""; for (int i=0; i") + ": " + Integer.toHexString(data.iconId)); } diff --git a/services/java/com/android/server/status/StatusBarManagerService.java b/services/java/com/android/server/status/StatusBarManagerService.java new file mode 100644 index 0000000..18cb1ed --- /dev/null +++ b/services/java/com/android/server/status/StatusBarManagerService.java @@ -0,0 +1,1896 @@ +/* + * Copyright (C) 2007 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.server.status; + +import com.android.internal.R; +import com.android.internal.util.CharSequences; + +import android.app.ActivityManagerNative; +import android.app.Dialog; +import android.app.IStatusBar; +import android.app.IStatusBarService; +import android.app.PendingIntent; +import android.app.StatusBarManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.Binder; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.provider.Telephony; +import android.util.Slog; +import android.view.Display; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.WindowManagerImpl; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.LinearLayout; +import android.widget.RemoteViews; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.FrameLayout; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Set; + + +/** + * The public (ok, semi-public) service for the status bar. + *

+ * This interesting thing to note about this class is that most of the methods that + * are called from other classes just post a message, and everything else is batched + * and coalesced into a series of calls to methods that all start with "perform." + * There are two reasons for this. The first is that some of the methods (activate/deactivate) + * are on IStatusBarService, so they're called from the thread pool and they need to make their + * way onto the UI thread. The second is that the message queue is stopped while animations + * are happening in order to make for smoother transitions. + *

+ * Each icon is either an icon or an icon and a notification. They're treated mostly + * separately throughout the code, although they both use the same key, which is assigned + * when they are created. + */ +public class StatusBarManagerService extends IStatusBarService.Stub +{ + static final String TAG = "StatusBar"; + static final boolean SPEW = false; + + public static final String ACTION_STATUSBAR_START + = "com.android.internal.policy.statusbar.START"; + + static final int EXPANDED_LEAVE_ALONE = -10000; + static final int EXPANDED_FULL_OPEN = -10001; + + private static final int MSG_ANIMATE = 1000; + private static final int MSG_ANIMATE_REVEAL = 1001; + + private static final int OP_ADD_ICON = 1; + private static final int OP_UPDATE_ICON = 2; + private static final int OP_REMOVE_ICON = 3; + private static final int OP_SET_VISIBLE = 4; + private static final int OP_EXPAND = 5; + private static final int OP_TOGGLE = 6; + private static final int OP_DISABLE = 7; + private class PendingOp { + IBinder key; + int code; + IconData iconData; + NotificationData notificationData; + boolean visible; + int integer; + } + + private class DisableRecord implements IBinder.DeathRecipient { + String pkg; + int what; + IBinder token; + + public void binderDied() { + Slog.i(TAG, "binder died for pkg=" + pkg); + disable(0, token, pkg); + token.unlinkToDeath(this, 0); + } + } + + public interface NotificationCallbacks { + void onSetDisabled(int status); + void onClearAll(); + void onNotificationClick(String pkg, String tag, int id); + void onPanelRevealed(); + } + + private class ExpandedDialog extends Dialog { + ExpandedDialog(Context context) { + super(context, com.android.internal.R.style.Theme_Light_NoTitleBar); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + boolean down = event.getAction() == KeyEvent.ACTION_DOWN; + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_BACK: + if (!down) { + StatusBarManagerService.this.deactivate(); + } + return true; + } + return super.dispatchKeyEvent(event); + } + } + + final Context mContext; + final Display mDisplay; + StatusBarView mStatusBarView; + int mPixelFormat; + H mHandler = new H(); + Object mQueueLock = new Object(); + ArrayList mQueue = new ArrayList(); + NotificationCallbacks mNotificationCallbacks; + + // All accesses to mIconMap and mNotificationData are syncronized on those objects, + // but this is only so dump() can work correctly. Modifying these outside of the UI + // thread will not work, there are places in the code that unlock and reaquire between + // reads and require them to not be modified. + + // icons + HashMap mIconMap = new HashMap(); + ArrayList mIconList = new ArrayList(); + String[] mRightIconSlots; + StatusBarIcon[] mRightIcons; + LinearLayout mIcons; + IconMerger mNotificationIcons; + LinearLayout mStatusIcons; + StatusBarIcon mMoreIcon; + private UninstallReceiver mUninstallReceiver; + + // expanded notifications + NotificationViewList mNotificationData = new NotificationViewList(); + Dialog mExpandedDialog; + ExpandedView mExpandedView; + WindowManager.LayoutParams mExpandedParams; + ScrollView mScrollView; + View mNotificationLinearLayout; + TextView mOngoingTitle; + LinearLayout mOngoingItems; + TextView mLatestTitle; + LinearLayout mLatestItems; + TextView mNoNotificationsTitle; + TextView mSpnLabel; + TextView mPlmnLabel; + TextView mClearButton; + View mExpandedContents; + CloseDragHandle mCloseView; + int[] mPositionTmp = new int[2]; + boolean mExpanded; + boolean mExpandedVisible; + + // the date view + DateView mDateView; + + // the tracker view + TrackingView mTrackingView; + WindowManager.LayoutParams mTrackingParams; + int mTrackingPosition; // the position of the top of the tracking view. + + // ticker + private Ticker mTicker; + private View mTickerView; + private boolean mTicking; + + // Tracking finger for opening/closing. + int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore + boolean mTracking; + VelocityTracker mVelocityTracker; + + static final int ANIM_FRAME_DURATION = (1000/60); + + boolean mAnimating; + long mCurAnimationTime; + float mDisplayHeight; + float mAnimY; + float mAnimVel; + float mAnimAccel; + long mAnimLastTime; + boolean mAnimatingReveal = false; + int mViewDelta; + int[] mAbsPos = new int[2]; + + // for disabling the status bar + ArrayList mDisableRecords = new ArrayList(); + int mDisabled = 0; + + /** + * Construct the service, add the status bar view to the window manager + */ + public StatusBarManagerService(Context context) { + mContext = context; + mDisplay = ((WindowManager)context.getSystemService( + Context.WINDOW_SERVICE)).getDefaultDisplay(); + makeStatusBarView(context); + mUninstallReceiver = new UninstallReceiver(); + } + + public void setNotificationCallbacks(NotificationCallbacks listener) { + mNotificationCallbacks = listener; + } + + // ================================================================================ + // Constructing the view + // ================================================================================ + private void makeStatusBarView(Context context) { + Resources res = context.getResources(); + mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order); + mRightIcons = new StatusBarIcon[mRightIconSlots.length]; + + ExpandedView expanded = (ExpandedView)View.inflate(context, + com.android.internal.R.layout.status_bar_expanded, null); + expanded.mService = this; + StatusBarView sb = (StatusBarView)View.inflate(context, + com.android.internal.R.layout.status_bar, null); + sb.mService = this; + + // figure out which pixel-format to use for the status bar. + mPixelFormat = PixelFormat.TRANSLUCENT; + Drawable bg = sb.getBackground(); + if (bg != null) { + mPixelFormat = bg.getOpacity(); + } + + mStatusBarView = sb; + mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons); + mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons); + mNotificationIcons.service = this; + mIcons = (LinearLayout)sb.findViewById(R.id.icons); + mTickerView = sb.findViewById(R.id.ticker); + mDateView = (DateView)sb.findViewById(R.id.date); + + mExpandedDialog = new ExpandedDialog(context); + mExpandedView = expanded; + mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout); + mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle); + mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems); + mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle); + mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems); + mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle); + mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button); + mClearButton.setOnClickListener(mClearButtonListener); + mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel); + mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel); + mScrollView = (ScrollView)expanded.findViewById(R.id.scroll); + mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout); + + mOngoingTitle.setVisibility(View.GONE); + mLatestTitle.setVisibility(View.GONE); + + mTicker = new MyTicker(context, sb); + + TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText); + tickerView.mTicker = mTicker; + + mTrackingView = (TrackingView)View.inflate(context, + com.android.internal.R.layout.status_bar_tracking, null); + mTrackingView.mService = this; + mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close); + mCloseView.mService = this; + + mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); + + // add the more icon for the notifications + IconData moreData = IconData.makeIcon(null, context.getPackageName(), + R.drawable.stat_notify_more, 0, 42); + mMoreIcon = new StatusBarIcon(context, moreData, mNotificationIcons); + mMoreIcon.view.setId(R.drawable.stat_notify_more); + mNotificationIcons.moreIcon = mMoreIcon; + mNotificationIcons.addView(mMoreIcon.view); + + // set the inital view visibility + setAreThereNotifications(); + mDateView.setVisibility(View.INVISIBLE); + + // before we register for broadcasts + mPlmnLabel.setText(R.string.lockscreen_carrier_default); + mPlmnLabel.setVisibility(View.VISIBLE); + mSpnLabel.setText(""); + mSpnLabel.setVisibility(View.GONE); + + // receive broadcasts + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION); + context.registerReceiver(mBroadcastReceiver, filter); + } + + public void systemReady() { + final StatusBarView view = mStatusBarView; + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + view.getContext().getResources().getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_height), + WindowManager.LayoutParams.TYPE_STATUS_BAR, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| + WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING, + mPixelFormat); + lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; + lp.setTitle("StatusBar"); + lp.windowAnimations = R.style.Animation_StatusBar; + + //WindowManagerImpl.getDefault().addView(view, lp); + } + + public void systemReady2() { + // Start the status bar app + Intent intent = new Intent(ACTION_STATUSBAR_START); + mContext.sendBroadcast(intent /** permission **/); + } + + // ================================================================================ + // From IStatusBarService + // ================================================================================ + public void activate() { + enforceExpandStatusBar(); + addPendingOp(OP_EXPAND, null, true); + } + + public void deactivate() { + enforceExpandStatusBar(); + addPendingOp(OP_EXPAND, null, false); + } + + public void toggle() { + enforceExpandStatusBar(); + addPendingOp(OP_TOGGLE, null, false); + } + + public void disable(int what, IBinder token, String pkg) { + enforceStatusBar(); + synchronized (mNotificationCallbacks) { + // This is a little gross, but I think it's safe as long as nobody else + // synchronizes on mNotificationCallbacks. It's important that the the callback + // and the pending op get done in the correct order and not interleaved with + // other calls, otherwise they'll get out of sync. + int net; + synchronized (mDisableRecords) { + manageDisableListLocked(what, token, pkg); + net = gatherDisableActionsLocked(); + mNotificationCallbacks.onSetDisabled(net); + } + addPendingOp(OP_DISABLE, net); + } + } + + public IBinder addIcon(String slot, String iconPackage, int iconId, int iconLevel) { + enforceStatusBar(); + return addIcon(IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null); + } + + public void updateIcon(IBinder key, + String slot, String iconPackage, int iconId, int iconLevel) { + enforceStatusBar(); + updateIcon(key, IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null); + } + + public void removeIcon(IBinder key) { + enforceStatusBar(); + addPendingOp(OP_REMOVE_ICON, key, null, null, -1); + } + + private void enforceStatusBar() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.STATUS_BAR, + "StatusBarManagerService"); + } + + private void enforceExpandStatusBar() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.EXPAND_STATUS_BAR, + "StatusBarManagerService"); + } + + public void registerStatusBar(IStatusBar bar) { + Slog.d(TAG, "registerStatusBar bar=" + bar); + } + + + // ================================================================================ + // Can be called from any thread + // ================================================================================ + public IBinder addIcon(IconData data, NotificationData n) { + int slot; + // assert early-on if they using a slot that doesn't exist. + if (data != null && n == null) { + slot = getRightIconIndex(data.slot); + if (slot < 0) { + throw new SecurityException("invalid status bar icon slot: " + + (data.slot != null ? "'" + data.slot + "'" : "null")); + } + } else { + slot = -1; + } + IBinder key = new Binder(); + addPendingOp(OP_ADD_ICON, key, data, n, -1); + return key; + } + + public void updateIcon(IBinder key, IconData data, NotificationData n) { + addPendingOp(OP_UPDATE_ICON, key, data, n, -1); + } + + public void setIconVisibility(IBinder key, boolean visible) { + addPendingOp(OP_SET_VISIBLE, key, visible); + } + + private void addPendingOp(int code, IBinder key, IconData data, NotificationData n, int i) { + synchronized (mQueueLock) { + PendingOp op = new PendingOp(); + op.key = key; + op.code = code; + op.iconData = data == null ? null : data.clone(); + op.notificationData = n; + op.integer = i; + mQueue.add(op); + if (mQueue.size() == 1) { + mHandler.sendEmptyMessage(2); + } + } + } + + private void addPendingOp(int code, IBinder key, boolean visible) { + synchronized (mQueueLock) { + PendingOp op = new PendingOp(); + op.key = key; + op.code = code; + op.visible = visible; + mQueue.add(op); + if (mQueue.size() == 1) { + mHandler.sendEmptyMessage(1); + } + } + } + + private void addPendingOp(int code, int integer) { + synchronized (mQueueLock) { + PendingOp op = new PendingOp(); + op.code = code; + op.integer = integer; + mQueue.add(op); + if (mQueue.size() == 1) { + mHandler.sendEmptyMessage(1); + } + } + } + + // lock on mDisableRecords + void manageDisableListLocked(int what, IBinder token, String pkg) { + if (SPEW) { + Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what) + + " pkg=" + pkg); + } + // update the list + synchronized (mDisableRecords) { + final int N = mDisableRecords.size(); + DisableRecord tok = null; + int i; + for (i=0; i queue; + synchronized (mQueueLock) { + queue = mQueue; + mQueue = new ArrayList(); + } + + boolean wasExpanded = mExpanded; + + // for each one in the queue, find all of the ones with the same key + // and collapse that down into a final op and/or call to setVisibility, etc + boolean expand = wasExpanded; + boolean doExpand = false; + boolean doDisable = false; + int disableWhat = 0; + int N = queue.size(); + while (N > 0) { + PendingOp op = queue.get(0); + boolean doOp = false; + boolean visible = false; + boolean doVisibility = false; + if (op.code == OP_SET_VISIBLE) { + doVisibility = true; + visible = op.visible; + } + else if (op.code == OP_EXPAND) { + doExpand = true; + expand = op.visible; + } + else if (op.code == OP_TOGGLE) { + doExpand = true; + expand = !expand; + } + else { + doOp = true; + } + + if (alwaysHandle(op.code)) { + // coalesce these + for (int i=1; i s + final float y = mAnimY; + final float v = mAnimVel; // px/s + final float a = mAnimAccel; // px/s/s + mAnimY = y + (v*t) + (0.5f*a*t*t); // px + mAnimVel = v + (a*t); // px/s + mAnimLastTime = now; // ms + //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY + // + " mAnimAccel=" + mAnimAccel); + } + + void doRevealAnimation() { + final int h = mCloseView.getHeight() + mStatusBarView.getHeight(); + if (mAnimatingReveal && mAnimating && mAnimY < h) { + incrementAnim(); + if (mAnimY >= h) { + mAnimY = h; + updateExpandedViewPos((int)mAnimY); + } else { + updateExpandedViewPos((int)mAnimY); + mCurAnimationTime += ANIM_FRAME_DURATION; + mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), + mCurAnimationTime); + } + } + } + + void prepareTracking(int y, boolean opening) { + mTracking = true; + mVelocityTracker = VelocityTracker.obtain(); + if (opening) { + mAnimAccel = 2000.0f; + mAnimVel = 200; + mAnimY = mStatusBarView.getHeight(); + updateExpandedViewPos((int)mAnimY); + mAnimating = true; + mAnimatingReveal = true; + mHandler.removeMessages(MSG_ANIMATE); + mHandler.removeMessages(MSG_ANIMATE_REVEAL); + long now = SystemClock.uptimeMillis(); + mAnimLastTime = now; + mCurAnimationTime = now + ANIM_FRAME_DURATION; + mAnimating = true; + mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), + mCurAnimationTime); + makeExpandedVisible(); + } else { + // it's open, close it? + if (mAnimating) { + mAnimating = false; + mHandler.removeMessages(MSG_ANIMATE); + } + updateExpandedViewPos(y + mViewDelta); + } + } + + void performFling(int y, float vel, boolean always) { + mAnimatingReveal = false; + mDisplayHeight = mDisplay.getHeight(); + + mAnimY = y; + mAnimVel = vel; + + //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel); + + if (mExpanded) { + if (!always && ( + vel > 200.0f + || (y > (mDisplayHeight-25) && vel > -200.0f))) { + // We are expanded, but they didn't move sufficiently to cause + // us to retract. Animate back to the expanded position. + mAnimAccel = 2000.0f; + if (vel < 0) { + mAnimVel = 0; + } + } + else { + // We are expanded and are now going to animate away. + mAnimAccel = -2000.0f; + if (vel > 0) { + mAnimVel = 0; + } + } + } else { + if (always || ( + vel > 200.0f + || (y > (mDisplayHeight/2) && vel > -200.0f))) { + // We are collapsed, and they moved enough to allow us to + // expand. Animate in the notifications. + mAnimAccel = 2000.0f; + if (vel < 0) { + mAnimVel = 0; + } + } + else { + // We are collapsed, but they didn't move sufficiently to cause + // us to retract. Animate back to the collapsed position. + mAnimAccel = -2000.0f; + if (vel > 0) { + mAnimVel = 0; + } + } + } + //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel + // + " mAnimAccel=" + mAnimAccel); + + long now = SystemClock.uptimeMillis(); + mAnimLastTime = now; + mCurAnimationTime = now + ANIM_FRAME_DURATION; + mAnimating = true; + mHandler.removeMessages(MSG_ANIMATE); + mHandler.removeMessages(MSG_ANIMATE_REVEAL); + mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime); + stopTracking(); + } + + boolean interceptTouchEvent(MotionEvent event) { + if (SPEW) { + Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" + + mDisabled); + } + + if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { + return false; + } + + final int statusBarSize = mStatusBarView.getHeight(); + final int hitSize = statusBarSize*2; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + final int y = (int)event.getRawY(); + + if (!mExpanded) { + mViewDelta = statusBarSize - y; + } else { + mTrackingView.getLocationOnScreen(mAbsPos); + mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y; + } + if ((!mExpanded && y < hitSize) || + (mExpanded && y > (mDisplay.getHeight()-hitSize))) { + + // We drop events at the edge of the screen to make the windowshade come + // down by accident less, especially when pushing open a device with a keyboard + // that rotates (like g1 and droid) + int x = (int)event.getRawX(); + final int edgeBorder = mEdgeBorder; + if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) { + prepareTracking(y, !mExpanded);// opening if we're not already fully visible + mVelocityTracker.addMovement(event); + } + } + } else if (mTracking) { + mVelocityTracker.addMovement(event); + final int minY = statusBarSize + mCloseView.getHeight(); + if (event.getAction() == MotionEvent.ACTION_MOVE) { + int y = (int)event.getRawY(); + if (mAnimatingReveal && y < minY) { + // nothing + } else { + mAnimatingReveal = false; + updateExpandedViewPos(y + mViewDelta); + } + } else if (event.getAction() == MotionEvent.ACTION_UP) { + mVelocityTracker.computeCurrentVelocity(1000); + + float yVel = mVelocityTracker.getYVelocity(); + boolean negative = yVel < 0; + + float xVel = mVelocityTracker.getXVelocity(); + if (xVel < 0) { + xVel = -xVel; + } + if (xVel > 150.0f) { + xVel = 150.0f; // limit how much we care about the x axis + } + + float vel = (float)Math.hypot(yVel, xVel); + if (negative) { + vel = -vel; + } + + performFling((int)event.getRawY(), vel, false); + } + + } + return false; + } + + private class Launcher implements View.OnClickListener { + private PendingIntent mIntent; + private String mPkg; + private String mTag; + private int mId; + + Launcher(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(); + } catch (RemoteException e) { + } + 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); + mNotificationCallbacks.onNotificationClick(mPkg, mTag, mId); + } catch (PendingIntent.CanceledException e) { + // the stack trace isn't very helpful here. Just log the exception message. + Slog.w(TAG, "Sending contentIntent failed: " + e); + } + deactivate(); + } + } + + private class MyTicker extends Ticker { + MyTicker(Context context, StatusBarView sb) { + super(context, sb); + } + + @Override + void tickerStarting() { + mTicking = true; + mIcons.setVisibility(View.GONE); + mTickerView.setVisibility(View.VISIBLE); + mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); + mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); + if (mExpandedVisible) { + setDateViewVisibility(false, com.android.internal.R.anim.push_up_out); + } + } + + @Override + void tickerDone() { + mIcons.setVisibility(View.VISIBLE); + mTickerView.setVisibility(View.GONE); + mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); + mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, + mTickingDoneListener)); + if (mExpandedVisible) { + setDateViewVisibility(true, com.android.internal.R.anim.push_down_in); + } + } + + void tickerHalting() { + mIcons.setVisibility(View.VISIBLE); + mTickerView.setVisibility(View.GONE); + mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); + mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out, + mTickingDoneListener)); + if (mExpandedVisible) { + setDateViewVisibility(true, com.android.internal.R.anim.fade_in); + } + } + } + + Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; + public void onAnimationEnd(Animation animation) { + mTicking = false; + } + public void onAnimationRepeat(Animation animation) { + } + public void onAnimationStart(Animation animation) { + } + }; + + private Animation loadAnim(int id, Animation.AnimationListener listener) { + Animation anim = AnimationUtils.loadAnimation(mContext, id); + if (listener != null) { + anim.setAnimationListener(listener); + } + return anim; + } + + public String viewInfo(View v) { + return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() + + " " + v.getWidth() + "x" + v.getHeight() + ")"; + } + + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump StatusBar from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + synchronized (mQueueLock) { + pw.println("Current Status Bar state:"); + pw.println(" mExpanded=" + mExpanded + + ", mExpandedVisible=" + mExpandedVisible); + pw.println(" mTicking=" + mTicking); + pw.println(" mTracking=" + mTracking); + pw.println(" mAnimating=" + mAnimating + + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel + + ", mAnimAccel=" + mAnimAccel); + pw.println(" mCurAnimationTime=" + mCurAnimationTime + + " mAnimLastTime=" + mAnimLastTime); + pw.println(" mDisplayHeight=" + mDisplayHeight + + " mAnimatingReveal=" + mAnimatingReveal + + " mViewDelta=" + mViewDelta); + pw.println(" mDisplayHeight=" + mDisplayHeight); + final int N = mQueue.size(); + pw.println(" mQueue.size=" + N); + for (int i=0; i list = null; + if (pkgList != null) { + synchronized (StatusBarManagerService.this) { + for (String pkg : pkgList) { + list = mNotificationData.notificationsForPackage(pkg); + } + } + } + + if (list != null) { + final int N = list.size(); + for (int i=0; i - * This interesting thing to note about this class is that most of the methods that - * are called from other classes just post a message, and everything else is batched - * and coalesced into a series of calls to methods that all start with "perform." - * There are two reasons for this. The first is that some of the methods (activate/deactivate) - * are on IStatusBarService, so they're called from the thread pool and they need to make their - * way onto the UI thread. The second is that the message queue is stopped while animations - * are happening in order to make for smoother transitions. - *

- * Each icon is either an icon or an icon and a notification. They're treated mostly - * separately throughout the code, although they both use the same key, which is assigned - * when they are created. - */ -public class StatusBarService extends IStatusBarService.Stub -{ - static final String TAG = "StatusBar"; - static final boolean SPEW = false; - - public static final String ACTION_STATUSBAR_START - = "com.android.internal.policy.statusbar.START"; - - static final int EXPANDED_LEAVE_ALONE = -10000; - static final int EXPANDED_FULL_OPEN = -10001; - - private static final int MSG_ANIMATE = 1000; - private static final int MSG_ANIMATE_REVEAL = 1001; - - private static final int OP_ADD_ICON = 1; - private static final int OP_UPDATE_ICON = 2; - private static final int OP_REMOVE_ICON = 3; - private static final int OP_SET_VISIBLE = 4; - private static final int OP_EXPAND = 5; - private static final int OP_TOGGLE = 6; - private static final int OP_DISABLE = 7; - private class PendingOp { - IBinder key; - int code; - IconData iconData; - NotificationData notificationData; - boolean visible; - int integer; - } - - private class DisableRecord implements IBinder.DeathRecipient { - String pkg; - int what; - IBinder token; - - public void binderDied() { - Slog.i(TAG, "binder died for pkg=" + pkg); - disable(0, token, pkg); - token.unlinkToDeath(this, 0); - } - } - - public interface NotificationCallbacks { - void onSetDisabled(int status); - void onClearAll(); - void onNotificationClick(String pkg, String tag, int id); - void onPanelRevealed(); - } - - private class ExpandedDialog extends Dialog { - ExpandedDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Light_NoTitleBar); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - boolean down = event.getAction() == KeyEvent.ACTION_DOWN; - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_BACK: - if (!down) { - StatusBarService.this.deactivate(); - } - return true; - } - return super.dispatchKeyEvent(event); - } - } - - final Context mContext; - final Display mDisplay; - StatusBarView mStatusBarView; - int mPixelFormat; - H mHandler = new H(); - Object mQueueLock = new Object(); - ArrayList mQueue = new ArrayList(); - NotificationCallbacks mNotificationCallbacks; - - // All accesses to mIconMap and mNotificationData are syncronized on those objects, - // but this is only so dump() can work correctly. Modifying these outside of the UI - // thread will not work, there are places in the code that unlock and reaquire between - // reads and require them to not be modified. - - // icons - HashMap mIconMap = new HashMap(); - ArrayList mIconList = new ArrayList(); - String[] mRightIconSlots; - StatusBarIcon[] mRightIcons; - LinearLayout mIcons; - IconMerger mNotificationIcons; - LinearLayout mStatusIcons; - StatusBarIcon mMoreIcon; - private UninstallReceiver mUninstallReceiver; - - // expanded notifications - NotificationViewList mNotificationData = new NotificationViewList(); - Dialog mExpandedDialog; - ExpandedView mExpandedView; - WindowManager.LayoutParams mExpandedParams; - ScrollView mScrollView; - View mNotificationLinearLayout; - TextView mOngoingTitle; - LinearLayout mOngoingItems; - TextView mLatestTitle; - LinearLayout mLatestItems; - TextView mNoNotificationsTitle; - TextView mSpnLabel; - TextView mPlmnLabel; - TextView mClearButton; - View mExpandedContents; - CloseDragHandle mCloseView; - int[] mPositionTmp = new int[2]; - boolean mExpanded; - boolean mExpandedVisible; - - // the date view - DateView mDateView; - - // the tracker view - TrackingView mTrackingView; - WindowManager.LayoutParams mTrackingParams; - int mTrackingPosition; // the position of the top of the tracking view. - - // ticker - private Ticker mTicker; - private View mTickerView; - private boolean mTicking; - - // Tracking finger for opening/closing. - int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore - boolean mTracking; - VelocityTracker mVelocityTracker; - - static final int ANIM_FRAME_DURATION = (1000/60); - - boolean mAnimating; - long mCurAnimationTime; - float mDisplayHeight; - float mAnimY; - float mAnimVel; - float mAnimAccel; - long mAnimLastTime; - boolean mAnimatingReveal = false; - int mViewDelta; - int[] mAbsPos = new int[2]; - - // for disabling the status bar - ArrayList mDisableRecords = new ArrayList(); - int mDisabled = 0; - - /** - * Construct the service, add the status bar view to the window manager - */ - public StatusBarService(Context context) { - mContext = context; - mDisplay = ((WindowManager)context.getSystemService( - Context.WINDOW_SERVICE)).getDefaultDisplay(); - makeStatusBarView(context); - mUninstallReceiver = new UninstallReceiver(); - } - - public void setNotificationCallbacks(NotificationCallbacks listener) { - mNotificationCallbacks = listener; - } - - // ================================================================================ - // Constructing the view - // ================================================================================ - private void makeStatusBarView(Context context) { - Resources res = context.getResources(); - mRightIconSlots = res.getStringArray(com.android.internal.R.array.status_bar_icon_order); - mRightIcons = new StatusBarIcon[mRightIconSlots.length]; - - ExpandedView expanded = (ExpandedView)View.inflate(context, - com.android.internal.R.layout.status_bar_expanded, null); - expanded.mService = this; - StatusBarView sb = (StatusBarView)View.inflate(context, - com.android.internal.R.layout.status_bar, null); - sb.mService = this; - - // figure out which pixel-format to use for the status bar. - mPixelFormat = PixelFormat.TRANSLUCENT; - Drawable bg = sb.getBackground(); - if (bg != null) { - mPixelFormat = bg.getOpacity(); - } - - mStatusBarView = sb; - mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons); - mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons); - mNotificationIcons.service = this; - mIcons = (LinearLayout)sb.findViewById(R.id.icons); - mTickerView = sb.findViewById(R.id.ticker); - mDateView = (DateView)sb.findViewById(R.id.date); - - mExpandedDialog = new ExpandedDialog(context); - mExpandedView = expanded; - mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout); - mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle); - mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems); - mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle); - mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems); - mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle); - mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button); - mClearButton.setOnClickListener(mClearButtonListener); - mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel); - mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel); - mScrollView = (ScrollView)expanded.findViewById(R.id.scroll); - mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout); - - mOngoingTitle.setVisibility(View.GONE); - mLatestTitle.setVisibility(View.GONE); - - mTicker = new MyTicker(context, sb); - - TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText); - tickerView.mTicker = mTicker; - - mTrackingView = (TrackingView)View.inflate(context, - com.android.internal.R.layout.status_bar_tracking, null); - mTrackingView.mService = this; - mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close); - mCloseView.mService = this; - - mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); - - // add the more icon for the notifications - IconData moreData = IconData.makeIcon(null, context.getPackageName(), - R.drawable.stat_notify_more, 0, 42); - mMoreIcon = new StatusBarIcon(context, moreData, mNotificationIcons); - mMoreIcon.view.setId(R.drawable.stat_notify_more); - mNotificationIcons.moreIcon = mMoreIcon; - mNotificationIcons.addView(mMoreIcon.view); - - // set the inital view visibility - setAreThereNotifications(); - mDateView.setVisibility(View.INVISIBLE); - - // before we register for broadcasts - mPlmnLabel.setText(R.string.lockscreen_carrier_default); - mPlmnLabel.setVisibility(View.VISIBLE); - mSpnLabel.setText(""); - mSpnLabel.setVisibility(View.GONE); - - // receive broadcasts - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION); - context.registerReceiver(mBroadcastReceiver, filter); - } - - public void systemReady() { - final StatusBarView view = mStatusBarView; - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - view.getContext().getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height), - WindowManager.LayoutParams.TYPE_STATUS_BAR, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| - WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING, - mPixelFormat); - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - lp.setTitle("StatusBar"); - lp.windowAnimations = R.style.Animation_StatusBar; - - //WindowManagerImpl.getDefault().addView(view, lp); - } - - public void systemReady2() { - // Start the status bar app - Intent intent = new Intent(ACTION_STATUSBAR_START); - mContext.sendBroadcast(intent /** permission **/); - } - - // ================================================================================ - // From IStatusBarService - // ================================================================================ - public void activate() { - enforceExpandStatusBar(); - addPendingOp(OP_EXPAND, null, true); - } - - public void deactivate() { - enforceExpandStatusBar(); - addPendingOp(OP_EXPAND, null, false); - } - - public void toggle() { - enforceExpandStatusBar(); - addPendingOp(OP_TOGGLE, null, false); - } - - public void disable(int what, IBinder token, String pkg) { - enforceStatusBar(); - synchronized (mNotificationCallbacks) { - // This is a little gross, but I think it's safe as long as nobody else - // synchronizes on mNotificationCallbacks. It's important that the the callback - // and the pending op get done in the correct order and not interleaved with - // other calls, otherwise they'll get out of sync. - int net; - synchronized (mDisableRecords) { - manageDisableListLocked(what, token, pkg); - net = gatherDisableActionsLocked(); - mNotificationCallbacks.onSetDisabled(net); - } - addPendingOp(OP_DISABLE, net); - } - } - - public IBinder addIcon(String slot, String iconPackage, int iconId, int iconLevel) { - enforceStatusBar(); - return addIcon(IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null); - } - - public void updateIcon(IBinder key, - String slot, String iconPackage, int iconId, int iconLevel) { - enforceStatusBar(); - updateIcon(key, IconData.makeIcon(slot, iconPackage, iconId, iconLevel, 0), null); - } - - public void removeIcon(IBinder key) { - enforceStatusBar(); - addPendingOp(OP_REMOVE_ICON, key, null, null, -1); - } - - private void enforceStatusBar() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.STATUS_BAR, - "StatusBarService"); - } - - private void enforceExpandStatusBar() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.EXPAND_STATUS_BAR, - "StatusBarService"); - } - - public void registerStatusBar(IStatusBar bar) { - Slog.d(TAG, "registerStatusBar bar=" + bar); - } - - - // ================================================================================ - // Can be called from any thread - // ================================================================================ - public IBinder addIcon(IconData data, NotificationData n) { - int slot; - // assert early-on if they using a slot that doesn't exist. - if (data != null && n == null) { - slot = getRightIconIndex(data.slot); - if (slot < 0) { - throw new SecurityException("invalid status bar icon slot: " - + (data.slot != null ? "'" + data.slot + "'" : "null")); - } - } else { - slot = -1; - } - IBinder key = new Binder(); - addPendingOp(OP_ADD_ICON, key, data, n, -1); - return key; - } - - public void updateIcon(IBinder key, IconData data, NotificationData n) { - addPendingOp(OP_UPDATE_ICON, key, data, n, -1); - } - - public void setIconVisibility(IBinder key, boolean visible) { - addPendingOp(OP_SET_VISIBLE, key, visible); - } - - private void addPendingOp(int code, IBinder key, IconData data, NotificationData n, int i) { - synchronized (mQueueLock) { - PendingOp op = new PendingOp(); - op.key = key; - op.code = code; - op.iconData = data == null ? null : data.clone(); - op.notificationData = n; - op.integer = i; - mQueue.add(op); - if (mQueue.size() == 1) { - mHandler.sendEmptyMessage(2); - } - } - } - - private void addPendingOp(int code, IBinder key, boolean visible) { - synchronized (mQueueLock) { - PendingOp op = new PendingOp(); - op.key = key; - op.code = code; - op.visible = visible; - mQueue.add(op); - if (mQueue.size() == 1) { - mHandler.sendEmptyMessage(1); - } - } - } - - private void addPendingOp(int code, int integer) { - synchronized (mQueueLock) { - PendingOp op = new PendingOp(); - op.code = code; - op.integer = integer; - mQueue.add(op); - if (mQueue.size() == 1) { - mHandler.sendEmptyMessage(1); - } - } - } - - // lock on mDisableRecords - void manageDisableListLocked(int what, IBinder token, String pkg) { - if (SPEW) { - Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what) - + " pkg=" + pkg); - } - // update the list - synchronized (mDisableRecords) { - final int N = mDisableRecords.size(); - DisableRecord tok = null; - int i; - for (i=0; i queue; - synchronized (mQueueLock) { - queue = mQueue; - mQueue = new ArrayList(); - } - - boolean wasExpanded = mExpanded; - - // for each one in the queue, find all of the ones with the same key - // and collapse that down into a final op and/or call to setVisibility, etc - boolean expand = wasExpanded; - boolean doExpand = false; - boolean doDisable = false; - int disableWhat = 0; - int N = queue.size(); - while (N > 0) { - PendingOp op = queue.get(0); - boolean doOp = false; - boolean visible = false; - boolean doVisibility = false; - if (op.code == OP_SET_VISIBLE) { - doVisibility = true; - visible = op.visible; - } - else if (op.code == OP_EXPAND) { - doExpand = true; - expand = op.visible; - } - else if (op.code == OP_TOGGLE) { - doExpand = true; - expand = !expand; - } - else { - doOp = true; - } - - if (alwaysHandle(op.code)) { - // coalesce these - for (int i=1; i s - final float y = mAnimY; - final float v = mAnimVel; // px/s - final float a = mAnimAccel; // px/s/s - mAnimY = y + (v*t) + (0.5f*a*t*t); // px - mAnimVel = v + (a*t); // px/s - mAnimLastTime = now; // ms - //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY - // + " mAnimAccel=" + mAnimAccel); - } - - void doRevealAnimation() { - final int h = mCloseView.getHeight() + mStatusBarView.getHeight(); - if (mAnimatingReveal && mAnimating && mAnimY < h) { - incrementAnim(); - if (mAnimY >= h) { - mAnimY = h; - updateExpandedViewPos((int)mAnimY); - } else { - updateExpandedViewPos((int)mAnimY); - mCurAnimationTime += ANIM_FRAME_DURATION; - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), - mCurAnimationTime); - } - } - } - - void prepareTracking(int y, boolean opening) { - mTracking = true; - mVelocityTracker = VelocityTracker.obtain(); - if (opening) { - mAnimAccel = 2000.0f; - mAnimVel = 200; - mAnimY = mStatusBarView.getHeight(); - updateExpandedViewPos((int)mAnimY); - mAnimating = true; - mAnimatingReveal = true; - mHandler.removeMessages(MSG_ANIMATE); - mHandler.removeMessages(MSG_ANIMATE_REVEAL); - long now = SystemClock.uptimeMillis(); - mAnimLastTime = now; - mCurAnimationTime = now + ANIM_FRAME_DURATION; - mAnimating = true; - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), - mCurAnimationTime); - makeExpandedVisible(); - } else { - // it's open, close it? - if (mAnimating) { - mAnimating = false; - mHandler.removeMessages(MSG_ANIMATE); - } - updateExpandedViewPos(y + mViewDelta); - } - } - - void performFling(int y, float vel, boolean always) { - mAnimatingReveal = false; - mDisplayHeight = mDisplay.getHeight(); - - mAnimY = y; - mAnimVel = vel; - - //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel); - - if (mExpanded) { - if (!always && ( - vel > 200.0f - || (y > (mDisplayHeight-25) && vel > -200.0f))) { - // We are expanded, but they didn't move sufficiently to cause - // us to retract. Animate back to the expanded position. - mAnimAccel = 2000.0f; - if (vel < 0) { - mAnimVel = 0; - } - } - else { - // We are expanded and are now going to animate away. - mAnimAccel = -2000.0f; - if (vel > 0) { - mAnimVel = 0; - } - } - } else { - if (always || ( - vel > 200.0f - || (y > (mDisplayHeight/2) && vel > -200.0f))) { - // We are collapsed, and they moved enough to allow us to - // expand. Animate in the notifications. - mAnimAccel = 2000.0f; - if (vel < 0) { - mAnimVel = 0; - } - } - else { - // We are collapsed, but they didn't move sufficiently to cause - // us to retract. Animate back to the collapsed position. - mAnimAccel = -2000.0f; - if (vel > 0) { - mAnimVel = 0; - } - } - } - //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel - // + " mAnimAccel=" + mAnimAccel); - - long now = SystemClock.uptimeMillis(); - mAnimLastTime = now; - mCurAnimationTime = now + ANIM_FRAME_DURATION; - mAnimating = true; - mHandler.removeMessages(MSG_ANIMATE); - mHandler.removeMessages(MSG_ANIMATE_REVEAL); - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime); - stopTracking(); - } - - boolean interceptTouchEvent(MotionEvent event) { - if (SPEW) { - Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" - + mDisabled); - } - - if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { - return false; - } - - final int statusBarSize = mStatusBarView.getHeight(); - final int hitSize = statusBarSize*2; - if (event.getAction() == MotionEvent.ACTION_DOWN) { - final int y = (int)event.getRawY(); - - if (!mExpanded) { - mViewDelta = statusBarSize - y; - } else { - mTrackingView.getLocationOnScreen(mAbsPos); - mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y; - } - if ((!mExpanded && y < hitSize) || - (mExpanded && y > (mDisplay.getHeight()-hitSize))) { - - // We drop events at the edge of the screen to make the windowshade come - // down by accident less, especially when pushing open a device with a keyboard - // that rotates (like g1 and droid) - int x = (int)event.getRawX(); - final int edgeBorder = mEdgeBorder; - if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) { - prepareTracking(y, !mExpanded);// opening if we're not already fully visible - mVelocityTracker.addMovement(event); - } - } - } else if (mTracking) { - mVelocityTracker.addMovement(event); - final int minY = statusBarSize + mCloseView.getHeight(); - if (event.getAction() == MotionEvent.ACTION_MOVE) { - int y = (int)event.getRawY(); - if (mAnimatingReveal && y < minY) { - // nothing - } else { - mAnimatingReveal = false; - updateExpandedViewPos(y + mViewDelta); - } - } else if (event.getAction() == MotionEvent.ACTION_UP) { - mVelocityTracker.computeCurrentVelocity(1000); - - float yVel = mVelocityTracker.getYVelocity(); - boolean negative = yVel < 0; - - float xVel = mVelocityTracker.getXVelocity(); - if (xVel < 0) { - xVel = -xVel; - } - if (xVel > 150.0f) { - xVel = 150.0f; // limit how much we care about the x axis - } - - float vel = (float)Math.hypot(yVel, xVel); - if (negative) { - vel = -vel; - } - - performFling((int)event.getRawY(), vel, false); - } - - } - return false; - } - - private class Launcher implements View.OnClickListener { - private PendingIntent mIntent; - private String mPkg; - private String mTag; - private int mId; - - Launcher(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(); - } catch (RemoteException e) { - } - 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); - mNotificationCallbacks.onNotificationClick(mPkg, mTag, mId); - } catch (PendingIntent.CanceledException e) { - // the stack trace isn't very helpful here. Just log the exception message. - Slog.w(TAG, "Sending contentIntent failed: " + e); - } - deactivate(); - } - } - - private class MyTicker extends Ticker { - MyTicker(Context context, StatusBarView sb) { - super(context, sb); - } - - @Override - void tickerStarting() { - mTicking = true; - mIcons.setVisibility(View.GONE); - mTickerView.setVisibility(View.VISIBLE); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); - if (mExpandedVisible) { - setDateViewVisibility(false, com.android.internal.R.anim.push_up_out); - } - } - - @Override - void tickerDone() { - mIcons.setVisibility(View.VISIBLE); - mTickerView.setVisibility(View.GONE); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, - mTickingDoneListener)); - if (mExpandedVisible) { - setDateViewVisibility(true, com.android.internal.R.anim.push_down_in); - } - } - - void tickerHalting() { - mIcons.setVisibility(View.VISIBLE); - mTickerView.setVisibility(View.GONE); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out, - mTickingDoneListener)); - if (mExpandedVisible) { - setDateViewVisibility(true, com.android.internal.R.anim.fade_in); - } - } - } - - Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; - public void onAnimationEnd(Animation animation) { - mTicking = false; - } - public void onAnimationRepeat(Animation animation) { - } - public void onAnimationStart(Animation animation) { - } - }; - - private Animation loadAnim(int id, Animation.AnimationListener listener) { - Animation anim = AnimationUtils.loadAnimation(mContext, id); - if (listener != null) { - anim.setAnimationListener(listener); - } - return anim; - } - - public String viewInfo(View v) { - return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() - + " " + v.getWidth() + "x" + v.getHeight() + ")"; - } - - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump StatusBar from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (mQueueLock) { - pw.println("Current Status Bar state:"); - pw.println(" mExpanded=" + mExpanded - + ", mExpandedVisible=" + mExpandedVisible); - pw.println(" mTicking=" + mTicking); - pw.println(" mTracking=" + mTracking); - pw.println(" mAnimating=" + mAnimating - + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel - + ", mAnimAccel=" + mAnimAccel); - pw.println(" mCurAnimationTime=" + mCurAnimationTime - + " mAnimLastTime=" + mAnimLastTime); - pw.println(" mDisplayHeight=" + mDisplayHeight - + " mAnimatingReveal=" + mAnimatingReveal - + " mViewDelta=" + mViewDelta); - pw.println(" mDisplayHeight=" + mDisplayHeight); - final int N = mQueue.size(); - pw.println(" mQueue.size=" + N); - for (int i=0; i list = null; - if (pkgList != null) { - synchronized (StatusBarService.this) { - for (String pkg : pkgList) { - list = mNotificationData.notificationsForPackage(pkg); - } - } - } - - if (list != null) { - final int N = list.size(); - for (int i=0; i