• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 package com.android.car.admin;
17 
18 import static com.android.car.admin.CarDevicePolicyService.DEBUG;
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
20 
21 import android.annotation.IntDef;
22 import android.app.admin.DevicePolicyManager;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.util.DebugUtils;
28 import android.util.IndentingPrintWriter;
29 import android.util.Slog;
30 
31 import com.android.car.CarLog;
32 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
33 import com.android.internal.annotations.GuardedBy;
34 import com.android.internal.annotations.VisibleForTesting;
35 
36 import java.lang.annotation.Retention;
37 import java.lang.annotation.RetentionPolicy;
38 import java.util.Objects;
39 
40 /**
41  * User-specific {@code CarDevicePolicyManagerService}.
42  */
43 public final class PerUserCarDevicePolicyService {
44 
45     private static final String TAG = CarLog.tagFor(PerUserCarDevicePolicyService.class);
46 
47     private static final String PREFIX_NEW_USER_DISCLAIMER_STATUS = "NEW_USER_DISCLAIMER_STATUS_";
48 
49     // TODO(b/175057848) must be public because of DebugUtils.constantToString()
50     public static final int NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED = 0;
51     public static final int NEW_USER_DISCLAIMER_STATUS_RECEIVED = 1;
52     public static final int NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT = 2;
53     public static final int NEW_USER_DISCLAIMER_STATUS_SHOWN = 3;
54     public static final int NEW_USER_DISCLAIMER_STATUS_ACKED = 4;
55 
56     @Retention(RetentionPolicy.SOURCE)
57     @IntDef(flag = false, prefix = { PREFIX_NEW_USER_DISCLAIMER_STATUS }, value = {
58             NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED,
59             NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT,
60             NEW_USER_DISCLAIMER_STATUS_RECEIVED,
61             NEW_USER_DISCLAIMER_STATUS_SHOWN,
62             NEW_USER_DISCLAIMER_STATUS_ACKED
63     })
64     public @interface NewUserDisclaimerStatus {}
65 
66     private static final Object SLOCK = new Object();
67 
68     @GuardedBy("SLOCK")
69     private static PerUserCarDevicePolicyService sInstance;
70 
71     private final Context mContext;
72 
73     @GuardedBy("sLock")
74     @NewUserDisclaimerStatus
75     private int mNewUserDisclaimerStatus = NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED;
76 
77     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
78         @Override
79         public void onReceive(Context context, Intent intent) {
80             if (DEBUG) {
81                 Slog.d(TAG, "Received intent on user " + mContext.getUserId() + ": " + intent);
82             }
83             switch(intent.getAction()) {
84                 case DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER:
85                     setUserDisclaimerStatus(NEW_USER_DISCLAIMER_STATUS_RECEIVED);
86                     showNewUserDisclaimer();
87                     break;
88                 default:
89                     Slog.w(TAG, "received unexpected intent: " + intent);
90             }
91         }
92     };
93 
94     /**
95      * Gests the singleton instance, creating it if necessary.
96      */
getInstance(Context context)97     public static PerUserCarDevicePolicyService getInstance(Context context) {
98         Objects.requireNonNull(context, "context cannot be null");
99 
100         synchronized (SLOCK) {
101             if (sInstance == null) {
102                 sInstance = new PerUserCarDevicePolicyService(context.getApplicationContext());
103                 if (DEBUG) Slog.d(TAG, "Created instance: " + sInstance);
104             }
105 
106             return sInstance;
107         }
108     }
109 
110     @VisibleForTesting
PerUserCarDevicePolicyService(Context context)111     PerUserCarDevicePolicyService(Context context) {
112         mContext = context;
113     }
114 
115     /**
116      * Callback for when the service is created.
117      */
onCreate()118     public void onCreate() {
119         if (DEBUG) Slog.d(TAG, "registering BroadcastReceiver");
120 
121         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
122                 DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER));
123     }
124 
125     /**
126      * Callback for when the service is not needed anymore.
127      */
onDestroy()128     public void onDestroy() {
129         synchronized (SLOCK) {
130             sInstance = null;
131         }
132         if (DEBUG) Slog.d(TAG, "unregistering BroadcastReceiver");
133         mContext.unregisterReceiver(mBroadcastReceiver);
134     }
135 
136     /**
137      * Dump its contents.
138      */
139     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter pw)140     public void dump(IndentingPrintWriter pw) {
141         synchronized (SLOCK) {
142             pw.printf("mNewUserDisclaimerStatus: %s\n",
143                     newUserDisclaimerStatusToString(mNewUserDisclaimerStatus));
144         }
145     }
146 
setShown()147     void setShown() {
148         setUserDisclaimerStatus(NEW_USER_DISCLAIMER_STATUS_SHOWN);
149     }
150 
setAcknowledged()151     void setAcknowledged() {
152         setUserDisclaimerStatus(NEW_USER_DISCLAIMER_STATUS_ACKED);
153         NewUserDisclaimerActivity.cancelNotification(mContext);
154 
155         DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
156         dpm.resetNewUserDisclaimer();
157     }
158 
showNewUserDisclaimer()159     private void showNewUserDisclaimer() {
160         // TODO(b/175057848) persist status so it's shown again if car service crashes?
161         NewUserDisclaimerActivity.showNotification(mContext);
162         setUserDisclaimerStatus(NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT);
163     }
164 
setUserDisclaimerStatus(@ewUserDisclaimerStatus int status)165     private void setUserDisclaimerStatus(@NewUserDisclaimerStatus int status) {
166         synchronized (SLOCK) {
167             if (DEBUG) {
168                 Slog.d(TAG, "Changinging status from "
169                         + newUserDisclaimerStatusToString(mNewUserDisclaimerStatus) + " to "
170                         + newUserDisclaimerStatusToString(status));
171             }
172             mNewUserDisclaimerStatus = status;
173         }
174     }
175 
176     @VisibleForTesting
177     @NewUserDisclaimerStatus
getNewUserDisclaimerStatus()178     int getNewUserDisclaimerStatus() {
179         synchronized (SLOCK) {
180             return mNewUserDisclaimerStatus;
181         }
182     }
183 
184     @VisibleForTesting
newUserDisclaimerStatusToString(@ewUserDisclaimerStatus int status)185     static String newUserDisclaimerStatusToString(@NewUserDisclaimerStatus int status) {
186         return DebugUtils.constantToString(PerUserCarDevicePolicyService.class,
187                 PREFIX_NEW_USER_DISCLAIMER_STATUS, status);
188     }
189 }
190