1 // dummy notifications for demos 2 // for anandx (at) google.com by dsandler (at) google.com 3 4 package com.android.example.notificationshowcase; 5 6 import java.util.ArrayList; 7 import android.app.Activity; 8 import android.app.Notification; 9 import android.app.NotificationManager; 10 import android.app.PendingIntent; 11 import android.app.Service; 12 import android.content.ComponentName; 13 import android.content.Context; 14 import android.content.Intent; 15 import android.graphics.Bitmap; 16 import android.graphics.Canvas; 17 import android.graphics.Typeface; 18 import android.graphics.drawable.BitmapDrawable; 19 import android.graphics.drawable.Drawable; 20 import android.net.Uri; 21 import android.os.Binder; 22 import android.os.Bundle; 23 import android.os.IBinder; 24 import android.support.v4.app.NotificationCompat; 25 import android.text.SpannableString; 26 import android.text.style.StyleSpan; 27 import android.util.Log; 28 import android.view.View; 29 import android.widget.Toast; 30 31 public class NotificationShowcaseActivity extends Activity { 32 private static final String TAG = "NotificationShowcase"; 33 34 private static final int NOTIFICATION_ID = 31338; 35 36 private static int bigtextId; 37 private static int uploadId; 38 39 private static final boolean FIRE_AND_FORGET = true; 40 41 public static class ToastFeedbackActivity extends Activity { 42 @Override 43 public void onCreate(Bundle icicle) { 44 super.onCreate(icicle); 45 } 46 47 @Override 48 public void onResume() { 49 super.onResume(); 50 Intent i = getIntent(); 51 Log.v(TAG, "clicked a thing! intent=" + i.toString()); 52 if (i.hasExtra("text")) { 53 final String text = i.getStringExtra("text"); 54 Toast.makeText(this, text, Toast.LENGTH_LONG).show(); 55 } 56 finish(); 57 } 58 } 59 60 public static class UpdateService extends Service { 61 @Override 62 public IBinder onBind(Intent intent) { 63 Log.v(TAG, "onbind"); 64 return null; 65 } 66 67 @Override 68 public void onStart(Intent i, int startId) { 69 super.onStart(i, startId); 70 try { 71 // allow the user close the shade, if they want to test that. 72 Thread.sleep(3000); 73 } catch (Exception e) { 74 } 75 Log.v(TAG, "clicked a thing! intent=" + i.toString()); 76 if (i.hasExtra("id") && i.hasExtra("when")) { 77 final int id = i.getIntExtra("id", 0); 78 if (id == bigtextId) { 79 NotificationManager noMa = 80 (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 81 final int update = i.getIntExtra("update", 0); 82 final long when = i.getLongExtra("when", 0L); 83 Log.v(TAG, "id: " + id + " when: " + when + " update: " + update); 84 noMa.notify(NOTIFICATION_ID + id, 85 makeBigTextNotification(this, update, id, when)); 86 } 87 } else { 88 Log.v(TAG, "id extra was " + (i.hasExtra("id") ? "present" : "missing")); 89 Log.v(TAG, "when extra was " + (i.hasExtra("when") ? "present" : "missing")); 90 } 91 } 92 } 93 94 public static class ProgressService extends Service { 95 @Override 96 public IBinder onBind(Intent intent) { 97 Log.v(TAG, "onbind"); 98 return null; 99 } 100 101 @Override 102 public void onStart(Intent i, int startId) { 103 super.onStart(i, startId); 104 if (i.hasExtra("id") && i.hasExtra("when") && i.hasExtra("progress")) { 105 final int id = i.getIntExtra("id", 0); 106 if (id == uploadId) { 107 final long when = i.getLongExtra("when", 0L); 108 int progress = i.getIntExtra("progress", 0); 109 NotificationManager noMa = (NotificationManager) 110 getSystemService(Context.NOTIFICATION_SERVICE); 111 while (progress <= 100) { 112 try { 113 // allow the user close the shade, if they want to test that. 114 Thread.sleep(1000); 115 } catch (Exception e) { 116 } 117 Log.v(TAG, "id: " + id + " when: " + when + " progress: " + progress); 118 noMa.notify(NOTIFICATION_ID + id, 119 makeUploadNotification(this, progress, id, when)); 120 progress+=10; 121 } 122 } 123 } else { 124 Log.v(TAG, "id extra " + (i.hasExtra("id") ? "present" : "missing")); 125 Log.v(TAG, "when extra " + (i.hasExtra("when") ? "present" : "missing")); 126 Log.v(TAG, "progress extra " + (i.hasExtra("progress") ? "present" : "missing")); 127 } 128 } 129 } 130 131 private ArrayList<Notification> mNotifications = new ArrayList<Notification>(); 132 NotificationManager mNoMa; 133 134 static int mLargeIconWidth, mLargeIconHeight; 135 private static Bitmap getBitmap(Context context, int resId) { 136 Drawable d = context.getResources().getDrawable(resId); 137 Bitmap b = Bitmap.createBitmap(mLargeIconWidth, mLargeIconHeight, Bitmap.Config.ARGB_8888); 138 Canvas c = new Canvas(b); 139 d.setBounds(0, 0, mLargeIconWidth, mLargeIconHeight); 140 d.draw(c); 141 return b; 142 } 143 144 private static PendingIntent makeToastIntent(Context context, String s) { 145 Intent toastIntent = new Intent(context, ToastFeedbackActivity.class); 146 toastIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 147 toastIntent.putExtra("text", s); 148 PendingIntent pi = PendingIntent.getActivity( 149 context, 58, toastIntent, PendingIntent.FLAG_CANCEL_CURRENT); 150 return pi; 151 } 152 153 private static PendingIntent makeEmailIntent(Context context, String who) { 154 final Intent intent = new Intent(android.content.Intent.ACTION_SENDTO, 155 Uri.parse("mailto:" + who)); 156 return PendingIntent.getActivity( 157 context, 0, intent, 158 PendingIntent.FLAG_CANCEL_CURRENT); 159 } 160 161 // this is a service, it will only close the notification shade if used as a contentIntent. 162 private static int updateId = 3000; 163 private static PendingIntent makeUpdateIntent(Context context, int update, int id, long when) { 164 Intent updateIntent = new Intent(); 165 updateIntent.setComponent( 166 new ComponentName(context, UpdateService.class)); 167 updateIntent.putExtra("id", id); 168 updateIntent.putExtra("when", when); 169 updateIntent.putExtra("update", update); 170 Log.v(TAG, "added id extra " + id); 171 Log.v(TAG, "added when extra " + when); 172 PendingIntent pi = PendingIntent.getService( 173 context, updateId++, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT); 174 return pi; 175 } 176 177 private static Notification makeBigTextNotification(Context context, int update, int id, 178 long when) { 179 String addendum = update > 0 ? "(updated) " : ""; 180 String longSmsText = "Hey, looks like\nI'm getting kicked out of this conference" + 181 " room"; 182 if (update > 1) { 183 longSmsText += ", so stay in the hangout and I'll rejoin in about 5-10 minutes" + 184 ". If you don't see me, assume I got pulled into another meeting. And" + 185 " now \u2026 I have to find my shoes. Four score and seven years "+ 186 "ago our fathers brought forth on this continent, a new nation, conceived "+ 187 "in Liberty, and dedicated to the proposition that all men are created "+ 188 "equal. Now we are engaged in a great civil war, testing whether that "+ 189 "nation, or any nation so conceived and so dedicated, can long "+ 190 "endure. We are met on a great battle-field of that war. We have come "+ 191 "to dedicate a portion of that field, as a final resting place for "+ 192 "those who here gave their lives that that nation might live. It is "+ 193 "altogether fitting and proper that we should do this.But, in a larger "+ 194 "sense, we can not dedicate -- we can not consecrate -- we can not "+ 195 "hallow -- this ground.The brave men, living and dead, who struggled "+ 196 "here, have consecrated it, far above our poor power to add or detract."+ 197 " The world will little note, nor long remember what we say here, but "+ 198 "it can never forget what they did here. It is for us the living, rather,"+ 199 " to be dedicated here to the unfinished work which they who fought "+ 200 "here have thus far so nobly advanced.It is rather for us to be here "+ 201 "dedicated to the great task remaining before us -- that from these "+ 202 "honored dead we take increased devotion to that cause for which they "+ 203 "gave the last full measure of devotion -- that we here highly resolve "+ 204 "that these dead shall not have died in vain -- that this nation, under "+ 205 "God, shall have a new birth of freedom -- and that government of "+ 206 "the people, by the people, for the people, shall not perish from the earth."; 207 } 208 if (update > 2) { 209 when = System.currentTimeMillis(); 210 } 211 NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); 212 bigTextStyle.bigText(addendum + longSmsText); 213 NotificationCompat.Builder bigTextNotification = new NotificationCompat.Builder(context) 214 .setContentTitle(addendum + "Mike Cleron") 215 .setContentIntent(makeToastIntent(context, "Clicked on bigText")) 216 .setContentText(addendum + longSmsText) 217 .setTicker(addendum + "Mike Cleron: " + longSmsText) 218 .setWhen(when) 219 .setLargeIcon(getBitmap(context, R.drawable.bucket)) 220 .setPriority(NotificationCompat.PRIORITY_HIGH) 221 .addAction(R.drawable.ic_media_next, 222 "update: " + update, 223 makeUpdateIntent(context, update+1, id, when)) 224 .setSmallIcon(R.drawable.stat_notify_talk_text) 225 .setStyle(bigTextStyle); 226 return bigTextNotification.build(); 227 } 228 229 // this is a service, it will only close the notification shade if used as a contentIntent. 230 private static void startProgressUpdater(Context context, int progress, int id, long when) { 231 Intent progressIntent = new Intent(); 232 progressIntent.setComponent(new ComponentName(context, ProgressService.class)); 233 progressIntent.putExtra("id", id); 234 progressIntent.putExtra("when", when); 235 progressIntent.putExtra("progress", progress); 236 context.startService(progressIntent); 237 } 238 239 private static Notification makeUploadNotification(Context context, int progress, int id, 240 long when) { 241 NotificationCompat.Builder uploadNotification = new NotificationCompat.Builder(context) 242 .setContentTitle("File Upload") 243 .setContentText("foo.txt") 244 .setPriority(NotificationCompat.PRIORITY_MIN) 245 .setContentIntent(makeToastIntent(context, "Clicked on Upload")) 246 .setWhen(when) 247 .setSmallIcon(R.drawable.ic_menu_upload) 248 .setProgress(100, Math.min(progress, 100), false); 249 return uploadNotification.build(); 250 } 251 252 @Override 253 public void onCreate(Bundle savedInstanceState) { 254 super.onCreate(savedInstanceState); 255 setContentView(R.layout.main); 256 257 mLargeIconWidth = (int) getResources().getDimension(R.dimen.notification_large_icon_width); 258 mLargeIconHeight = (int) getResources().getDimension(R.dimen.notification_large_icon_height); 259 260 mNoMa = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 261 262 bigtextId = mNotifications.size(); 263 mNotifications.add(makeBigTextNotification(this, 0, bigtextId, 264 System.currentTimeMillis())); 265 266 uploadId = mNotifications.size(); 267 long uploadWhen = System.currentTimeMillis(); 268 mNotifications.add(makeUploadNotification(this, 10, uploadId, uploadWhen)); 269 270 mNotifications.add(new NotificationCompat.Builder(this) 271 .setContentTitle("Incoming call") 272 .setContentText("Matias Duarte") 273 .setLargeIcon(getBitmap(this, R.drawable.matias_hed)) 274 .setSmallIcon(R.drawable.stat_sys_phone_call) 275 .setPriority(NotificationCompat.PRIORITY_MAX) 276 .setContentIntent(makeToastIntent(this, "Clicked on Matias")) 277 .addAction(R.drawable.ic_dial_action_call, "Answer", makeToastIntent(this, "call answered")) 278 .addAction(R.drawable.ic_end_call, "Ignore", makeToastIntent(this, "call ignored")) 279 .setAutoCancel(true) 280 .build()); 281 282 mNotifications.add(new NotificationCompat.Builder(this) 283 .setContentTitle("Stopwatch PRO") 284 .setContentText("Counting up") 285 .setContentIntent(makeToastIntent(this, "Clicked on Stopwatch")) 286 .setSmallIcon(R.drawable.stat_notify_alarm) 287 .setUsesChronometer(true) 288 .build()); 289 290 mNotifications.add(new NotificationCompat.Builder(this) 291 .setContentTitle("J Planning") 292 .setContentText("The Botcave") 293 .setWhen(System.currentTimeMillis()) 294 .setSmallIcon(R.drawable.stat_notify_calendar) 295 .setContentIntent(makeToastIntent(this, "tapped in the calendar event")) 296 .setContentInfo("7PM") 297 .addAction(R.drawable.stat_notify_snooze, "+10 min", 298 makeToastIntent(this, "snoozed 10 min")) 299 .addAction(R.drawable.stat_notify_snooze_longer, "+1 hour", 300 makeToastIntent(this, "snoozed 1 hr")) 301 .addAction(R.drawable.stat_notify_email, "Email", 302 makeEmailIntent(this, 303 "gabec (at) example.com,mcleron (at) example.com,dsandler (at) example.com")) 304 .build()); 305 306 BitmapDrawable d = 307 (BitmapDrawable) getResources().getDrawable(R.drawable.romainguy_rockaway); 308 mNotifications.add(new NotificationCompat.BigPictureStyle( 309 new NotificationCompat.Builder(this) 310 .setContentTitle("Romain Guy") 311 .setContentText("I was lucky to find a Canon 5D Mk III at a local Bay Area store last " 312 + "week but I had not been able to try it in the field until tonight. After a " 313 + "few days of rain the sky finally cleared up. Rockaway Beach did not disappoint " 314 + "and I was finally able to see what my new camera feels like when shooting " 315 + "landscapes.") 316 .setSmallIcon(R.drawable.ic_stat_gplus) 317 .setContentIntent(makeToastIntent(this, "Clicked on bigPicture")) 318 .setLargeIcon(getBitmap(this, R.drawable.romainguy_hed)) 319 .addAction(R.drawable.add, "Add to Gallery", 320 makeToastIntent(this, "added! (just kidding)")) 321 .setSubText("talk rocks!") 322 ) 323 .bigPicture(d.getBitmap()) 324 .build()); 325 326 // Note: this may conflict with real email notifications 327 StyleSpan bold = new StyleSpan(Typeface.BOLD); 328 SpannableString line1 = new SpannableString("Alice: hey there!"); 329 line1.setSpan(bold, 0, 5, 0); 330 SpannableString line2 = new SpannableString("Bob: hi there!"); 331 line2.setSpan(bold, 0, 3, 0); 332 SpannableString line3 = new SpannableString("Charlie: Iz IN UR EMAILZ!!"); 333 line3.setSpan(bold, 0, 7, 0); 334 mNotifications.add(new NotificationCompat.InboxStyle( 335 new NotificationCompat.Builder(this) 336 .setContentTitle("24 new messages") 337 .setContentText("You have mail!") 338 .setSubText("test.hugo2 (at) gmail.com") 339 .setContentIntent(makeToastIntent(this, "Clicked on Email")) 340 .setSmallIcon(R.drawable.stat_notify_email)) 341 .setSummaryText("+21 more") 342 .addLine(line1) 343 .addLine(line2) 344 .addLine(line3) 345 .build()); 346 347 mNotifications.add(new NotificationCompat.Builder(this) 348 .setContentTitle("Twitter") 349 .setContentText("New mentions") 350 .setContentIntent(makeToastIntent(this, "Clicked on Twitter")) 351 .setSmallIcon(R.drawable.twitter_icon) 352 .setNumber(15) 353 .setPriority(NotificationCompat.PRIORITY_LOW) 354 .build()); 355 356 if (FIRE_AND_FORGET) { 357 doPost(null); 358 startProgressUpdater(this, 10, uploadId, uploadWhen); 359 finish(); 360 } 361 } 362 363 public void doPost(View v) { 364 for (int i=0; i<mNotifications.size(); i++) { 365 mNoMa.notify(NOTIFICATION_ID + i, mNotifications.get(i)); 366 } 367 } 368 369 public void doRemove(View v) { 370 for (int i=0; i<mNotifications.size(); i++) { 371 mNoMa.cancel(NOTIFICATION_ID + i); 372 } 373 } 374 } 375