1 /*
2  * Copyright (C) 2012 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.settings;
18 
19 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
20 
21 import android.appwidget.AppWidgetManager;
22 import android.appwidget.AppWidgetProviderInfo;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.PackageManager;
29 import android.os.Bundle;
30 import android.os.UserHandle;
31 import android.util.Log;
32 import android.view.LayoutInflater;
33 import android.widget.CheckBox;
34 
35 import androidx.appcompat.app.AlertDialog;
36 
37 import com.android.internal.app.AlertActivity;
38 import com.android.internal.app.AlertController;
39 
40 /**
41  * This activity is displayed when an app launches the BIND_APPWIDGET intent. This allows apps
42  * that don't have the BIND_APPWIDGET permission to bind specific widgets.
43  */
44 public class AllowBindAppWidgetActivity extends AlertActivity implements
45         DialogInterface.OnClickListener {
46 
47     private CheckBox mAlwaysUse;
48     private int mAppWidgetId;
49     private Bundle mBindOptions;
50     private UserHandle mProfile;
51     private ComponentName mComponentName;
52     private String mCallingPackage;
53     private AppWidgetManager mAppWidgetManager;
54 
55     // Indicates whether this activity was closed because of a click
56     private boolean mClicked;
57 
onClick(DialogInterface dialog, int which)58     public void onClick(DialogInterface dialog, int which) {
59         mClicked = true;
60         if (which == AlertDialog.BUTTON_POSITIVE) {
61             if (mAppWidgetId != -1 && mComponentName != null && mCallingPackage != null) {
62                 try {
63                     final boolean bound = mAppWidgetManager.bindAppWidgetIdIfAllowed(mAppWidgetId,
64                             mProfile, mComponentName, mBindOptions);
65                     if (bound) {
66                         Intent result = new Intent();
67                         result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
68                         setResult(RESULT_OK, result);
69                     }
70                 } catch (Exception e) {
71                     Log.v("BIND_APPWIDGET", "Error binding widget with id "
72                             + mAppWidgetId + " and component " + mComponentName);
73                 }
74 
75                 final boolean alwaysAllowBind = mAlwaysUse.isChecked();
76                 if (alwaysAllowBind != mAppWidgetManager.hasBindAppWidgetPermission(
77                         mCallingPackage)) {
78                     mAppWidgetManager.setBindAppWidgetPermission(mCallingPackage,
79                             alwaysAllowBind);
80                 }
81             }
82         }
83         finish();
84     }
85 
86     @Override
onPause()87     protected void onPause() {
88         if (!mClicked) { // RESULT_CANCELED
89             finish();
90         }
91         super.onPause();
92     }
93 
94     @Override
onCreate(Bundle savedInstanceState)95     protected void onCreate(Bundle savedInstanceState) {
96         super.onCreate(savedInstanceState);
97         getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
98         setResult(RESULT_CANCELED); // By default, set the result to cancelled
99         Intent intent = getIntent();
100         CharSequence label = "";
101         if (intent != null) {
102             try {
103                 mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
104                 mProfile = intent.getParcelableExtra(
105                         AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE);
106                 if (mProfile == null) {
107                     mProfile = android.os.Process.myUserHandle();
108                 }
109                 mComponentName =
110                         intent.getParcelableExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER);
111                 mBindOptions =
112                         intent.getParcelableExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
113                 mCallingPackage = getCallingPackage();
114                 PackageManager pm = getPackageManager();
115                 ApplicationInfo ai = pm.getApplicationInfo(mCallingPackage, 0);
116                 label = pm.getApplicationLabel(ai);
117             } catch (Exception e) {
118                 mAppWidgetId = -1;
119                 mComponentName = null;
120                 mCallingPackage = null;
121                 Log.v("BIND_APPWIDGET", "Error getting parameters");
122                 finish();
123                 return;
124             }
125         }
126         mAppWidgetManager = AppWidgetManager.getInstance(this);
127         final String widgetLabel = getWidgetLabel();
128         AlertController.AlertParams ap = mAlertParams;
129         ap.mTitle = getString(R.string.allow_bind_app_widget_activity_allow_bind_title);
130         ap.mMessage = getString(R.string.allow_bind_app_widget_activity_allow_bind, label,
131                 widgetLabel);
132         ap.mPositiveButtonText = getString(R.string.create);
133         ap.mNegativeButtonText = getString(android.R.string.cancel);
134         ap.mPositiveButtonListener = this;
135         ap.mNegativeButtonListener = this;
136         LayoutInflater inflater =
137                 (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
138         ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
139         mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
140         mAlwaysUse.setText(
141                 getString(R.string.allow_bind_app_widget_activity_always_allow_bind, label));
142 
143         mAlwaysUse.setPadding(mAlwaysUse.getPaddingLeft(),
144                 mAlwaysUse.getPaddingTop(),
145                 mAlwaysUse.getPaddingRight(),
146                 (int) (mAlwaysUse.getPaddingBottom() +
147                         getResources().getDimension(
148                                 R.dimen.bind_app_widget_dialog_checkbox_bottom_padding)));
149 
150         mAlwaysUse.setChecked(mAppWidgetManager.hasBindAppWidgetPermission(mCallingPackage,
151                 mProfile.getIdentifier()));
152 
153         setupAlert();
154     }
155 
getWidgetLabel()156     private String getWidgetLabel() {
157         String label = "";
158         for (AppWidgetProviderInfo providerInfo : mAppWidgetManager.getInstalledProviders()) {
159             if (providerInfo.provider.equals(mComponentName)) {
160                 label = providerInfo.loadLabel(getPackageManager());
161                 break;
162             }
163         }
164         return label;
165     }
166 }
167