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 
17 package com.android.systemui;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageManager;
26 import android.net.Uri;
27 import android.os.Bundle;
28 import android.provider.Settings;
29 import android.util.IconDrawableFactory;
30 import android.util.Log;
31 import android.view.LayoutInflater;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.widget.AdapterView;
35 import android.widget.ArrayAdapter;
36 import android.widget.ImageView;
37 import android.widget.ListView;
38 import android.widget.TextView;
39 
40 import com.android.internal.app.AlertActivity;
41 import com.android.internal.app.AlertController;
42 import com.android.internal.logging.MetricsLogger;
43 import com.android.internal.logging.nano.MetricsProto;
44 import com.android.systemui.res.R;
45 
46 import java.util.ArrayList;
47 
48 import javax.inject.Inject;
49 
50 /**
51  * Show a list of currently running foreground services (supplied by the caller)
52  * that the user can tap through to their application details.
53  */
54 public final class ForegroundServicesDialog extends AlertActivity implements
55         AdapterView.OnItemSelectedListener, DialogInterface.OnClickListener,
56         AlertController.AlertParams.OnPrepareListViewListener {
57 
58     private static final String TAG = "ForegroundServicesDialog";
59 
60     LayoutInflater mInflater;
61 
62     private final MetricsLogger mMetricsLogger;
63 
64     private String[] mPackages;
65     private PackageItemAdapter mAdapter;
66 
67     private DialogInterface.OnClickListener mAppClickListener =
68             new DialogInterface.OnClickListener() {
69                 public void onClick(DialogInterface dialog, int which) {
70                     String pkg = mAdapter.getItem(which).packageName;
71                     Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
72                     intent.setData(Uri.fromParts("package", pkg, null));
73                     startActivity(intent);
74                     finish();
75                 }
76             };
77 
78     @Inject
ForegroundServicesDialog(MetricsLogger metricsLogger)79     ForegroundServicesDialog(MetricsLogger metricsLogger) {
80         super();
81         mMetricsLogger = metricsLogger;
82     }
83 
84     @Override
onCreate(Bundle savedInstanceState)85     protected void onCreate(Bundle savedInstanceState) {
86         super.onCreate(savedInstanceState);
87 
88         mInflater = LayoutInflater.from(this);
89 
90         mAdapter = new PackageItemAdapter(this);
91 
92         final AlertController.AlertParams p = mAlertParams;
93         p.mAdapter = mAdapter;
94         p.mOnClickListener = mAppClickListener;
95         p.mCustomTitleView = mInflater.inflate(R.layout.foreground_service_title, null);
96         p.mIsSingleChoice = true;
97         p.mOnItemSelectedListener = this;
98         p.mPositiveButtonText = getString(com.android.internal.R.string.done_label);
99         p.mPositiveButtonListener = this;
100         p.mOnPrepareListViewListener = this;
101 
102         updateApps(getIntent());
103         if (mPackages == null) {
104             Log.w(TAG, "No packages supplied");
105             finish();
106             return;
107         }
108 
109         setupAlert();
110     }
111 
112     @Override
onResume()113     protected void onResume() {
114         super.onResume();
115         mMetricsLogger.visible(MetricsProto.MetricsEvent.RUNNING_BACKGROUND_APPS_DIALOG);
116     }
117 
118     @Override
onPause()119     protected void onPause() {
120         super.onPause();
121         mMetricsLogger.hidden(MetricsProto.MetricsEvent.RUNNING_BACKGROUND_APPS_DIALOG);
122     }
123 
124     @Override
onNewIntent(Intent intent)125     protected void onNewIntent(Intent intent) {
126         super.onNewIntent(intent);
127         updateApps(intent);
128     }
129 
130     @Override
onStop()131     protected void onStop() {
132         super.onStop();
133 
134         // This is a transient dialog, if the user leaves it then it goes away,
135         // they can return back to it from the notification.
136         if (!isChangingConfigurations()) {
137             finish();
138         }
139     }
140 
updateApps(Intent intent)141     void updateApps(Intent intent) {
142         mPackages = intent.getStringArrayExtra("packages");
143         if (mPackages != null) {
144             mAdapter.setPackages(mPackages);
145         }
146     }
147 
onPrepareListView(ListView listView)148     public void onPrepareListView(ListView listView) {
149     }
150 
151     /*
152      * On click of Ok/Cancel buttons
153      */
onClick(DialogInterface dialog, int which)154     public void onClick(DialogInterface dialog, int which) {
155         finish();
156     }
157 
onItemSelected(AdapterView parent, View view, int position, long id)158     public void onItemSelected(AdapterView parent, View view, int position, long id) {
159     }
160 
onNothingSelected(AdapterView parent)161     public void onNothingSelected(AdapterView parent) {
162     }
163 
164     static private class PackageItemAdapter extends ArrayAdapter<ApplicationInfo> {
165         final PackageManager mPm;
166         final LayoutInflater mInflater;
167         final IconDrawableFactory mIconDrawableFactory;
168 
PackageItemAdapter(Context context)169         public PackageItemAdapter(Context context) {
170             super(context, R.layout.foreground_service_item);
171             mPm = context.getPackageManager();
172             mInflater = LayoutInflater.from(context);
173             mIconDrawableFactory = IconDrawableFactory.newInstance(context, true);
174         }
175 
setPackages(String[] packages)176         public void setPackages(String[] packages) {
177             clear();
178 
179             ArrayList<ApplicationInfo> apps = new ArrayList<>();
180             for (int i = 0; i < packages.length; i++) {
181                 try {
182                     apps.add(mPm.getApplicationInfo(packages[i],
183                             PackageManager.MATCH_KNOWN_PACKAGES));
184                 } catch (PackageManager.NameNotFoundException e) {
185                 }
186             }
187 
188             apps.sort(new ApplicationInfo.DisplayNameComparator(mPm));
189             addAll(apps);
190         }
191 
192         public @NonNull
getView(int position, @Nullable View convertView, @NonNull ViewGroup parent)193         View getView(int position, @Nullable View convertView,
194                 @NonNull ViewGroup parent) {
195             final View view;
196             if (convertView == null) {
197                 view = mInflater.inflate(R.layout.foreground_service_item, parent, false);
198             } else {
199                 view = convertView;
200             }
201 
202             ImageView icon = view.findViewById(R.id.app_icon);
203             icon.setImageDrawable(mIconDrawableFactory.getBadgedIcon(getItem(position)));
204 
205             TextView label = view.findViewById(R.id.app_name);
206             label.setText(getItem(position).loadLabel(mPm));
207 
208             return view;
209         }
210     }
211 }
212