NotificationStation.java revision c97593b9fda3344828b505cd9dec69e3709f9045
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings; 18 19import android.app.Activity; 20import android.app.ActivityManager; 21import android.app.INotificationListener; 22import android.app.INotificationManager; 23import android.app.Notification; 24import android.content.BroadcastReceiver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.pm.PackageManager; 29import android.content.res.Resources; 30import android.graphics.drawable.Drawable; 31import android.net.Uri; 32import android.os.Bundle; 33import android.os.RemoteException; 34import android.os.ServiceManager; 35import android.os.UserHandle; 36import android.util.Log; 37import android.view.LayoutInflater; 38import android.view.View; 39import android.view.View.OnClickListener; 40import android.view.ViewGroup; 41import android.widget.ArrayAdapter; 42import android.widget.DateTimeView; 43import android.widget.ImageView; 44import android.widget.ListView; 45import android.widget.TextView; 46import com.android.internal.statusbar.StatusBarNotification; 47 48import java.util.ArrayList; 49import java.util.List; 50 51public class NotificationStation extends SettingsPreferenceFragment { 52 private static final String TAG = NotificationStation.class.getSimpleName(); 53 static final boolean DEBUG = true; 54 private static final String PACKAGE_SCHEME = "package"; 55 private static final boolean SHOW_HISTORICAL_NOTIFICATIONS = true; 56 57 private final PackageReceiver mPackageReceiver = new PackageReceiver(); 58 59 private INotificationManager mNoMan; 60 private INotificationListener.Stub mListener = new INotificationListener.Stub() { 61 @Override 62 public void onNotificationPosted(StatusBarNotification notification) throws RemoteException { 63 Log.v(TAG, "onNotificationPosted: " + notification); 64 getListView().post(new Runnable() { public void run() { refreshList(); }}); 65 } 66 67 @Override 68 public void onNotificationRemoved(StatusBarNotification notification) throws RemoteException { 69 Log.v(TAG, "onNotificationRemoved: " + notification); 70 getListView().post(new Runnable() { public void run() { refreshList(); }}); 71 } 72 }; 73 74 private NotificationHistoryAdapter mAdapter; 75 private Context mContext; 76 77 @Override 78 public void onAttach(Activity activity) { 79 logd("onAttach(%s)", activity.getClass().getSimpleName()); 80 super.onAttach(activity); 81 mContext = activity; 82 mNoMan = INotificationManager.Stub.asInterface( 83 ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 84 try { 85 mNoMan.registerListener(mListener, ActivityManager.getCurrentUser()); 86 } catch (RemoteException e) { 87 // well, that didn't work out 88 } 89 } 90 91 @Override 92 public void onCreate(Bundle icicle) { 93 logd("onCreate(%s)", icicle); 94 super.onCreate(icicle); 95 Activity activity = getActivity(); 96 } 97 98 @Override 99 public void onDestroyView() { 100 super.onDestroyView(); 101 } 102 103 @Override 104 public void onActivityCreated(Bundle savedInstanceState) { 105 logd("onActivityCreated(%s)", savedInstanceState); 106 super.onActivityCreated(savedInstanceState); 107 108 ListView listView = getListView(); 109 110// TextView emptyView = (TextView) getView().findViewById(android.R.id.empty); 111// emptyView.setText(R.string.screensaver_settings_disabled_prompt); 112// listView.setEmptyView(emptyView); 113 114 mAdapter = new NotificationHistoryAdapter(mContext); 115 listView.setAdapter(mAdapter); 116 } 117 118 @Override 119 public void onPause() { 120 logd("onPause()"); 121 super.onPause(); 122 mContext.unregisterReceiver(mPackageReceiver); 123 } 124 125 @Override 126 public void onResume() { 127 logd("onResume()"); 128 super.onResume(); 129 refreshList(); 130 131 // listen for package changes 132 IntentFilter filter = new IntentFilter(); 133 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 134 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 135 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 136 filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 137 filter.addDataScheme(PACKAGE_SCHEME); 138 mContext.registerReceiver(mPackageReceiver , filter); 139 } 140 141 private void refreshList() { 142 List<HistoricalNotificationInfo> infos = loadNotifications(); 143 if (infos != null) { 144 logd("adding %d infos", infos.size()); 145 mAdapter.clear(); 146 mAdapter.addAll(infos); 147 } 148 } 149 150 private static void logd(String msg, Object... args) { 151 if (DEBUG) 152 Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args)); 153 } 154 155 private static class HistoricalNotificationInfo { 156 public String pkg; 157 public Drawable pkgicon; 158 public Drawable icon; 159 public CharSequence title; 160 public int priority; 161 public int user; 162 public long timestamp; 163 } 164 165 private List<HistoricalNotificationInfo> loadNotifications() { 166 final int currentUserId = ActivityManager.getCurrentUser(); 167 try { 168 StatusBarNotification[] nions; 169 nions = SHOW_HISTORICAL_NOTIFICATIONS 170 ? mNoMan.getHistoricalNotifications(mContext.getPackageName(), 50) 171 : mNoMan.getActiveNotifications(mContext.getPackageName()); 172 173 List<HistoricalNotificationInfo> list 174 = new ArrayList<HistoricalNotificationInfo>(nions.length); 175 176 for (StatusBarNotification sbn : nions) { 177 final HistoricalNotificationInfo info = new HistoricalNotificationInfo(); 178 info.pkg = sbn.pkg; 179 info.user = sbn.getUserId(); 180 info.icon = loadIconDrawable(info.pkg, info.user, sbn.notification.icon); 181 info.pkgicon = loadPackageIconDrawable(info.pkg, info.user); 182 if (sbn.notification.extras != null) { 183 info.title = sbn.notification.extras.getString(Notification.EXTRA_TITLE); 184 } 185 info.timestamp = sbn.postTime; 186 info.priority = sbn.notification.priority; 187 logd(" [%d] %s: %s", info.timestamp, info.pkg, info.title); 188 189 if (info.user == UserHandle.USER_ALL 190 || info.user == currentUserId) { 191 list.add(info); 192 } 193 } 194 195 return list; 196 } catch (RemoteException e) { 197 e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 198 } 199 return null; 200 } 201 202 private Resources getResourcesForUserPackage(String pkg, int userId) { 203 Resources r = null; 204 205 if (pkg != null) { 206 try { 207 if (userId == UserHandle.USER_ALL) { 208 userId = UserHandle.USER_OWNER; 209 } 210 r = mContext.getPackageManager() 211 .getResourcesForApplicationAsUser(pkg, userId); 212 } catch (PackageManager.NameNotFoundException ex) { 213 Log.e(TAG, "Icon package not found: " + pkg); 214 return null; 215 } 216 } else { 217 r = mContext.getResources(); 218 } 219 return r; 220 } 221 222 private Drawable loadPackageIconDrawable(String pkg, int userId) { 223 Drawable icon = null; 224 try { 225 icon = mContext.getPackageManager().getApplicationIcon(pkg); 226 } catch (PackageManager.NameNotFoundException e) { 227 } 228 229 return icon; 230 } 231 232 private Drawable loadIconDrawable(String pkg, int userId, int resId) { 233 Resources r = getResourcesForUserPackage(pkg, userId); 234 235 if (resId == 0) { 236 return null; 237 } 238 239 try { 240 return r.getDrawable(resId); 241 } catch (RuntimeException e) { 242 Log.w(TAG, "Icon not found in " 243 + (pkg != null ? resId : "<system>") 244 + ": " + Integer.toHexString(resId)); 245 } 246 247 return null; 248 } 249 250 private class NotificationHistoryAdapter extends ArrayAdapter<HistoricalNotificationInfo> { 251 private final LayoutInflater mInflater; 252 253 public NotificationHistoryAdapter(Context context) { 254 super(context, 0); 255 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 256 } 257 258 @Override 259 public View getView(int position, View convertView, ViewGroup parent) { 260 HistoricalNotificationInfo info = getItem(position); 261 logd("getView(%s/%s)", info.pkg, info.title); 262 final View row = convertView != null ? convertView : createRow(parent, info.pkg); 263 row.setTag(info); 264 265 // bind icon 266 if (info.icon != null) { 267 ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(info.icon); 268 } 269 if (info.pkgicon != null) { 270 ((ImageView) row.findViewById(R.id.pkgicon)).setImageDrawable(info.pkgicon); 271 } 272 273 ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(info.timestamp); 274 275 // bind caption 276 ((TextView) row.findViewById(android.R.id.title)).setText(info.title); 277 278// // bind radio button 279// RadioButton radioButton = (RadioButton) row.findViewById(android.R.id.button1); 280// radioButton.setChecked(dreamInfo.isActive); 281// radioButton.setOnTouchListener(new OnTouchListener() { 282// @Override 283// public boolean onTouch(View v, MotionEvent event) { 284// row.onTouchEvent(event); 285// return false; 286// }}); 287 288 // bind settings button + divider 289// boolean showSettings = info. 290// settingsComponentName != null; 291// View settingsDivider = row.findViewById(R.id.divider); 292// settingsDivider.setVisibility(false ? View.VISIBLE : View.INVISIBLE); 293// 294// ImageView settingsButton = (ImageView) row.findViewById(android.R.id.button2); 295// settingsButton.setVisibility(false ? View.VISIBLE : View.INVISIBLE); 296// settingsButton.setAlpha(info.isActive ? 1f : Utils.DISABLED_ALPHA); 297// settingsButton.setEnabled(info.isActive); 298// settingsButton.setOnClickListener(new OnClickListener(){ 299// @Override 300// public void onClick(View v) { 301// mBackend.launchSettings((DreamInfo) row.getTag()); 302// }}); 303 304 return row; 305 } 306 307 private View createRow(ViewGroup parent, final String pkg) { 308 final View row = mInflater.inflate(R.layout.notification_log_row, parent, false); 309 row.setOnClickListener(new OnClickListener(){ 310 @Override 311 public void onClick(View v) { 312 v.setPressed(true); 313 startApplicationDetailsActivity(pkg); 314 }}); 315 return row; 316 } 317 318 } 319 320 private void startApplicationDetailsActivity(String packageName) { 321 Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, 322 Uri.fromParts("package", packageName, null)); 323 intent.setComponent(intent.resolveActivity(mContext.getPackageManager())); 324 startActivity(intent); 325 } 326 327 private class PackageReceiver extends BroadcastReceiver { 328 @Override 329 public void onReceive(Context context, Intent intent) { 330 logd("PackageReceiver.onReceive"); 331 //refreshList(); 332 } 333 } 334} 335