1 /* 2 * Copyright (C) 2013 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 17 package com.android.example.notificationshowcase; 18 19 import android.app.AlarmManager; 20 import android.app.IntentService; 21 import android.app.Notification; 22 import android.app.PendingIntent; 23 import android.content.ComponentName; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.SharedPreferences; 28 import android.database.Cursor; 29 import android.graphics.Bitmap; 30 import android.graphics.Canvas; 31 import android.graphics.Typeface; 32 import android.graphics.drawable.BitmapDrawable; 33 import android.graphics.drawable.Drawable; 34 import android.net.Uri; 35 import android.os.SystemClock; 36 import android.provider.ContactsContract; 37 import android.support.v4.app.NotificationCompat; 38 import android.support.v4.app.NotificationManagerCompat; 39 import android.support.v7.preference.PreferenceManager; 40 import android.text.SpannableString; 41 import android.text.TextUtils; 42 import android.text.style.StyleSpan; 43 import android.util.Log; 44 45 import com.android.example.notificationshowcase.R; 46 47 import java.util.ArrayList; 48 49 public class NotificationService extends IntentService { 50 51 private static final String TAG = "NotificationService"; 52 53 public static final String ACTION_CREATE = "create"; 54 public static final String ACTION_DESTROY = "destroy"; 55 public static final int NOTIFICATION_ID = 31338; 56 private static final long FADE_TIME_MILLIS = 1000 * 60 * 5; 57 58 public NotificationService() { 59 super(TAG); 60 } 61 62 public NotificationService(String name) { 63 super(name); 64 } 65 66 private static PendingIntent makeCancelAllIntent(Context context) { 67 final Intent intent = new Intent(ACTION_DESTROY); 68 intent.setComponent(new ComponentName(context, NotificationService.class)); 69 return PendingIntent.getService( 70 context, 0, intent, 71 PendingIntent.FLAG_UPDATE_CURRENT); 72 } 73 74 private static Bitmap getBitmap(Context context, int resId) { 75 int largeIconWidth = (int) context.getResources() 76 .getDimension(R.dimen.notification_large_icon_width); 77 int largeIconHeight = (int) context.getResources() 78 .getDimension(R.dimen.notification_large_icon_height); 79 Drawable d = context.getResources().getDrawable(resId); 80 Bitmap b = Bitmap.createBitmap(largeIconWidth, largeIconHeight, Bitmap.Config.ARGB_8888); 81 Canvas c = new Canvas(b); 82 d.setBounds(0, 0, largeIconWidth, largeIconHeight); 83 d.draw(c); 84 return b; 85 } 86 87 private static PendingIntent makeEmailIntent(Context context, String who) { 88 final Intent intent = new Intent(android.content.Intent.ACTION_SENDTO, 89 Uri.parse("mailto:" + who)); 90 return PendingIntent.getActivity( 91 context, 0, intent, 92 PendingIntent.FLAG_CANCEL_CURRENT); 93 } 94 95 public static Notification makeSmsNotification(Context context, int update, int id, long when) { 96 final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); 97 String sender = context.getString(R.string.sms_sender); 98 99 String personUri = null; 100 if (sharedPref.getBoolean(SettingsActivity.KEY_SMS_PERSON, false)) { 101 Cursor c = null; 102 try { 103 String[] projection = new String[] { ContactsContract.Contacts._ID, 104 ContactsContract.Contacts.LOOKUP_KEY }; 105 String selections = ContactsContract.Contacts.DISPLAY_NAME + " = ?"; 106 String[] selectionArgs = { sender }; 107 final ContentResolver contentResolver = context.getContentResolver(); 108 c = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, 109 projection, selections, selectionArgs, null); 110 if (c != null && c.getCount() > 0) { 111 c.moveToFirst(); 112 int lookupIdx = c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY); 113 int idIdx = c.getColumnIndex(ContactsContract.Contacts._ID); 114 String lookupKey = c.getString(lookupIdx); 115 long contactId = c.getLong(idIdx); 116 Uri lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 117 personUri = lookupUri.toString(); 118 } 119 } finally { 120 if (c != null) { 121 c.close(); 122 } 123 } 124 } 125 126 if (update > 2) { 127 when = System.currentTimeMillis(); 128 } 129 final String priorityName = sharedPref.getString(SettingsActivity.KEY_SMS_PRIORITY, "0"); 130 final int priority = Integer.valueOf(priorityName); 131 NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); 132 bigTextStyle.bigText(context.getString(R.string.sms_message)); 133 PendingIntent ci = ToastService.getPendingIntent(context, R.string.sms_click); 134 PendingIntent ai = UpdateService.getPendingIntent(context, update + 1, id, when); 135 NotificationCompat.Builder bigText = new NotificationCompat.Builder(context) 136 .setContentTitle(sender) 137 .setCategory(NotificationCompat.CATEGORY_MESSAGE) 138 .setContentIntent(ci) 139 .setContentText(context.getString(R.string.sms_message)) 140 .setWhen(when) 141 .setLargeIcon(getBitmap(context, R.drawable.bucket)) 142 .setPriority(priority) 143 .addAction(R.drawable.ic_media_next, context.getString(R.string.sms_reply), ai) 144 .setSmallIcon(R.drawable.stat_notify_talk_text) 145 .setStyle(bigTextStyle) 146 .setOnlyAlertOnce(sharedPref.getBoolean(SettingsActivity.KEY_SMS_ONCE, true)); 147 148 if (TextUtils.isEmpty(personUri)) { 149 Log.w(TAG, "failed to find contact for Mike Cleron"); 150 } else { 151 bigText.addPerson(personUri); 152 Log.w(TAG, "Mike Cleron is " + personUri); 153 } 154 155 int defaults = 0; 156 if(sharedPref.getBoolean(SettingsActivity.KEY_SMS_NOISY, true)) { 157 String uri = sharedPref.getString(SettingsActivity.KEY_SMS_SOUND, null); 158 if(uri == null) { 159 defaults |= Notification.DEFAULT_SOUND; 160 } else { 161 bigText.setSound(Uri.parse(uri)); 162 } 163 } 164 if(sharedPref.getBoolean(SettingsActivity.KEY_SMS_BUZZY, false)) { 165 defaults |= Notification.DEFAULT_VIBRATE; 166 } 167 bigText.setDefaults(defaults); 168 169 return bigText.build(); 170 } 171 172 public static Notification makeUploadNotification(Context context, int progress, long when) { 173 PendingIntent pi = ToastService.getPendingIntent(context, R.string.upload_click); 174 NotificationCompat.Builder uploadNotification = new NotificationCompat.Builder(context) 175 .setContentTitle(context.getString(R.string.upload_title)) 176 .setContentText(context.getString(R.string.upload_text)) 177 .setCategory(NotificationCompat.CATEGORY_PROGRESS) 178 .setPriority(NotificationCompat.PRIORITY_MIN) 179 .setContentIntent(pi) 180 .setWhen(when) 181 .setSmallIcon(R.drawable.ic_menu_upload) 182 .setProgress(100, Math.min(progress, 100), false); 183 return uploadNotification.build(); 184 } 185 186 @Override 187 protected void onHandleIntent(Intent intent) { 188 NotificationManagerCompat noMa = NotificationManagerCompat.from(this); 189 if (ACTION_DESTROY.equals(intent.getAction())) { 190 noMa.cancelAll(); 191 return; 192 } 193 194 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); 195 ArrayList<Notification> mNotifications = new ArrayList<Notification>(); 196 197 if(sharedPref.getBoolean(SettingsActivity.KEY_SMS_ENABLE, true)) { 198 final int id = mNotifications.size(); 199 mNotifications.add(makeSmsNotification(this, 2, id, System.currentTimeMillis())); 200 } 201 202 if(sharedPref.getBoolean(SettingsActivity.KEY_UPLOAD_ENABLE, false)) { 203 final int id = mNotifications.size(); 204 final long uploadWhen = System.currentTimeMillis(); 205 mNotifications.add(makeUploadNotification(this, 10, uploadWhen)); 206 ProgressService.startProgressUpdater(this, id, uploadWhen, 0); 207 } 208 209 if(sharedPref.getBoolean(SettingsActivity.KEY_PHONE_ENABLE, false)) { 210 final int id = mNotifications.size(); 211 final PendingIntent fullscreen = FullScreenActivity.getPendingIntent(this, id); 212 PendingIntent ans = PhoneService.getPendingIntent(this, id, 213 PhoneService.ACTION_ANSWER); 214 PendingIntent ign = 215 PhoneService.getPendingIntent(this, id, PhoneService.ACTION_IGNORE); 216 NotificationCompat.Builder phoneCall = new NotificationCompat.Builder(this) 217 .setContentTitle(getString(R.string.call_title)) 218 .setContentText(getString(R.string.call_text)) 219 .setLargeIcon(getBitmap(this, R.drawable.matias_hed)) 220 .setSmallIcon(R.drawable.stat_sys_phone_call) 221 .setPriority(NotificationCompat.PRIORITY_MAX) 222 .setCategory(NotificationCompat.CATEGORY_CALL) 223 .setContentIntent(fullscreen) 224 .addAction(R.drawable.ic_dial_action_call, getString(R.string.call_answer), ans) 225 .addAction(R.drawable.ic_end_call, getString(R.string.call_ignore), ign) 226 .setOngoing(true); 227 228 if(sharedPref.getBoolean(SettingsActivity.KEY_PHONE_FULLSCREEN, false)) { 229 phoneCall.setFullScreenIntent(fullscreen, true); 230 } 231 232 if(sharedPref.getBoolean(SettingsActivity.KEY_PHONE_NOISY, false)) { 233 phoneCall.setDefaults(Notification.DEFAULT_SOUND); 234 } 235 236 if (sharedPref.getBoolean(SettingsActivity.KEY_PHONE_PERSON, false)) { 237 phoneCall.addPerson(Uri.fromParts("tel", 238 "1 (617) 555-1212", null) 239 .toString()); 240 } 241 mNotifications.add(phoneCall.build()); 242 } 243 244 if(sharedPref.getBoolean(SettingsActivity.KEY_TIMER_ENABLE, false)) { 245 PendingIntent pi = ToastService.getPendingIntent(this, R.string.timer_click); 246 mNotifications.add(new NotificationCompat.Builder(this) 247 .setContentTitle(getString(R.string.timer_title)) 248 .setContentText(getString(R.string.timer_text)) 249 .setCategory(NotificationCompat.CATEGORY_PROGRESS) 250 .setContentIntent(pi) 251 .setSmallIcon(R.drawable.stat_notify_alarm) 252 .setUsesChronometer(true) 253 .build()); 254 } 255 256 if(sharedPref.getBoolean(SettingsActivity.KEY_CALENDAR_ENABLE, false)) { 257 mNotifications.add(new NotificationCompat.Builder(this) 258 .setContentTitle(getString(R.string.calendar_title)) 259 .setContentText(getString(R.string.calendar_text)) 260 .setCategory(NotificationCompat.CATEGORY_EVENT) 261 .setWhen(System.currentTimeMillis()) 262 .setSmallIcon(R.drawable.stat_notify_calendar) 263 .setContentIntent(ToastService.getPendingIntent(this, R.string.calendar_click)) 264 .setContentInfo("7PM") 265 .addAction(R.drawable.stat_notify_snooze, getString(R.string.calendar_10), 266 ToastService.getPendingIntent(this, R.string.calendar_10_click)) 267 .addAction(R.drawable.stat_notify_snooze_longer, getString(R.string.calendar_60), 268 ToastService.getPendingIntent(this, R.string.calendar_60_click)) 269 .addAction(R.drawable.stat_notify_email, "Email", 270 makeEmailIntent(this, 271 "gabec (at) example.com,mcleron (at) example.com,dsandler (at) example.com")) 272 .build()); 273 } 274 275 if(sharedPref.getBoolean(SettingsActivity.KEY_PICTURE_ENABLE, false)) { 276 BitmapDrawable d = 277 (BitmapDrawable) getResources().getDrawable(R.drawable.romainguy_rockaway); 278 PendingIntent ci = ToastService.getPendingIntent(this, R.string.picture_click); 279 PendingIntent ai = ToastService.getPendingIntent(this, R.string.picture_add_click); 280 mNotifications.add(new NotificationCompat.BigPictureStyle( 281 new NotificationCompat.Builder(this) 282 .setCategory(NotificationCompat.CATEGORY_SOCIAL) 283 .setContentTitle(getString(R.string.picture_title)) 284 .setContentText(getString(R.string.picture_text)) 285 .setSmallIcon(R.drawable.ic_stat_gplus) 286 .setContentIntent(ci) 287 .setLargeIcon(getBitmap(this, R.drawable.romainguy_hed)) 288 .addAction(R.drawable.add, getString(R.string.picture_add), ai) 289 .setSubText(getString(R.string.picture_sub_text))) 290 .bigPicture(d.getBitmap()) 291 .build()); 292 } 293 294 if(sharedPref.getBoolean(SettingsActivity.KEY_INBOX_ENABLE, false)) { 295 PendingIntent pi = ToastService.getPendingIntent(this, R.string.email_click); 296 mNotifications.add(new NotificationCompat.InboxStyle( 297 new NotificationCompat.Builder(this) 298 .setContentTitle(getString(R.string.email_title)) 299 .setContentText(getString(R.string.email_text)) 300 .setSubText(getString(R.string.email_sub_text)) 301 .setCategory(NotificationCompat.CATEGORY_EMAIL) 302 .setContentIntent(pi) 303 .setSmallIcon(R.drawable.stat_notify_email)) 304 .setSummaryText("+21 more") 305 .addLine(getString(R.string.email_a)) 306 .addLine(getString(R.string.email_b)) 307 .addLine(getString(R.string.email_c)) 308 .build()); 309 } 310 311 if(sharedPref.getBoolean(SettingsActivity.KEY_SOCIAL_ENABLE, false)) { 312 PendingIntent pi = ToastService.getPendingIntent(this, R.string.social_click); 313 mNotifications.add(new NotificationCompat.Builder(this) 314 .setContentTitle(getString(R.string.social_title)) 315 .setContentText(getString(R.string.social_text)) 316 .setCategory(NotificationCompat.CATEGORY_SOCIAL) 317 .setContentIntent(pi) 318 .setSmallIcon(R.drawable.twitter_icon) 319 .setNumber(15) 320 .setPriority(NotificationCompat.PRIORITY_LOW) 321 .build()); 322 } 323 324 for (int i=0; i<mNotifications.size(); i++) { 325 noMa.notify(NOTIFICATION_ID + i, mNotifications.get(i)); 326 } 327 328 // always cancel any previous alarm 329 PendingIntent pendingCancel = makeCancelAllIntent(this); 330 AlarmManager alMa = (AlarmManager) getSystemService(Context.ALARM_SERVICE); 331 alMa.cancel(pendingCancel); 332 if(sharedPref.getBoolean(SettingsActivity.KEY_GLOBAL_FADE, false)) { 333 long t = SystemClock.elapsedRealtime() + FADE_TIME_MILLIS; 334 alMa.set(AlarmManager.ELAPSED_REALTIME, t, pendingCancel); 335 } 336 } 337 } 338