1 /*
2 * Copyright 2014 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.example.android.lnotifications;
18 
19 import android.app.Activity;
20 import android.app.Fragment;
21 import android.app.Notification;
22 import android.app.NotificationManager;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.database.Cursor;
26 import android.graphics.Bitmap;
27 import android.graphics.drawable.BitmapDrawable;
28 import android.graphics.drawable.Drawable;
29 import android.net.Uri;
30 import android.os.Bundle;
31 import android.provider.ContactsContract;
32 import android.provider.MediaStore;
33 import android.util.Log;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.widget.ArrayAdapter;
38 import android.widget.Button;
39 import android.widget.ImageView;
40 import android.widget.Spinner;
41 import android.widget.TextView;
42 import android.widget.Toast;
43 
44 import java.io.IOException;
45 import java.util.Random;
46 
47 /**
48  * Fragment that demonstrates how to attach metadata introduced in Android L, such as
49  * priority data, notification category and person data.
50  */
51 public class OtherMetadataFragment extends Fragment {
52 
53     private static final String TAG = OtherMetadataFragment.class.getSimpleName();
54 
55     /**
56      * Request code used for picking a contact.
57      */
58     public static final int REQUEST_CODE_PICK_CONTACT = 1;
59 
60     /**
61      * Incremental Integer used for ID for notifications so that each notification will be
62      * treated differently.
63      */
64     private Integer mIncrementalNotificationId = Integer.valueOf(0);
65 
66     private NotificationManager mNotificationManager;
67 
68     /**
69      * Button to show a notification.
70      */
71     private Button mShowNotificationButton;
72 
73     /**
74      *  Spinner that holds possible categories used for a notification as
75      *  {@link Notification.Builder#setCategory(String)}.
76      */
77     private Spinner mCategorySpinner;
78 
79     /**
80      * Spinner that holds possible priorities used for a notification as
81      * {@link Notification.Builder#setPriority(int)}.
82      */
83     private Spinner mPrioritySpinner;
84 
85     /**
86      * Holds a URI for the person to be attached to the notification.
87      */
88     //@VisibleForTesting
89     Uri mContactUri;
90 
91     /**
92      * Use this factory method to create a new instance of
93      * this fragment using the provided parameters.
94      *
95      * @return A new instance of fragment NotificationFragment.
96      */
newInstance()97     public static OtherMetadataFragment newInstance() {
98         OtherMetadataFragment fragment = new OtherMetadataFragment();
99         fragment.setRetainInstance(true);
100         return fragment;
101     }
102 
OtherMetadataFragment()103     public OtherMetadataFragment() {
104         // Required empty public constructor
105     }
106 
107     @Override
onCreate(Bundle savedInstanceState)108     public void onCreate(Bundle savedInstanceState) {
109         super.onCreate(savedInstanceState);
110         mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
111                 .NOTIFICATION_SERVICE);
112     }
113 
114     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)115     public View onCreateView(LayoutInflater inflater, ViewGroup container,
116                              Bundle savedInstanceState) {
117         // Inflate the layout for this fragment
118         return inflater.inflate(R.layout.fragment_other_metadata, container, false);
119     }
120 
121     @Override
onViewCreated(View view, Bundle savedInstanceState)122     public void onViewCreated(View view, Bundle savedInstanceState) {
123         super.onViewCreated(view, savedInstanceState);
124         mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
125         mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
126             @Override
127             public void onClick(View view) {
128                 Priority selectedPriority = (Priority) mPrioritySpinner.getSelectedItem();
129                 Category selectedCategory = (Category) mCategorySpinner.getSelectedItem();
130                 showNotificationClicked(selectedPriority, selectedCategory, mContactUri);
131             }
132         });
133 
134         mCategorySpinner = (Spinner) view.findViewById(R.id.category_spinner);
135         ArrayAdapter<Category> categoryArrayAdapter = new ArrayAdapter<Category>(getActivity(),
136                 android.R.layout.simple_spinner_item, Category.values());
137         categoryArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
138         mCategorySpinner.setAdapter(categoryArrayAdapter);
139 
140         mPrioritySpinner = (Spinner) view.findViewById(R.id.priority_spinner);
141         ArrayAdapter<Priority> priorityArrayAdapter = new ArrayAdapter<Priority>(getActivity(),
142                 android.R.layout.simple_spinner_item, Priority.values());
143         priorityArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
144         mPrioritySpinner.setAdapter(priorityArrayAdapter);
145 
146         view.findViewById(R.id.attach_person).setOnClickListener(new View.OnClickListener() {
147             @Override
148             public void onClick(View view) {
149                 findContact();
150             }
151         });
152 
153         view.findViewById(R.id.contact_entry).setVisibility(View.GONE);
154     }
155 
156     @Override
onActivityResult(int requestCode, int resultCode, Intent data)157     public void onActivityResult(int requestCode, int resultCode, Intent data) {
158         super.onActivityResult(requestCode, resultCode, data);
159         switch (requestCode) {
160             case REQUEST_CODE_PICK_CONTACT:
161                 if (resultCode == Activity.RESULT_OK) {
162                     Uri contactUri = data.getData();
163                     mContactUri = contactUri;
164                     updateContactEntryFromUri(contactUri);
165                 }
166                 break;
167         }
168     }
169 
170     /**
171      * Invoked when {@link #mShowNotificationButton} is clicked.
172      * Creates a new notification and sets metadata passed as arguments.
173      *
174      * @param priority   The priority metadata.
175      * @param category   The category metadata.
176      * @param contactUri The URI to be added to the new notification as metadata.
177      *
178      * @return A Notification instance.
179      */
180     //@VisibleForTesting
createNotification(Priority priority, Category category, Uri contactUri)181     Notification createNotification(Priority priority, Category category, Uri contactUri) {
182         Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
183                 .setContentTitle("Notification with other metadata")
184                 .setSmallIcon(R.drawable.ic_launcher_notification)
185                 .setPriority(priority.value)
186                 .setCategory(category.value)
187                 .setContentText(String.format("Category %s, Priority %s", category.value,
188                         priority.name()));
189         if (contactUri != null) {
190             notificationBuilder.addPerson(contactUri.toString());
191             Bitmap photoBitmap = loadBitmapFromContactUri(contactUri);
192             if (photoBitmap != null) {
193                 notificationBuilder.setLargeIcon(photoBitmap);
194             }
195         }
196         return notificationBuilder.build();
197     }
198 
199     /**
200      * Invoked when {@link #mShowNotificationButton} is clicked.
201      * Creates a new notification and sets metadata passed as arguments.
202      *
203      * @param priority   The priority metadata.
204      * @param category   The category metadata.
205      * @param contactUri The URI to be added to the new notification as metadata.
206      */
showNotificationClicked(Priority priority, Category category, Uri contactUri)207     private void showNotificationClicked(Priority priority, Category category, Uri contactUri) {
208         // Assigns a unique (incremented) notification ID in order to treat each notification as a
209         // different one. This helps demonstrate how a priority flag affects ordering.
210         mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
211         mNotificationManager.notify(mIncrementalNotificationId, createNotification(priority,
212                 category, contactUri));
213         Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
214     }
215 
findContact()216     private void findContact() {
217         Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
218         startActivityForResult(intent, REQUEST_CODE_PICK_CONTACT);
219     }
220 
221     /**
222      * Returns a {@link Bitmap} from the Uri specified as the argument.
223      *
224      * @param contactUri The Uri from which the result Bitmap is created.
225      * @return The {@link Bitmap} instance retrieved from the contactUri.
226      */
loadBitmapFromContactUri(Uri contactUri)227     private Bitmap loadBitmapFromContactUri(Uri contactUri) {
228         if (contactUri == null) {
229             return null;
230         }
231         Bitmap result = null;
232         Cursor cursor = getActivity().getContentResolver().query(contactUri, null, null, null,
233                 null);
234         if (cursor != null && cursor.moveToFirst()) {
235             int idx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
236             String hasPhoto = cursor.getString(idx);
237             Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
238                     .CONTENT_DIRECTORY);
239             if (hasPhoto != null) {
240                 try {
241                     result = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver()
242                             , photoUri);
243                 } catch (IOException e) {
244                     Log.e(TAG, String.format("Failed to load resource. Uri %s", photoUri), e);
245                 }
246             } else {
247                 Drawable defaultContactDrawable = getActivity().getResources().getDrawable(R
248                         .drawable.ic_contact_picture);
249                 result = ((BitmapDrawable) defaultContactDrawable).getBitmap();
250             }
251         }
252         return result;
253     }
254 
255     /**
256      * Updates the Contact information on the screen when a contact is picked.
257      *
258      * @param contactUri The Uri from which the contact is retrieved.
259      */
updateContactEntryFromUri(Uri contactUri)260     private void updateContactEntryFromUri(Uri contactUri) {
261         Cursor cursor = getActivity().getContentResolver().query(contactUri, null, null, null,
262                 null);
263         if (cursor != null && cursor.moveToFirst()) {
264             int idx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
265             String name = cursor.getString(idx);
266             idx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
267             String hasPhoto = cursor.getString(idx);
268 
269             Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
270                     .CONTENT_DIRECTORY);
271             ImageView contactPhoto = (ImageView) getActivity().findViewById(R.id.contact_photo);
272             if (hasPhoto != null) {
273                 contactPhoto.setImageURI(photoUri);
274             } else {
275                 Drawable defaultContactDrawable = getActivity().getResources().getDrawable(R
276                         .drawable.ic_contact_picture);
277                 contactPhoto.setImageDrawable(defaultContactDrawable);
278             }
279             TextView contactName = (TextView) getActivity().findViewById(R.id.contact_name);
280             contactName.setText(name);
281 
282             getActivity().findViewById(R.id.contact_entry).setVisibility(View.VISIBLE);
283             getActivity().findViewById(R.id.attach_person).setVisibility(View.GONE);
284             getActivity().findViewById(R.id.click_to_change).setOnClickListener(new View.OnClickListener() {
285                 @Override
286                 public void onClick(View view) {
287                     findContact();
288                 }
289             });
290             Log.i(TAG, String.format("Contact updated. Name %s, PhotoUri %s", name, photoUri));
291         }
292     }
293 
294     /**
295      * Enum indicating possible categories in {@link Notification} used from
296      * {@link #mCategorySpinner}.
297      */
298     //@VisibleForTesting
299     static enum Category {
300         ALARM("alarm"),
301         CALL("call"),
302         EMAIL("email"),
303         ERROR("err"),
304         EVENT("event"),
305         MESSAGE("msg"),
306         PROGRESS("progress"),
307         PROMO("promo"),
308         RECOMMENDATION("recommendation"),
309         SERVICE("service"),
310         SOCIAL("social"),
311         STATUS("status"),
312         SYSTEM("sys"),
313         TRANSPORT("transport");
314 
315         private final String value;
316 
Category(String value)317         Category(String value) {
318             this.value = value;
319         }
320 
321         @Override
toString()322         public String toString() {
323             return value;
324         }
325     }
326 
327     /**
328      * Enum indicating possible priorities in {@link Notification} used from
329      * {@link #mPrioritySpinner}.
330      */
331     //@VisibleForTesting
332     static enum Priority {
333         DEFAULT(Notification.PRIORITY_DEFAULT),
334         MAX(Notification.PRIORITY_MAX),
335         HIGH(Notification.PRIORITY_HIGH),
336         LOW(Notification.PRIORITY_LOW),
337         MIN(Notification.PRIORITY_MIN);
338 
339         private final int value;
340 
Priority(int value)341         Priority(int value) {
342             this.value = value;
343         }
344     }
345 }
346