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