blob: 3b9324df31c35f5359261b02dd3ebbed134cb965 [file] [log] [blame]
Maggieca80da22018-01-29 20:29:16 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14package com.android.settings.location;
15
Maggieca80da22018-01-29 20:29:16 -080016import android.content.Context;
17import android.content.Intent;
18import android.content.pm.ActivityInfo;
19import android.content.pm.ApplicationInfo;
20import android.content.pm.PackageManager;
21import android.content.pm.PackageManager.NameNotFoundException;
22import android.content.pm.ResolveInfo;
23import android.location.LocationManager;
Maggieca80da22018-01-29 20:29:16 -080024import android.util.Log;
Fan Zhangc7162cd2018-06-18 15:21:41 -070025
Fan Zhang23f8d592018-08-28 15:11:40 -070026import androidx.preference.Preference;
27import androidx.preference.PreferenceCategory;
28
Maggieca80da22018-01-29 20:29:16 -080029import com.android.settingslib.widget.FooterPreference;
Fan Zhangc7162cd2018-06-18 15:21:41 -070030
Maggieca80da22018-01-29 20:29:16 -080031import java.util.ArrayList;
32import java.util.Collection;
33import java.util.Collections;
34import java.util.List;
35
Maggieca80da22018-01-29 20:29:16 -080036/**
37 * Preference controller for location footer preference category
38 */
Soonil Nagarkar533a17f2019-07-10 15:11:02 -070039public class LocationFooterPreferenceController extends LocationBasePreferenceController {
40
Maggieca80da22018-01-29 20:29:16 -080041 private static final String TAG = "LocationFooter";
Maggieca80da22018-01-29 20:29:16 -080042 private static final Intent INJECT_INTENT =
43 new Intent(LocationManager.SETTINGS_FOOTER_DISPLAYED_ACTION);
Maggieca80da22018-01-29 20:29:16 -080044
Soonil Nagarkar533a17f2019-07-10 15:11:02 -070045 private final PackageManager mPackageManager;
46
Raff Tsai22295852019-11-22 11:35:40 +080047 public LocationFooterPreferenceController(Context context, String key) {
48 super(context, key);
Soonil Nagarkar533a17f2019-07-10 15:11:02 -070049 mPackageManager = context.getPackageManager();
Maggieca80da22018-01-29 20:29:16 -080050 }
51
Maggieca80da22018-01-29 20:29:16 -080052 /**
Soonil Nagarkar533a17f2019-07-10 15:11:02 -070053 * Insert footer preferences.
Maggieca80da22018-01-29 20:29:16 -080054 */
55 @Override
56 public void updateState(Preference preference) {
57 PreferenceCategory category = (PreferenceCategory) preference;
58 category.removeAll();
Maggieca80da22018-01-29 20:29:16 -080059 Collection<FooterData> footerData = getFooterData();
60 for (FooterData data : footerData) {
Maggieca80da22018-01-29 20:29:16 -080061 try {
Soonil Nagarkar533a17f2019-07-10 15:11:02 -070062 String footerString =
Maggieca80da22018-01-29 20:29:16 -080063 mPackageManager
64 .getResourcesForApplication(data.applicationInfo)
65 .getString(data.footerStringRes);
Soonil Nagarkar533a17f2019-07-10 15:11:02 -070066
67 // Generate a footer preference with the given text
68 FooterPreference footerPreference = new FooterPreference(preference.getContext());
69 footerPreference.setTitle(footerString);
70 category.addPreference(footerPreference);
Maggieca80da22018-01-29 20:29:16 -080071 } catch (NameNotFoundException exception) {
Soonil Nagarkarc5dd4e52019-03-25 10:50:16 -070072 Log.w(
73 TAG,
74 "Resources not found for application "
75 + data.applicationInfo.packageName);
Maggieca80da22018-01-29 20:29:16 -080076 }
Maggieca80da22018-01-29 20:29:16 -080077 }
78 }
79
80 /**
81 * Do nothing on location mode changes.
82 */
83 @Override
84 public void onLocationModeChanged(int mode, boolean restricted) {}
85
86 /**
87 * Location footer preference group should be displayed if there is at least one footer to
88 * inject.
89 */
90 @Override
Raff Tsai22295852019-11-22 11:35:40 +080091 public int getAvailabilityStatus() {
92 return !getFooterData().isEmpty() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
Maggieca80da22018-01-29 20:29:16 -080093 }
94
95 /**
Maggieca80da22018-01-29 20:29:16 -080096 * Return a list of strings with text provided by ACTION_INJECT_FOOTER broadcast receivers.
97 */
Soonil Nagarkar533a17f2019-07-10 15:11:02 -070098 private List<FooterData> getFooterData() {
Maggieca80da22018-01-29 20:29:16 -080099 // Fetch footer text from system apps
Soonil Nagarkar533a17f2019-07-10 15:11:02 -0700100 List<ResolveInfo> resolveInfos =
Maggieca80da22018-01-29 20:29:16 -0800101 mPackageManager.queryBroadcastReceivers(
102 INJECT_INTENT, PackageManager.GET_META_DATA);
103 if (resolveInfos == null) {
Soonil Nagarkarc5dd4e52019-03-25 10:50:16 -0700104 Log.e(TAG, "Unable to resolve intent " + INJECT_INTENT);
105 return Collections.emptyList();
106 }
107
108 if (Log.isLoggable(TAG, Log.DEBUG)) {
Maggieca80da22018-01-29 20:29:16 -0800109 Log.d(TAG, "Found broadcast receivers: " + resolveInfos);
110 }
111
Soonil Nagarkar533a17f2019-07-10 15:11:02 -0700112 List<FooterData> footerDataList = new ArrayList<>(resolveInfos.size());
Maggieca80da22018-01-29 20:29:16 -0800113 for (ResolveInfo resolveInfo : resolveInfos) {
Soonil Nagarkar533a17f2019-07-10 15:11:02 -0700114 ActivityInfo activityInfo = resolveInfo.activityInfo;
115 ApplicationInfo appInfo = activityInfo.applicationInfo;
Maggieca80da22018-01-29 20:29:16 -0800116
117 // If a non-system app tries to inject footer, ignore it
118 if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
Soonil Nagarkarc5dd4e52019-03-25 10:50:16 -0700119 Log.w(TAG, "Ignoring attempt to inject footer from app not in system image: "
120 + resolveInfo);
121 continue;
Maggieca80da22018-01-29 20:29:16 -0800122 }
123
124 // Get the footer text resource id from broadcast receiver's metadata
125 if (activityInfo.metaData == null) {
126 if (Log.isLoggable(TAG, Log.DEBUG)) {
127 Log.d(TAG, "No METADATA in broadcast receiver " + activityInfo.name);
Maggieca80da22018-01-29 20:29:16 -0800128 }
Soonil Nagarkarc5dd4e52019-03-25 10:50:16 -0700129 continue;
Maggieca80da22018-01-29 20:29:16 -0800130 }
131
132 final int footerTextRes =
133 activityInfo.metaData.getInt(LocationManager.METADATA_SETTINGS_FOOTER_STRING);
134 if (footerTextRes == 0) {
Soonil Nagarkarc5dd4e52019-03-25 10:50:16 -0700135 Log.w(
136 TAG,
137 "No mapping of integer exists for "
138 + LocationManager.METADATA_SETTINGS_FOOTER_STRING);
Maggieca80da22018-01-29 20:29:16 -0800139 continue;
140 }
Soonil Nagarkar533a17f2019-07-10 15:11:02 -0700141 footerDataList.add(new FooterData(footerTextRes, appInfo));
Maggieca80da22018-01-29 20:29:16 -0800142 }
143 return footerDataList;
144 }
145
146 /**
147 * Contains information related to a footer.
148 */
149 private static class FooterData {
150
151 // The string resource of the footer
152 final int footerStringRes;
153
154 // Application info of receiver injecting this footer
155 final ApplicationInfo applicationInfo;
156
Soonil Nagarkar533a17f2019-07-10 15:11:02 -0700157 FooterData(int footerRes, ApplicationInfo appInfo) {
Maggieca80da22018-01-29 20:29:16 -0800158 this.footerStringRes = footerRes;
159 this.applicationInfo = appInfo;
Maggieca80da22018-01-29 20:29:16 -0800160 }
161 }
162}