• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
18 package com.android.car.settings.notifications;
19 
20 
21 import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_COMPONENT_NAME;
22 
23 import android.Manifest;
24 import android.annotation.Nullable;
25 import android.app.NotificationManager;
26 import android.content.ComponentName;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.PackageItemInfo;
29 import android.content.pm.PackageManager;
30 import android.content.pm.ServiceInfo;
31 import android.os.Bundle;
32 import android.text.TextUtils;
33 import android.view.accessibility.AccessibilityEvent;
34 
35 import androidx.fragment.app.Fragment;
36 import androidx.fragment.app.FragmentActivity;
37 
38 import com.android.car.settings.R;
39 import com.android.car.settings.common.ConfirmationDialogFragment;
40 import com.android.car.settings.common.Logger;
41 import com.android.internal.app.AlertActivity;
42 import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
43 
44 /**
45  * This activity is a copy of
46  * {@link com.android.settings.notification.NotificationAccessConfirmationActivity}.
47  */
48 public class NotificationAccessConfirmationActivity extends FragmentActivity {
49     private static final Logger LOG = new Logger(NotificationAccessConfirmationActivity.class);
50     private static final String REQUIRED_PERMISSION =
51             Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
52 
53     private ComponentName mComponentName;
54 
55     private final ConfirmationDialogFragment.ConfirmListener mConfirmListener =
56             arguments -> onAllow();
57 
58     private final ConfirmationDialogFragment.RejectListener mRejectListener =
59             arguments -> cancel();
60 
61     @Override
onCreate(@ullable Bundle savedInstanceState)62     protected void onCreate(@Nullable Bundle savedInstanceState) {
63         super.onCreate(savedInstanceState);
64         getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
65         ConfirmationDialogFragment.resetListeners(findConfirmationDialogFragment(),
66                 mConfirmListener,
67                 mRejectListener,
68                 /* neutralListener= */ null);
69 
70         mComponentName = getIntent().getParcelableExtra(EXTRA_COMPONENT_NAME);
71         CharSequence mAppLabel;
72 
73         if (mComponentName == null || mComponentName.getPackageName() == null) {
74             finish();
75             return;
76         }
77 
78         try {
79             ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(
80                     mComponentName.getPackageName(), 0);
81             mAppLabel = applicationInfo.loadSafeLabel(getPackageManager(),
82                     PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
83                     PackageItemInfo.SAFE_LABEL_FLAG_TRIM
84                             | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
85         } catch (PackageManager.NameNotFoundException e) {
86             LOG.e("Couldn't find app with package name for " + mComponentName, e);
87             finish();
88             return;
89         }
90 
91         if (TextUtils.isEmpty(mAppLabel)) {
92             finish();
93             return;
94         }
95 
96         ConfirmationDialogFragment confirmationDialogFragment =
97                 new ConfirmationDialogFragment.Builder(this)
98                         .setTitle(getString(R.string.notification_listener_security_warning_title,
99                                 mAppLabel))
100                         .setMessage(
101                                 getString(R.string.notification_listener_security_warning_summary,
102                                         mAppLabel))
103                         .setPositiveButton(R.string.allow, mConfirmListener)
104                         .setNegativeButton(R.string.deny, mRejectListener)
105                         .build();
106 
107         // Consistent with the permission dialog
108         confirmationDialogFragment.setCancelable(false);
109         confirmationDialogFragment
110                 .show(getSupportFragmentManager(), ConfirmationDialogFragment.TAG);
111     }
112 
113     @Nullable
findConfirmationDialogFragment()114     private ConfirmationDialogFragment findConfirmationDialogFragment() {
115         Fragment fragment = getSupportFragmentManager().findFragmentByTag(
116                 ConfirmationDialogFragment.TAG);
117         if (fragment != null) {
118             return (ConfirmationDialogFragment) fragment;
119         }
120         return null;
121     }
122 
onAllow()123     private void onAllow() {
124         try {
125             ServiceInfo serviceInfo = getPackageManager().getServiceInfo(mComponentName, 0);
126             if (!REQUIRED_PERMISSION.equals(serviceInfo.permission)) {
127                 LOG.e("Service " + mComponentName + " lacks permission " + REQUIRED_PERMISSION);
128                 finish();
129                 return;
130             }
131         } catch (PackageManager.NameNotFoundException e) {
132             LOG.e("Failed to get service info for " + mComponentName, e);
133             finish();
134             return;
135         }
136 
137         getSystemService(NotificationManager.class)
138                 .setNotificationListenerAccessGranted(mComponentName, true);
139         finish();
140     }
141 
142     @Override
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)143     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
144         return AlertActivity.dispatchPopulateAccessibilityEvent(this, event);
145     }
146 
147     @Override
onBackPressed()148     public void onBackPressed() {
149         // Suppress finishing the activity on back button press,
150         // consistently with the permission dialog behavior
151     }
152 
cancel()153     private void cancel() {
154         finish();
155     }
156 }
157