• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package com.android.documentsui.services;
17 
18 import android.app.Notification;
19 import android.app.PendingIntent;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.BroadcastReceiver;
24 import android.service.notification.NotificationListenerService;
25 import android.service.notification.StatusBarNotification;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.widget.FrameLayout;
29 import android.widget.ProgressBar;
30 import android.widget.RemoteViews;
31 
32 
33 /**
34 * This class receives a callback when Notification is posted or removed
35 * and monitors the Notification status.
36 * And, this sends the operation's result by Broadcast.
37 */
38 public class TestNotificationService extends NotificationListenerService {
39     public static final String ACTION_CHANGE_CANCEL_MODE =
40             "com.android.documentsui.services.TestNotificationService.ACTION_CHANGE_CANCEL_MODE";
41 
42     public static final String ACTION_CHANGE_EXECUTION_MODE =
43             "com.android.documentsui.services.TestNotificationService.ACTION_CHANGE_EXECUTION_MODE";
44 
45     public static final String ACTION_OPERATION_RESULT =
46             "com.android.documentsui.services.TestNotificationService.ACTION_OPERATION_RESULT";
47 
48     public static final String EXTRA_RESULT =
49             "com.android.documentsui.services.TestNotificationService.EXTRA_RESULT";
50 
51     public static final String EXTRA_ERROR_REASON =
52             "com.android.documentsui.services.TestNotificationService.EXTRA_ERROR_REASON";
53 
54     public enum MODE {
55         CANCEL_MODE,
56         EXECUTION_MODE;
57     }
58 
59     private String DOCUMENTSUI= "com.android.documentsui";
60 
61     private FrameLayout mFrameLayout = null;
62 
63     private ProgressBar mProgressBar = null;
64 
65     private MODE mCurrentMode = MODE.CANCEL_MODE;
66 
67     private boolean mCancelled = false;
68 
69     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
70         @Override
71         public void onReceive(Context context, Intent intent) {
72             String action = intent.getAction();
73             if (ACTION_CHANGE_CANCEL_MODE.equals(action)) {
74                 mCurrentMode = MODE.CANCEL_MODE;
75             } else if (ACTION_CHANGE_EXECUTION_MODE.equals(action)) {
76                 mCurrentMode = MODE.EXECUTION_MODE;
77             }
78         }
79     };
80 
81     @Override
onCreate()82     public void onCreate() {
83         mFrameLayout = new FrameLayout(getBaseContext());
84         IntentFilter filter = new IntentFilter();
85         filter.addAction(ACTION_CHANGE_CANCEL_MODE);
86         filter.addAction(ACTION_CHANGE_EXECUTION_MODE);
87         registerReceiver(mReceiver, filter);
88     }
89 
90     @Override
onStartCommand(Intent intent, int flags, int startId)91     public int onStartCommand(Intent intent, int flags, int startId) {
92         return START_STICKY;
93     }
94 
95     @Override
onDestroy()96     public void onDestroy() {
97         unregisterReceiver(mReceiver);
98         mProgressBar = null;
99         mFrameLayout.removeAllViews();
100         mFrameLayout = null;
101     }
102 
103     @Override
onNotificationPosted(StatusBarNotification sbn)104     public void onNotificationPosted(StatusBarNotification sbn) {
105         String pkgName = sbn.getPackageName();
106         if (!pkgName.equals(DOCUMENTSUI)) {
107             return;
108         }
109 
110         if (MODE.CANCEL_MODE.equals(mCurrentMode)) {
111             mCancelled = doCancel(sbn.getNotification());
112         }
113     }
114 
115     @Override
onNotificationRemoved(StatusBarNotification sbn)116     public void onNotificationRemoved(StatusBarNotification sbn) {
117         String pkgName = sbn.getPackageName();
118         if (!pkgName.equals(DOCUMENTSUI)) {
119             return;
120         }
121 
122         Intent intent = new Intent(ACTION_OPERATION_RESULT);
123         if (MODE.CANCEL_MODE.equals(mCurrentMode)) {
124             intent.putExtra(EXTRA_RESULT, mCancelled);
125             if (!mCancelled) {
126                 intent.putExtra(EXTRA_ERROR_REASON, "Cannot executed cancel");
127             }
128         } else if (MODE.EXECUTION_MODE.equals(mCurrentMode)) {
129             boolean isStartProgress = isStartProgress(sbn.getNotification());
130             intent.putExtra(EXTRA_RESULT, isStartProgress);
131             if (!isStartProgress) {
132                 intent.putExtra(EXTRA_ERROR_REASON, "Progress does not displayed correctly.");
133             }
134         }
135         sendBroadcast(intent);
136     }
137 
doCancel(Notification noti)138     private boolean doCancel(Notification noti) {
139         if (!isStartProgress(noti)) {
140             return false;
141         }
142 
143         Notification.Action aList [] = noti.actions;
144         if (aList == null) {
145             return false;
146         }
147 
148         boolean result = false;
149         for (Notification.Action item : aList) {
150             if (item.title.equals("Cancel")) {
151                 try {
152                     item.actionIntent.send();
153                     result = true;
154                 } catch (PendingIntent.CanceledException e) {
155                 }
156             }
157         }
158         return result;
159     }
160 
isStartProgress(Notification notifiction)161     private boolean isStartProgress(Notification notifiction) {
162         ProgressBar progressBar = getProgresssBar(getRemoteViews(notifiction));
163         return (progressBar != null) ? progressBar.getProgress() > 0 : false;
164     }
165 
getRemoteViews(Notification notifiction)166     private RemoteViews getRemoteViews(Notification notifiction) {
167         Notification.Builder builder = Notification.Builder.recoverBuilder(
168             getBaseContext(), notifiction);
169         if (builder == null) {
170             return null;
171         }
172 
173         return builder.createContentView();
174     }
175 
getProgresssBar(RemoteViews remoteViews)176     private ProgressBar getProgresssBar(RemoteViews remoteViews) {
177         if (remoteViews == null) {
178             return null;
179         }
180 
181         View view = remoteViews.apply(getBaseContext(), mFrameLayout);
182         return getProgressBarImpl(view);
183     }
184 
getProgressBarImpl(View view)185     private ProgressBar getProgressBarImpl(View view) {
186         if (view == null || !(view instanceof ViewGroup)) {
187             return null;
188         }
189 
190         ViewGroup viewGroup = (ViewGroup)view;
191         if (viewGroup.getChildCount() <= 0) {
192             return null;
193         }
194 
195         ProgressBar result = null;
196         for (int i = 0; i < viewGroup.getChildCount(); i++) {
197             View v = viewGroup.getChildAt(i);
198             if (v instanceof ProgressBar) {
199                 result = ((ProgressBar)v);
200                 break;
201             } else if (v instanceof ViewGroup) {
202                 result = getProgressBarImpl(v);
203                 if (result != null) {
204                     break;
205                 }
206             }
207         }
208         return result;
209     }
210 }
211 
212