1/*
2 * Copyright (C) 2015 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
17package android.car.content.pm;
18
19import android.annotation.IntDef;
20import android.annotation.SystemApi;
21import android.car.CarApiUtil;
22import android.car.CarManagerBase;
23import android.car.CarNotConnectedException;
24import android.content.ComponentName;
25import android.content.Context;
26import android.os.IBinder;
27import android.os.Looper;
28import android.os.RemoteException;
29
30import java.lang.annotation.Retention;
31import java.lang.annotation.RetentionPolicy;
32
33/**
34 * Provides car specific API related with package management.
35 */
36public final class CarPackageManager implements CarManagerBase {
37
38    /**
39     * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this
40     * flag is set, the call will be blocked until policy is set to system. This can take time
41     * and the flag cannot be used in main thread.
42     * @hide
43     */
44    @SystemApi
45    public static final int FLAG_SET_POLICY_WAIT_FOR_CHANGE = 0x1;
46    /**
47     * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this
48     * flag is set, passed policy is added to existing policy set from the current package.
49     * If none of {@link #FLAG_SET_POLICY_ADD} or {@link #FLAG_SET_POLICY_REMOVE} is set, existing
50     * policy is replaced. Note that policy per each package is always replaced and will not be
51     * added.
52     * @hide
53     */
54    @SystemApi
55    public static final int FLAG_SET_POLICY_ADD = 0x2;
56    /**
57     * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this
58     * flag is set, passed policy is removed from existing policy set from the current package.
59     * If none of {@link #FLAG_SET_POLICY_ADD} or {@link #FLAG_SET_POLICY_REMOVE} is set, existing
60     * policy is replaced.
61     * @hide
62     */
63    @SystemApi
64    public static final int FLAG_SET_POLICY_REMOVE = 0x4;
65
66    /** @hide */
67    @IntDef(flag = true,
68            value = {FLAG_SET_POLICY_WAIT_FOR_CHANGE, FLAG_SET_POLICY_ADD, FLAG_SET_POLICY_REMOVE})
69    @Retention(RetentionPolicy.SOURCE)
70    public @interface SetPolicyFlags {}
71
72    private final ICarPackageManager mService;
73    private final Context mContext;
74
75    /** @hide */
76    public CarPackageManager(IBinder service, Context context) {
77        mService = ICarPackageManager.Stub.asInterface(service);
78        mContext = context;
79    }
80
81    /** @hide */
82    @Override
83    public void onCarDisconnected() {
84        // nothing to do
85    }
86
87    /**
88     * Set Application blocking policy for system app. {@link #FLAG_SET_POLICY_ADD} or
89     * {@link #FLAG_SET_POLICY_REMOVE} flag allows adding or removing from already set policy. When
90     * none of these flags are set, it will completely replace existing policy for each package
91     * specified.
92     * When {@link #FLAG_SET_POLICY_WAIT_FOR_CHANGE} flag is set, this call will be blocked
93     * until the policy is set to system and become effective. Otherwise, the call will start
94     * changing the policy but it will be completed asynchronously and the call will return
95     * without waiting for system level policy change.
96     *
97     * @param packageName Package name of the client. If wrong package name is passed, exception
98     *        will be thrown. This name is used to update the policy.
99     * @param policy
100     * @param flags
101     * @throws SecurityException if caller has no permission.
102     * @throws IllegalArgumentException For wrong or invalid arguments.
103     * @throws IllegalStateException If {@link #FLAG_SET_POLICY_WAIT_FOR_CHANGE} is set while
104     *         called from main thread.
105     * @hide
106     */
107    @SystemApi
108    public void setAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy,
109            @SetPolicyFlags int flags) throws CarNotConnectedException, SecurityException,
110            IllegalArgumentException {
111        if ((flags & FLAG_SET_POLICY_WAIT_FOR_CHANGE) != 0 &&
112                Looper.getMainLooper().isCurrentThread()) {
113            throw new IllegalStateException(
114                    "FLAG_SET_POLICY_WAIT_FOR_CHANGE cannot be used in main thread");
115        }
116        try {
117            mService.setAppBlockingPolicy(packageName, policy, flags);
118        } catch (IllegalStateException e) {
119            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
120        } catch (RemoteException e) {
121            //ignore as CarApi will handle disconnection anyway.
122        }
123    }
124
125    /**
126     * Check if finishing Activity will lead into safe Activity (=allowed Activity) to be shown.
127     * This can be used by unsafe activity blocking Activity to check if finishing itself can
128     * lead into being launched again due to unsafe activity shown. Note that checking this does not
129     * guarantee that blocking will not be done as driving state can change after this call is made.
130     *
131     * @param activityName
132     * @return true if there is a safe Activity (or car is stopped) in the back of task stack
133     *         so that finishing the Activity will not trigger another Activity blocking. If
134     *         the given Activity is not in foreground, then it will return true as well as
135     *         finishing the Activity will not make any difference.
136     *
137     * @hide
138     */
139    @SystemApi
140    public boolean isActivityBackedBySafeActivity(ComponentName activityName)
141            throws CarNotConnectedException {
142        try {
143            return mService.isActivityBackedBySafeActivity(activityName);
144        } catch (IllegalStateException e) {
145            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
146        } catch (RemoteException e) {
147            //ignore as CarApi will handle disconnection anyway.
148        }
149        return true;
150    }
151
152    /**
153     * Check if given activity is allowed while driving.
154     * @param packageName
155     * @param className
156     * @return
157     */
158    public boolean isActivityAllowedWhileDriving(String packageName, String className)
159            throws CarNotConnectedException {
160        try {
161            return mService.isActivityAllowedWhileDriving(packageName, className);
162        } catch (IllegalStateException e) {
163            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
164        } catch (RemoteException e) {
165            //ignore as CarApi will handle disconnection anyway.
166        }
167        return false;
168    }
169
170    /**
171     * Check if given service is allowed while driving.
172     * @param packageName
173     * @param className
174     * @return
175     */
176    public boolean isServiceAllowedWhileDriving(String packageName, String className)
177            throws CarNotConnectedException {
178        try {
179            return mService.isServiceAllowedWhileDriving(packageName, className);
180        } catch (IllegalStateException e) {
181            CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
182        } catch (RemoteException e) {
183            //ignore as CarApi will handle disconnection anyway.
184        }
185        return false;
186    }
187}
188