导入/导出联系人过程,notification创建都是在com.android.contacts.common.vcard.NotificationImportExportListener中。

1 /* 2 * Copyright (C) 2011 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.contacts.common.vcard; 18 19 import android.app.Activity; 20 import android.app.Notification; 21 import android.app.NotificationManager; 22 import android.app.PendingIntent; 23 import android.content.ContentUris; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.net.Uri; 27 import android.os.Handler; 28 import android.os.Message; 29 import android.provider.ContactsContract.RawContacts; 30 import android.widget.Toast; 31 32 import com.android.contacts.common.R; 33 import com.android.vcard.VCardEntry; 34 35 public class NotificationImportExportListener implements VCardImportExportListener, 36 Handler.Callback { 37 /** The tag used by vCard-related notifications. */ 38 /* package */ static final String DEFAULT_NOTIFICATION_TAG = "VCardServiceProgress"; 39 /** 40 * The tag used by vCard-related failure notifications. 41 * <p> 42 * Use a different tag from {@link #DEFAULT_NOTIFICATION_TAG} so that failures do not get 43 * replaced by other notifications and vice-versa. 44 */ 45 /* package */ static final String FAILURE_NOTIFICATION_TAG = "VCardServiceFailure"; 46 47 private final NotificationManager mNotificationManager; 48 private final Activity mContext; 49 private final Handler mHandler; 50 51 public NotificationImportExportListener(Activity activity) { 52 mContext = activity; 53 mNotificationManager = (NotificationManager) activity.getSystemService( 54 Context.NOTIFICATION_SERVICE); 55 mHandler = new Handler(this); 56 } 57 58 @Override 59 public boolean handleMessage(Message msg) { 60 String text = (String) msg.obj; 61 Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); 62 return true; 63 } 64 65 @Override 66 public void onImportProcessed(ImportRequest request, int jobId, int sequence) { 67 // Show a notification about the status 68 final String displayName; 69 final String message; 70 if (request.displayName != null) { 71 displayName = request.displayName; 72 message = mContext.getString(R.string.vcard_import_will_start_message, displayName); 73 } else { 74 displayName = mContext.getString(R.string.vcard_unknown_filename); 75 message = mContext.getString( 76 R.string.vcard_import_will_start_message_with_default_name); 77 } 78 79 // We just want to show notification for the first vCard. 80 if (sequence == 0) { 81 // TODO: Ideally we should detect the current status of import/export and 82 // show "started" when we can import right now and show "will start" when 83 // we cannot. 84 mHandler.obtainMessage(0, message).sendToTarget(); 85 } 86 87 final Notification notification = constructProgressNotification(mContext, 88 VCardService.TYPE_IMPORT, message, message, jobId, displayName, -1, 0); 89 mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification); 90 } 91 92 @Override 93 public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount, 94 int totalCount) { 95 if (entry.isIgnorable()) { 96 return; 97 } 98 99 if(currentCount!=totalCount && currentCount%100 !=1 ) return ;//for slow down the notification speed 100 101 final String totalCountString = String.valueOf(totalCount); 102 //modified ------ 103 /*final String tickerText = 104 mContext.getString(R.string.progress_notifier_message, 105 String.valueOf(currentCount), 106 totalCountString, 107 entry.getDisplayName()); 108 final String description = mContext.getString(R.string.importing_vcard_description, 109 entry.getDisplayName());*/ 110 final String tickerText =mContext.getString(R.string.progress_notifier_message_importing); 111 final String description = tickerText; 112 //end modified ------ 113 final Notification notification = constructProgressNotification( 114 mContext.getApplicationContext(), VCardService.TYPE_IMPORT, description, tickerText, 115 jobId, request.displayName, totalCount, currentCount); 116 mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification); 117 } 118 119 @Override 120 public void onImportFinished(ImportRequest request, int jobId, Uri createdUri) { 121 final String description = mContext.getString(R.string.importing_vcard_finished_title, 122 request.displayName); 123 final Intent intent; 124 if (createdUri != null) { 125 final long rawContactId = ContentUris.parseId(createdUri); 126 final Uri contactUri = RawContacts.getContactLookupUri( 127 mContext.getContentResolver(), ContentUris.withAppendedId( 128 RawContacts.CONTENT_URI, rawContactId)); 129 intent = new Intent(Intent.ACTION_VIEW, contactUri); 130 } else { 131 intent = null; 132 } 133 final Notification notification = 134 NotificationImportExportListener.constructFinishNotification(mContext, 135 VCardService.TYPE_IMPORT, description, null, intent); 136 mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG, 137 jobId, notification); 138 } 139 140 @Override 141 public void onImportFailed(ImportRequest request) { 142 // TODO: a little unkind to show Toast in this case, which is shown just a moment. 143 // Ideally we should show some persistent something users can notice more easily. 144 mHandler.obtainMessage(0, 145 mContext.getString(R.string.vcard_import_request_rejected_message)).sendToTarget(); 146 } 147 148 @Override 149 public void onImportCanceled(ImportRequest request, int jobId) { 150 final String description = mContext.getString(R.string.importing_vcard_canceled_title, 151 request.displayName); 152 final Notification notification = 153 NotificationImportExportListener.constructCancelNotification(mContext, description); 154 mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG, 155 jobId, notification); 156 } 157 158 @Override 159 public void onExportProcessed(ExportRequest request, int jobId) { 160 final String displayName = request.destUri.getLastPathSegment(); 161 final String message = mContext.getString(R.string.vcard_export_will_start_message, 162 displayName); 163 164 mHandler.obtainMessage(0, message).sendToTarget(); 165 final Notification notification = 166 NotificationImportExportListener.constructProgressNotification(mContext, 167 VCardService.TYPE_EXPORT, message, message, jobId, displayName, -1, 0); 168 mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification); 169 } 170 171 @Override 172 public void onExportFailed(ExportRequest request) { 173 mHandler.obtainMessage(0, 174 mContext.getString(R.string.vcard_export_request_rejected_message)).sendToTarget(); 175 } 176 177 @Override 178 public void onCancelRequest(CancelRequest request, int type) { 179 final String description = type == VCardService.TYPE_IMPORT ? 180 mContext.getString(R.string.importing_vcard_canceled_title, request.displayName) : 181 mContext.getString(R.string.exporting_vcard_canceled_title, request.displayName); 182 final Notification notification = constructCancelNotification(mContext, description); 183 mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, request.jobId, notification); 184 } 185 186 /** 187 * Constructs a {@link Notification} showing the current status of import/export. 188 * Users can cancel the process with the Notification. 189 * 190 * @param context 191 * @param type import/export 192 * @param description Content of the Notification. 193 * @param tickerText 194 * @param jobId 195 * @param displayName Name to be shown to the Notification (e.g. "finished importing XXXX"). 196 * Typycally a file name. 197 * @param totalCount The number of vCard entries to be imported. Used to show progress bar. 198 * -1 lets the system show the progress bar with "indeterminate" state. 199 * @param currentCount The index of current vCard. Used to show progress bar. 200 */ 201 /* package */ static Notification constructProgressNotification( 202 Context context, int type, String description, String tickerText, 203 int jobId, String displayName, int totalCount, int currentCount) { 204 // Note: We cannot use extra values here (like setIntExtra()), as PendingIntent doesn't 205 // preserve them across multiple Notifications. PendingIntent preserves the first extras 206 // (when flag is not set), or update them when PendingIntent#getActivity() is called 207 // (See PendingIntent#FLAG_UPDATE_CURRENT). In either case, we cannot preserve extras as we 208 // expect (for each vCard import/export request). 209 // 210 // We use query parameter in Uri instead. 211 // Scheme and Authority is arbitorary, assuming CancelActivity never refers them. 212 final Intent intent = new Intent(context, CancelActivity.class); 213 final Uri uri = (new Uri.Builder()) 214 .scheme("invalidscheme") 215 .authority("invalidauthority") 216 .appendQueryParameter(CancelActivity.JOB_ID, String.valueOf(jobId)) 217 .appendQueryParameter(CancelActivity.DISPLAY_NAME, displayName) 218 .appendQueryParameter(CancelActivity.TYPE, String.valueOf(type)).build(); 219 intent.setData(uri); 220 221 final Notification.Builder builder = new Notification.Builder(context); 222 builder.setOngoing(true) 223 .setProgress(totalCount, currentCount, totalCount == - 1) 224 .setTicker(tickerText) 225 .setContentTitle(description) 226 .setSmallIcon(type == VCardService.TYPE_IMPORT 227 ? android.R.drawable.stat_sys_download 228 : android.R.drawable.stat_sys_upload) 229 .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0)); 230 if (totalCount > 0) { 231 builder.setContentText(context.getString(R.string.percentage, 232 String.valueOf(currentCount * 100 / totalCount))); 233 } 234 return builder.getNotification(); 235 } 236 237 /** 238 * Constructs a Notification telling users the process is canceled. 239 * 240 * @param context 241 * @param description Content of the Notification 242 */ 243 /* package */ static Notification constructCancelNotification( 244 Context context, String description) { 245 return new Notification.Builder(context) 246 .setAutoCancel(true) 247 .setSmallIcon(android.R.drawable.stat_notify_error) 248 .setContentTitle(description) 249 .setContentText(description) 250 .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(), 0)) 251 .getNotification(); 252 } 253 254 /** 255 * Constructs a Notification telling users the process is finished. 256 * 257 * @param context 258 * @param description Content of the Notification 259 * @param intent Intent to be launched when the Notification is clicked. Can be null. 260 */ 261 /* package */ static Notification constructFinishNotification( 262 Context context, int type, String title, String description, Intent intent) { 263 return new Notification.Builder(context) 264 .setAutoCancel(true) 265 .setSmallIcon(type == VCardService.TYPE_IMPORT 266 ? android.R.drawable.stat_sys_download_done 267 : android.R.drawable.stat_sys_upload_done) 268 .setContentTitle(title) 269 .setContentText(description) 270 .setContentIntent(PendingIntent.getActivity(context, 0, 271 (intent != null ? intent : new Intent()), 0)) 272 .getNotification(); 273 } 274 275 /** 276 * Constructs a Notification telling the vCard import has failed. 277 * 278 * @param context 279 * @param reason The reason why the import has failed. Shown in description field. 280 */ 281 /* package */ static Notification constructImportFailureNotification( 282 Context context, String reason) { 283 return new Notification.Builder(context) 284 .setAutoCancel(true) 285 .setSmallIcon(android.R.drawable.stat_notify_error) 286 .setContentTitle(context.getString(R.string.vcard_import_failed)) 287 .setContentText(reason) 288 .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(), 0)) 289 .getNotification(); 290 } 291 292 @Override 293 public void onComplete() { 294 mContext.finish(); 295 } 296 }
导入联系人:
处理每个Vcard文件时的通知(每个Vcard对应一条单独的通知,排队Import)
1 public void onImportProcessed(ImportRequest request, int jobId, int sequence) { 2 // Show a notification about the status 3 final String displayName; 4 final String message; 5 if (request.displayName != null) { 6 displayName = request.displayName; 7 message = mContext.getString(R.string.vcard_import_will_start_message, displayName); 8 } else { 9 displayName = mContext.getString(R.string.vcard_unknown_filename); 10 message = mContext.getString( 11 R.string.vcard_import_will_start_message_with_default_name); 12 } 13 14 // We just want to show notification for the first vCard. 15 if (sequence == 0) { 16 // TODO: Ideally we should detect the current status of import/export and 17 // show "started" when we can import right now and show "will start" when 18 // we cannot. 19 mHandler.obtainMessage(0, message).sendToTarget(); 20 } 21 22 final Notification notification = constructProgressNotification(mContext, 23 VCardService.TYPE_IMPORT, message, message, jobId, displayName, -1, 0); 24 mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification); 25 }
处理具体Vcard文件中每个contact时的通知(百分比进度条显示):
1 public void onImportParsed(ImportRequest request, int jobId, VCardEntry entry, int currentCount, 2 int totalCount) { 3 if (entry.isIgnorable()) { 4 return; 5 } 6 7 if(currentCount!=totalCount && currentCount%100 !=1 ) return ;//slow down the notification speed 8 9 final String totalCountString = String.valueOf(totalCount); 10 //modified 11 /*final String tickerText = 12 mContext.getString(R.string.progress_notifier_message, 13 String.valueOf(currentCount), 14 totalCountString, 15 entry.getDisplayName()); 16 final String description = mContext.getString(R.string.importing_vcard_description, 17 entry.getDisplayName());*/ 18 final String tickerText =mContext.getString(R.string.progress_notifier_message_importing); 19 final String description = tickerText; 20 //end modified 21 final Notification notification = constructProgressNotification( 22 mContext.getApplicationContext(), VCardService.TYPE_IMPORT, description, tickerText, 23 jobId, request.displayName, totalCount, currentCount); 24 mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification); 25 }
----------------------------------------------------分割线----------------------------------------------------
导出联系人:
总的提示
1 public void onExportProcessed(ExportRequest request, int jobId) { 2 final String displayName = request.destUri.getLastPathSegment(); 3 final String message = mContext.getString(R.string.vcard_export_will_start_message, 4 displayName); 5 6 mHandler.obtainMessage(0, message).sendToTarget(); 7 final Notification notification = 8 NotificationImportExportListener.constructProgressNotification(mContext, 9 VCardService.TYPE_EXPORT, message, message, jobId, displayName, -1, 0); 10 mNotificationManager.notify(DEFAULT_NOTIFICATION_TAG, jobId, notification); 11 }
具体每个Contact导出提示(百分比进度条显示):
在com.android.contacts.common.vcard.ExportProcessor中处理
1 private void doProgressNotification(Uri uri, int totalCount, int currentCount) { 2 final String displayName = uri.getLastPathSegment(); 3 final String description = 4 mService.getString(R.string.exporting_contact_list_message, displayName); 5 final String tickerText = 6 mService.getString(R.string.exporting_contact_list_title); 7 final Notification notification = 8 NotificationImportExportListener.constructProgressNotification(mService, 9 VCardService.TYPE_EXPORT, description, tickerText, mJobId, displayName, 10 totalCount, currentCount); 11 mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG, 12 mJobId, notification); 13 }
总结:导入导出联系人notification显示——对contacts总数进行while循环,每次循环都会new一个notificaiton,所以通知栏可以看到notification一闪一闪的显示。
而通知栏下载进度条却是进度条更新显示,notification条不闪烁,UI效果更好。