Merge "Add missing wrapper for VHAL Wheel enum" into pi-dev
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index fb74730..e18e573 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -498,7 +498,6 @@
method public int getAreaType();
method public int getChangeMode();
method public java.util.List<java.lang.Integer> getConfigArray();
- method public int getConfigFlags();
method public java.lang.String getConfigString();
method public int getFirstAndOnlyAreaId();
method public float getMaxSampleRate();
@@ -533,7 +532,6 @@
method public android.car.hardware.CarPropertyConfig.Builder<T> setAccess(int);
method public android.car.hardware.CarPropertyConfig.Builder<T> setChangeMode(int);
method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigArray(java.util.ArrayList<java.lang.Integer>);
- method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigFlags(int);
method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigString(java.lang.String);
method public android.car.hardware.CarPropertyConfig.Builder<T> setMaxSampleRate(float);
method public android.car.hardware.CarPropertyConfig.Builder<T> setMinSampleRate(float);
diff --git a/car-lib/src/android/car/content/pm/CarPackageManager.java b/car-lib/src/android/car/content/pm/CarPackageManager.java
index 0cbef44..b1828db 100644
--- a/car-lib/src/android/car/content/pm/CarPackageManager.java
+++ b/car-lib/src/android/car/content/pm/CarPackageManager.java
@@ -27,6 +27,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -35,6 +36,7 @@
* Provides car specific API related with package management.
*/
public final class CarPackageManager implements CarManagerBase {
+ private static final String TAG = "CarPackageManager";
/**
* Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this
@@ -119,7 +121,21 @@
} catch (IllegalStateException e) {
CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
} catch (RemoteException e) {
- //ignore as CarApi will handle disconnection anyway.
+ // Ignore as CarApi will handle disconnection anyway.
+ }
+ }
+
+ /**
+ * Restarts the requested task. If task with {@code taskId} does not exist, do nothing.
+ *
+ * @hide
+ */
+ public void restartTask(int taskId) {
+ try {
+ mService.restartTask(taskId);
+ } catch (RemoteException e) {
+ // Ignore as CarApi will handle disconnection anyway.
+ Log.e(TAG, "Could not restart task " + taskId, e);
}
}
diff --git a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
index 77d89ee..7210f90 100644
--- a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
+++ b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
@@ -26,4 +26,5 @@
boolean isServiceDistractionOptimized(in String packageName, in String className) = 2;
boolean isActivityBackedBySafeActivity(in ComponentName activityName) = 3;
void setEnableActivityBlocking(boolean enable) = 4;
+ void restartTask(int taskId) = 5;
}
diff --git a/car-lib/src/android/car/hardware/CarPropertyConfig.java b/car-lib/src/android/car/hardware/CarPropertyConfig.java
index e0890c8..965253a 100644
--- a/car-lib/src/android/car/hardware/CarPropertyConfig.java
+++ b/car-lib/src/android/car/hardware/CarPropertyConfig.java
@@ -45,7 +45,6 @@
private final int mAreaType;
private final int mChangeMode;
private final ArrayList<Integer> mConfigArray;
- private final int mConfigFlags;
private final String mConfigString;
private final float mMaxSampleRate;
private final float mMinSampleRate;
@@ -54,14 +53,13 @@
private final Class<T> mType;
private CarPropertyConfig(int access, int areaType, int changeMode,
- ArrayList<Integer> configArray, int configFlags, String configString,
+ ArrayList<Integer> configArray, String configString,
float maxSampleRate, float minSampleRate, int propertyId,
SparseArray<AreaConfig<T>> supportedAreas, Class<T> type) {
mAccess = access;
mAreaType = areaType;
mChangeMode = changeMode;
mConfigArray = configArray;
- mConfigFlags = configFlags;
mConfigString = configString;
mMaxSampleRate = maxSampleRate;
mMinSampleRate = minSampleRate;
@@ -82,9 +80,6 @@
public List<Integer> getConfigArray() {
return Collections.unmodifiableList(mConfigArray);
}
- public int getConfigFlags() {
- return mConfigFlags;
- }
public String getConfigString() {
return mConfigString;
}
@@ -172,7 +167,6 @@
for (int i = 0; i < mConfigArray.size(); i++) {
dest.writeInt(mConfigArray.get(i));
}
- dest.writeInt(mConfigFlags);
dest.writeString(mConfigString);
dest.writeFloat(mMaxSampleRate);
dest.writeFloat(mMinSampleRate);
@@ -195,7 +189,6 @@
for (int i = 0; i < configArraySize; i++) {
mConfigArray.add(in.readInt());
}
- mConfigFlags = in.readInt();
mConfigString = in.readString();
mMaxSampleRate = in.readFloat();
mMinSampleRate = in.readFloat();
@@ -235,7 +228,6 @@
+ ", mAreaType=" + mAreaType
+ ", mChangeMode=" + mChangeMode
+ ", mConfigArray=" + mConfigArray
- + ", mConfigFlags=" + mConfigFlags
+ ", mConfigString=" + mConfigString
+ ", mMaxSampleRate=" + mMaxSampleRate
+ ", mMinSampleRate=" + mMinSampleRate
@@ -324,7 +316,6 @@
private final int mAreaType;
private int mChangeMode;
private final ArrayList<Integer> mConfigArray;
- private int mConfigFlags;
private String mConfigString;
private float mMaxSampleRate;
private float mMinSampleRate;
@@ -411,16 +402,6 @@
}
/**
- * Set configFlags parameter to CarPropertyConfig
- *
- * @return Builder<T>
- */
- public Builder<T> setConfigFlags(int configFlags) {
- mConfigFlags = configFlags;
- return this;
- }
-
- /**
* Set configString parameter to CarPropertyConfig
*
* @return Builder<T>
@@ -452,8 +433,8 @@
public CarPropertyConfig<T> build() {
return new CarPropertyConfig<>(mAccess, mAreaType, mChangeMode, mConfigArray,
- mConfigFlags, mConfigString, mMaxSampleRate,
- mMinSampleRate, mPropertyId, mSupportedAreas, mType);
+ mConfigString, mMaxSampleRate, mMinSampleRate,
+ mPropertyId, mSupportedAreas, mType);
}
}
}
diff --git a/evs/manager/service.cpp b/evs/manager/service.cpp
index f9e45eb..20504a0 100644
--- a/evs/manager/service.cpp
+++ b/evs/manager/service.cpp
@@ -38,6 +38,28 @@
using namespace android;
+static void startService(const char *hardwareServiceName, const char * managerServiceName) {
+ ALOGI("EVS managed service connecting to hardware service at %s", hardwareServiceName);
+ android::sp<Enumerator> service = new Enumerator();
+ if (!service->init(hardwareServiceName)) {
+ ALOGE("Failed to connect to hardware service - quitting from registrationThread");
+ exit(1);
+ }
+
+ // Register our service -- if somebody is already registered by our name,
+ // they will be killed (their thread pool will throw an exception).
+ ALOGI("EVS managed service is starting as %s", managerServiceName);
+ status_t status = service->registerAsService(managerServiceName);
+ if (status != OK) {
+ ALOGE("Could not register service %s (%d) - quitting from registrationThread",
+ managerServiceName, status);
+ exit(2);
+ }
+
+ ALOGD("Registration complete");
+}
+
+
int main(int argc, char** argv) {
ALOGI("EVS manager starting\n");
@@ -72,26 +94,14 @@
// threads beyond the main thread which will "join" the pool below.
configureRpcThreadpool(1, true /* callerWillJoin */);
- ALOGI("EVS managed service connecting to hardware service at %s", evsHardwareServiceName);
- android::sp<Enumerator> service = new Enumerator();
- if (!service->init(evsHardwareServiceName)) {
- ALOGE("Failed to initialize");
- return 1;
- }
+ // The connection to the underlying hardware service must happen on a dedicated thread to ensure
+ // that the hwbinder response can be processed by the thread pool without blocking.
+ std::thread registrationThread(startService, evsHardwareServiceName, kManagedEnumeratorName);
- // Register our service -- if somebody is already registered by our name,
- // they will be killed (their thread pool will throw an exception).
- ALOGI("EVS managed service is starting as %s", kManagedEnumeratorName);
- status_t status = service->registerAsService(kManagedEnumeratorName);
- if (status == OK) {
- ALOGD("Registration complete");
-
- // Send this main thread to become a permanent part of the thread pool.
- // This is not expected to return.
- joinRpcThreadpool();
- } else {
- ALOGE("Could not register service %s (%d).", kManagedEnumeratorName, status);
- }
+ // Send this main thread to become a permanent part of the thread pool.
+ // This is not expected to return.
+ ALOGD("Main thread entering thread pool");
+ joinRpcThreadpool();
// In normal operation, we don't expect the thread pool to exit
ALOGE("EVS Hardware Enumerator is shutting down");
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index d58c01a..5477f1e 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -253,7 +253,8 @@
<activity android:name="com.android.car.pm.ActivityBlockingActivity"
android:excludeFromRecents="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
- android:exported="false">
+ android:exported="false"
+ android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
diff --git a/service/res/drawable/exit_button_background.xml b/service/res/drawable/exit_button_background.xml
new file mode 100644
index 0000000..7daa69b
--- /dev/null
+++ b/service/res/drawable/exit_button_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/exit_button_background"/>
+ <corners
+ android:radius="@dimen/exit_button_radius"/>
+</shape>
\ No newline at end of file
diff --git a/service/res/layout/activity_blocking.xml b/service/res/layout/activity_blocking.xml
index 6a41c7f..9cd854a 100644
--- a/service/res/layout/activity_blocking.xml
+++ b/service/res/layout/activity_blocking.xml
@@ -13,16 +13,30 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<FrameLayout
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:background="@color/activity_blocking_activity_background">
+ android:background="@color/activity_blocking_activity_background"
+ android:padding="@dimen/blocking_activity_padding"
+ android:gravity="center">
<TextView
android:id="@+id/activity_blocked_title"
- android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:textColor="@color/blocking_text"
android:textAppearance="@style/ActivityBlockingActivityText" />
-</FrameLayout>
+ <Button
+ android:id="@+id/exit"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="@dimen/exit_button_top_margin"
+ android:background="@drawable/exit_button_background"
+ android:paddingEnd="@dimen/exit_button_padding"
+ android:paddingStart="@dimen/exit_button_padding"
+ android:textColor="@color/exit_button_text"
+ android:textAllCaps="true"
+ android:textAppearance="@style/ActivityBlockingActivityText"
+ android:text="@string/exit_button"/>
+</LinearLayout>
diff --git a/service/res/values-h1920dp/dimens.xml b/service/res/values-h1920dp/dimens.xml
index 1cd38f3..938fb17 100644
--- a/service/res/values-h1920dp/dimens.xml
+++ b/service/res/values-h1920dp/dimens.xml
@@ -19,4 +19,8 @@
<resources>
<!-- Text size in ActivityBlockingActivity. -->
<dimen name="blocking_text_size">40sp</dimen>
+ <!-- Padding of exit button in ActivityBlockingActivity. -->
+ <dimen name="exit_button_padding">28dp</dimen>
+ <!-- Top margin of exit button in ActivityBlockingActivity. -->
+ <dimen name="exit_button_top_margin">20dp</dimen>
</resources>
diff --git a/service/res/values-h800dp/dimens.xml b/service/res/values-h800dp/dimens.xml
new file mode 100644
index 0000000..9594554
--- /dev/null
+++ b/service/res/values-h800dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Padding of exit button in ActivityBlockingActivity. -->
+ <dimen name="exit_button_padding">28dp</dimen>
+</resources>
diff --git a/service/res/values-night/colors.xml b/service/res/values-night/colors.xml
index 794759e..d19a164 100644
--- a/service/res/values-night/colors.xml
+++ b/service/res/values-night/colors.xml
@@ -22,5 +22,11 @@
<color name="activity_blocking_activity_background">#cc000000</color>
<!-- Color of text in blocking activity. -->
- <color name="activity_blocking_activity_text_color">#fff5f5f5</color>
+ <color name="blocking_text">#fff5f5f5</color>
+
+ <!-- Background color of exit button. -->
+ <color name="exit_button_background">#ff80cbc4</color>
+
+ <!-- Color of exit button text. -->
+ <color name="exit_button_text">#ff212121</color>
</resources>
diff --git a/service/res/values-w1280dp/dimens.xml b/service/res/values-w1280dp/dimens.xml
new file mode 100644
index 0000000..f5469f2
--- /dev/null
+++ b/service/res/values-w1280dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Padding of ActivityBlockingActivity. -->
+ <dimen name="blocking_activity_padding">148dp</dimen>
+</resources>
diff --git a/service/res/values-w1920dp/dimens.xml b/service/res/values-w1920dp/dimens.xml
new file mode 100644
index 0000000..75d2deb
--- /dev/null
+++ b/service/res/values-w1920dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Padding of ActivityBlockingActivity. -->
+ <dimen name="blocking_activity_padding">192dp</dimen>
+</resources>
diff --git a/service/res/values-w690dp/dimens.xml b/service/res/values-w690dp/dimens.xml
new file mode 100644
index 0000000..0b06ada
--- /dev/null
+++ b/service/res/values-w690dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Padding of ActivityBlockingActivity. -->
+ <dimen name="blocking_activity_padding">112dp</dimen>
+</resources>
diff --git a/service/res/values/colors.xml b/service/res/values/colors.xml
index 9fd06a1..4f61234 100644
--- a/service/res/values/colors.xml
+++ b/service/res/values/colors.xml
@@ -22,5 +22,11 @@
<color name="activity_blocking_activity_background">#e6eeeeee</color>
<!-- Color of text in blocking activity. -->
- <color name="activity_blocking_activity_text_color">#ff212121</color>
+ <color name="blocking_text">#ff212121</color>
+
+ <!-- Background color of exit button. -->
+ <color name="exit_button_background">#ff00796b</color>
+
+ <!-- Color of exit button text. -->
+ <color name="exit_button_text">#fffafafa</color>
</resources>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 4e30d7f..294bd3b 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -52,9 +52,6 @@
<!-- The com.android.car.VmsPublisherService will bind to this list of clients -->
<string-array translatable="false" name="vmsPublisherClients">
</string-array>
- <!-- System privileged packages in this list can access the VMS subscribers API -->
- <string-array translatable="false" name="allowedVmsSubscriberClients">
- </string-array>
<!-- Permissions that the com.android.car.VmsPublisherService is allowed to grant to publishers -->
<string-array translatable="false" name="vmsSafePermissions">
<item>"android.permission.ACCESS_FINE_LOCATION"</item>
diff --git a/service/res/values/dimens.xml b/service/res/values/dimens.xml
index c32770b..1289080 100644
--- a/service/res/values/dimens.xml
+++ b/service/res/values/dimens.xml
@@ -19,4 +19,12 @@
<resources>
<!-- Text size in ActivityBlockingActivity. -->
<dimen name="blocking_text_size">32sp</dimen>
-</resources>
\ No newline at end of file
+ <!-- Padding of ActivityBlockingActivity. -->
+ <dimen name="blocking_activity_padding">20dp</dimen>
+ <!-- Padding of exit button in ActivityBlockingActivity. -->
+ <dimen name="exit_button_padding">16dp</dimen>
+ <!-- Radius of exit button in ActivityBlockingActivity. -->
+ <dimen name="exit_button_radius">4dp</dimen>
+ <!-- Top margin of exit button in ActivityBlockingActivity. -->
+ <dimen name="exit_button_top_margin">16dp</dimen>
+</resources>
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index 8604abc..9423e85 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- For permissions -->
<!-- Permission text: can access your car's information [CHAR LIMIT=NONE] -->
<string name="car_permission_label">Car information</string>
@@ -101,8 +101,10 @@
<string name="car_can_bus_failure_desc">CAN bus does not respond. Unplug and plug back headunit
box and restart the car</string>
- <!-- Blocking activity: Message to show to user when an application is not allowed. [CHAR LIMIT=NONE] -->
- <string name="activity_blocked_string">%1$s can\'t be used while driving.</string>
+ <!-- Blocking activity: Message to show to user when a feature of current application is not allowed. [CHAR LIMIT=60] -->
+ <string name="activity_blocked_string">This <xliff:g id="app_name" example="Google Maps">%1$s</xliff:g> feature can\'t be used while driving.</string>
+ <!-- Blocking activity: Button text that restarts the current blocked application. [CHAR LIMIT=10] -->
+ <string name="exit_button">OK</string>
<!-- Permission text: apps can control diagnostic data [CHAR LIMIT=NONE] -->
<string name="car_permission_label_diag_read">Diagnostic Data</string>
diff --git a/service/res/values/styles.xml b/service/res/values/styles.xml
index 213eb2e..7571362 100644
--- a/service/res/values/styles.xml
+++ b/service/res/values/styles.xml
@@ -19,7 +19,6 @@
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textStyle">normal</item>
<item name="android:textSize">@dimen/blocking_text_size</item>
- <item name="android:textColor">@color/activity_blocking_activity_text_color</item>
</style>
</resources>
diff --git a/service/src/com/android/car/CarNightService.java b/service/src/com/android/car/CarNightService.java
index 497f77c..212bb1a 100644
--- a/service/src/com/android/car/CarNightService.java
+++ b/service/src/com/android/car/CarNightService.java
@@ -64,14 +64,20 @@
return;
}
if (event.sensorType == CarSensorManager.SENSOR_TYPE_NIGHT) {
- if (event.intValues[0] == 1) {
- mNightSetting = UiModeManager.MODE_NIGHT_YES;
+ if (event.intValues[0] == 0) {
+ mNightSetting = UiModeManager.MODE_NIGHT_NO;
+ if (DBG) Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent DAY");
}
else {
- mNightSetting = UiModeManager.MODE_NIGHT_NO;
+ mNightSetting = UiModeManager.MODE_NIGHT_YES;
+ if (DBG) Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent NIGHT");
}
+
if (mUiModeManager != null && (mForcedMode == FORCED_SENSOR_MODE)) {
mUiModeManager.setNightMode(mNightSetting);
+ if (DBG) Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent APPLIED");
+ } else {
+ if (DBG) Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent IGNORED");
}
}
}
@@ -107,7 +113,7 @@
mCarSensorService = sensorService;
mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
if (mUiModeManager == null) {
- Log.w(CarLog.TAG_SENSOR,"Failed to get UI_MODE_SERVICE");
+ Log.w(CarLog.TAG_SENSOR, "Failed to get UI_MODE_SERVICE");
}
}
@@ -130,8 +136,8 @@
@Override
public synchronized void dump(PrintWriter writer) {
writer.println("*DAY NIGHT POLICY*");
- writer.println("Mode:" + ((mNightSetting == UiModeManager.MODE_NIGHT_YES) ? "night" : "day")
- );
+ writer.println("Mode:" +
+ ((mNightSetting == UiModeManager.MODE_NIGHT_YES) ? "night" : "day"));
writer.println("Forced Mode? " + (mForcedMode == FORCED_SENSOR_MODE ? "false"
: (mForcedMode == FORCED_DAY_MODE ? "day" : "night")));
}
diff --git a/service/src/com/android/car/CarSensorService.java b/service/src/com/android/car/CarSensorService.java
index 8c5a960..4b0227e 100644
--- a/service/src/com/android/car/CarSensorService.java
+++ b/service/src/com/android/car/CarSensorService.java
@@ -40,10 +40,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import com.android.car.hal.SensorBase;
import com.android.car.hal.SensorHalService;
-import com.android.car.hal.SensorHalService.SensorListener;
-import com.android.car.hal.SensorHalServiceBase;
import com.android.internal.annotations.GuardedBy;
import com.google.android.collect.Lists;
@@ -62,37 +59,6 @@
implements CarServiceBase, SensorHalService.SensorListener {
/**
- * <pre>
- * Abstraction for logical sensor which is not physical sensor but presented
- * as sensor to upper layer. Currently {@link CarSensorManager#SENSOR_TYPE_NIGHT}
- * falls into this category.
- * Implementation can call {@link CarSensorService#onSensorData(CarSensorEvent)} when there
- * is state change for the given sensor after {@link SensorHalServiceBase#init()}
- * is called.
- * </pre>
- */
- public static abstract class LogicalSensor implements SensorBase {
- private final LinkedList<CarSensorEvent> mDispatchQ = new LinkedList<>();
-
- /** Sensor service is ready and all vehicle sensors are available. */
- public abstract void onSensorServiceReady();
-
- /**
- * Utility to help service to send one event as listener only takes list form.
- * @param listener
- * @param event
- *
- */
- protected void dispatchCarSensorEvent(SensorListener listener, CarSensorEvent event) {
- synchronized (mDispatchQ) {
- mDispatchQ.add(event);
- listener.onSensorEvents(mDispatchQ);
- mDispatchQ.clear();
- }
- }
- }
-
- /**
* When set, sensor service sets its own dispatching rate limit.
* VehicleNetworkService is already doing this, so not necessary to set it for now.
*/
@@ -168,7 +134,8 @@
event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT, 0, 0, 1, 0);
event.intValues[0] = 1; // 1 means night mode!
}
- Log.i(CarLog.TAG_SENSOR, "initial daynight: " + event.intValues[0]);
+ Log.i(CarLog.TAG_SENSOR, "initial daynight: " +
+ (event.intValues[0] == 1 ? "Night" : "Day"));
return event;
}
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 9db071b..037069a 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -21,6 +21,7 @@
import android.car.Car;
import android.car.ICar;
import android.car.cluster.renderer.IInstrumentClusterNavigation;
+import android.car.user.CarUserManagerHelper;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.automotive.vehicle.V2_0.IVehicle;
@@ -39,6 +40,7 @@
import com.android.car.internal.FeatureConfiguration;
import com.android.car.pm.CarPackageManagerService;
import com.android.car.systeminterface.SystemInterface;
+import com.android.car.user.CarUserService;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.car.ICarServiceHelper;
@@ -81,6 +83,8 @@
private final CarDiagnosticService mCarDiagnosticService;
private final CarStorageMonitoringService mCarStorageMonitoringService;
private final CarConfigurationService mCarConfigurationService;
+ private final CarUserManagerHelper mCarUserManagerHelper;
+ private final CarUserService mCarUserService;
private VmsSubscriberService mVmsSubscriberService;
private VmsPublisherService mVmsPublisherService;
@@ -144,10 +148,13 @@
systemInterface);
mCarConfigurationService =
new CarConfigurationService(serviceContext, new JsonReaderImpl());
+ mCarUserManagerHelper = new CarUserManagerHelper(serviceContext);
+ mCarUserService = new CarUserService(serviceContext, mCarUserManagerHelper);
// Be careful with order. Service depending on other service should be inited later.
mAllServices = new CarServiceBase[] {
mSystemActivityMonitoringService,
+ mCarUserService,
mCarPowerManagementService,
mCarSensorService,
mCarDrivingStateService,
diff --git a/service/src/com/android/car/SystemActivityMonitoringService.java b/service/src/com/android/car/SystemActivityMonitoringService.java
index 24ce2e7..2df9b00 100644
--- a/service/src/com/android/car/SystemActivityMonitoringService.java
+++ b/service/src/com/android/car/SystemActivityMonitoringService.java
@@ -85,10 +85,6 @@
void onActivityLaunch(TopTaskInfoContainer topTask);
}
- private static final boolean DBG = false;
-
- private static final int NUM_MAX_TASK_TO_FETCH = 10;
-
private final Context mContext;
private final IActivityManager mAm;
private final ProcessObserver mProcessObserver;
@@ -192,6 +188,57 @@
return false;
}
+ /**
+ * Attempts to restart a task.
+ *
+ * <p>Restarts a task by sending an empty intent with flag
+ * {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} to its root activity. If the task does not exist,
+ * do nothing.
+ *
+ * @param taskId id of task to be restarted.
+ */
+ public void restartTask(int taskId) {
+ String rootActivityName = null;
+ int userId = 0;
+ try {
+ findRootActivityName:
+ for (StackInfo info : mAm.getAllStackInfos()) {
+ for (int i = 0; i < info.taskIds.length; i++) {
+ if (info.taskIds[i] == taskId) {
+ rootActivityName = info.taskNames[i];
+ userId = info.userId;
+ if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
+ Log.d(CarLog.TAG_AM, "Root activity is " + rootActivityName);
+ Log.d(CarLog.TAG_AM, "User id is " + userId);
+ }
+ // Break out of nested loop.
+ break findRootActivityName;
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(CarLog.TAG_AM, "Could not get stack info", e);
+ return;
+ }
+
+ if (rootActivityName == null) {
+ Log.e(CarLog.TAG_AM, "Could not find root activity with task id " + taskId);
+ return;
+ }
+
+ Intent rootActivityIntent = new Intent();
+ rootActivityIntent.setComponent(ComponentName.unflattenFromString(rootActivityName));
+ // Clear the task the root activity is running in and start it in a new task.
+ // Effectively restart root activity.
+ rootActivityIntent.addFlags(
+ Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
+ Log.i(CarLog.TAG_AM, "restarting root activity with user id " + userId);
+ }
+ mContext.startActivityAsUser(rootActivityIntent, new UserHandle(userId));
+ }
+
public void registerActivityLaunchListener(ActivityLaunchListener listener) {
synchronized (this) {
mActivityLaunchListener = listener;
@@ -238,7 +285,7 @@
(focusedStackId == stackId && focusedStackId != mFocusedStackId)) {
mTopTasks.put(stackId, newTopTaskInfo);
mTasksToDispatch.add(newTopTaskInfo);
- if (DBG) {
+ if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Log.i(CarLog.TAG_AM, "New top task: " + newTopTaskInfo);
}
}
@@ -247,7 +294,7 @@
}
if (listener != null) {
for (TopTaskInfoContainer topTask : mTasksToDispatch) {
- if (DBG) {
+ if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Log.i(CarLog.TAG_AM, "activity launched:" + topTask.toString());
}
listener.onActivityLaunch(topTask);
@@ -310,11 +357,9 @@
* block the current task with the provided new activity.
*/
private void handleBlockActivity(TopTaskInfoContainer currentTask, Intent newActivityIntent) {
- newActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
mContext.startActivityAsUser(newActivityIntent,
new UserHandle(currentTask.stackInfo.userId));
- // now make stack with new activity focused.
+ // Now make stack with new activity focused.
findTaskAndGrantFocus(newActivityIntent.getComponent());
}
@@ -347,7 +392,7 @@
private class ProcessObserver extends IProcessObserver.Stub {
@Override
public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
- if (DBG) {
+ if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Log.i(CarLog.TAG_AM,
String.format("onForegroundActivitiesChanged uid %d pid %d fg %b",
uid, pid, foregroundActivities));
@@ -364,7 +409,7 @@
private class TaskListener extends TaskStackListener {
@Override
public void onTaskStackChanged() {
- if (DBG) {
+ if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
Log.i(CarLog.TAG_AM, "onTaskStackChanged");
}
mHandler.requestUpdatingTask();
diff --git a/service/src/com/android/car/VmsSubscriberService.java b/service/src/com/android/car/VmsSubscriberService.java
index aea0274..371b418 100644
--- a/service/src/com/android/car/VmsSubscriberService.java
+++ b/service/src/com/android/car/VmsSubscriberService.java
@@ -20,12 +20,9 @@
import android.car.Car;
import android.car.vms.IVmsSubscriberClient;
import android.car.vms.IVmsSubscriberService;
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsLayer;
import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsLayer;
import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -34,9 +31,7 @@
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
-import java.util.Arrays;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -56,7 +51,6 @@
private final Context mContext;
private final VmsHalService mHal;
- private final Set<String> mWhitelistedSubscribersNames;
@GuardedBy("mSubscriberServiceLock")
private final VmsSubscribersManager mSubscribersManager = new VmsSubscribersManager();
@@ -205,30 +199,6 @@
public VmsSubscriberService(Context context, VmsHalService hal) {
mContext = context;
mHal = hal;
- mWhitelistedSubscribersNames = Collections.unmodifiableSet(
- new HashSet(Arrays.asList(
- mContext.getResources().getStringArray(R.array.allowedVmsSubscriberClients))));
- Log.d(TAG, "Initialized VMS subscribers whitelist: " + mWhitelistedSubscribersNames);
- }
-
- private void verifySubscriberOrThrow() {
- // Assert permissions.
- ICarImpl.assertVmsSubscriberPermission(mContext);
-
- // Assert whitelisted.
- int callingUid = Binder.getCallingUid();
- PackageManager pm = mContext.getPackageManager();
- Set<String> packagesForUid = new HashSet<>(Arrays.asList(pm.getPackagesForUid(callingUid)));
-
- packagesForUid.retainAll(mWhitelistedSubscribersNames);
- if (packagesForUid.isEmpty()) {
- throw new SecurityException(
- "Package is not whitelisted as a VMS Subscriber. got : "
- + Arrays.asList(pm.getPackagesForUid(callingUid))
- + " expected :"
- + mWhitelistedSubscribersNames);
- }
- Log.d(TAG, "verified package for VMS subscriber API: " + packagesForUid);
}
// Implements CarServiceBase interface.
@@ -250,7 +220,7 @@
// Implements IVmsService interface.
@Override
public void addVmsSubscriberToNotifications(IVmsSubscriberClient subscriber) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
// Add the subscriber so it can subscribe.
mSubscribersManager.add(subscriber);
@@ -259,7 +229,7 @@
@Override
public void removeVmsSubscriberToNotifications(IVmsSubscriberClient subscriber) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
if (mHal.containsSubscriber(subscriber)) {
throw new IllegalArgumentException("Subscriber has active subscriptions.");
@@ -270,7 +240,7 @@
@Override
public void addVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
// Add the subscriber so it can subscribe.
mSubscribersManager.add(subscriber);
@@ -282,7 +252,7 @@
@Override
public void removeVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
// Remove the subscription.
mHal.removeSubscription(subscriber, layer);
@@ -293,7 +263,7 @@
public void addVmsSubscriberToPublisher(IVmsSubscriberClient subscriber,
VmsLayer layer,
int publisherId) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
// Add the subscriber so it can subscribe.
mSubscribersManager.add(subscriber);
@@ -307,7 +277,7 @@
public void removeVmsSubscriberToPublisher(IVmsSubscriberClient subscriber,
VmsLayer layer,
int publisherId) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
// Remove the subscription.
mHal.removeSubscription(subscriber, layer, publisherId);
@@ -316,7 +286,7 @@
@Override
public void addVmsSubscriberPassive(IVmsSubscriberClient subscriber) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
mSubscribersManager.add(subscriber);
mHal.addSubscription(subscriber);
@@ -325,7 +295,7 @@
@Override
public void removeVmsSubscriberPassive(IVmsSubscriberClient subscriber) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
// Remove the subscription.
mHal.removeSubscription(subscriber);
@@ -334,7 +304,7 @@
@Override
public byte[] getPublisherInfo(int publisherId) {
- verifySubscriberOrThrow();
+ ICarImpl.assertVmsSubscriberPermission(mContext);
synchronized (mSubscriberServiceLock) {
return mHal.getPublisherInfo(publisherId);
}
diff --git a/service/src/com/android/car/hal/CarPropertyUtils.java b/service/src/com/android/car/hal/CarPropertyUtils.java
index 6b04b02..8b5c446 100644
--- a/service/src/com/android/car/hal/CarPropertyUtils.java
+++ b/service/src/com/android/car/hal/CarPropertyUtils.java
@@ -117,7 +117,6 @@
.setAccess(p.access)
.setChangeMode(p.changeMode)
.setConfigArray(p.configArray)
- .setConfigFlags(p.configFlags)
.setConfigString(p.configString)
.setMaxSampleRate(p.maxSampleRate)
.setMinSampleRate(p.minSampleRate)
@@ -128,7 +127,6 @@
.setAccess(p.access)
.setChangeMode(p.changeMode)
.setConfigArray(p.configArray)
- .setConfigFlags(p.configFlags)
.setConfigString(p.configString)
.setMaxSampleRate(p.maxSampleRate)
.setMinSampleRate(p.minSampleRate);
diff --git a/service/src/com/android/car/pm/ActivityBlockingActivity.java b/service/src/com/android/car/pm/ActivityBlockingActivity.java
index 3ce74df..3e55405 100644
--- a/service/src/com/android/car/pm/ActivityBlockingActivity.java
+++ b/service/src/com/android/car/pm/ActivityBlockingActivity.java
@@ -18,15 +18,20 @@
import android.app.Activity;
import android.car.Car;
import android.car.CarNotConnectedException;
+import android.car.content.pm.CarPackageManager;
import android.car.drivingstate.CarUxRestrictions;
import android.car.drivingstate.CarUxRestrictionsManager;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
+import android.text.TextUtils;
import android.util.Log;
+import android.view.View;
+import android.widget.Button;
import android.widget.TextView;
import com.android.car.CarLog;
@@ -39,20 +44,29 @@
*/
public class ActivityBlockingActivity extends Activity {
public static final String INTENT_KEY_BLOCKED_ACTIVITY = "blocked_activity";
+ public static final String EXTRA_BLOCKED_TASK = "blocked_task";
+
+ private static final int INVALID_TASK_ID = -1;
private Car mCar;
private CarUxRestrictionsManager mUxRManager;
+ private TextView mBlockedTitle;
+ private Button mExitButton;
+ // Exiting depends on Car connection, which might not be available at the time exit was
+ // requested (e.g. user presses Exit Button). In that case, we record exiting was requested, and
+ // Car connection will perform exiting once it is established.
+ private boolean mExitRequested;
+ private int mBlockedTaskId;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_blocking);
- String blockedActivity = getIntent().getStringExtra(INTENT_KEY_BLOCKED_ACTIVITY);
-
- TextView blockedTitle = findViewById(R.id.activity_blocked_title);
- blockedTitle.setText(getString(R.string.activity_blocked_string,
- findBlockedApplicationLabel(blockedActivity)));
+ mBlockedTitle = findViewById(R.id.activity_blocked_title);
+ mExitButton = findViewById(R.id.exit);
+ mExitButton.setOnClickListener(v -> handleFinish());
// Listen to the CarUxRestrictions so this blocking activity can be dismissed when the
// restrictions are lifted.
@@ -60,6 +74,9 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
+ if (mExitRequested) {
+ handleFinish();
+ }
mUxRManager = (CarUxRestrictionsManager) mCar.getCarManager(
Car.CAR_UX_RESTRICTION_SERVICE);
// This activity would have been launched only in a restricted state.
@@ -81,29 +98,34 @@
mCar.connect();
}
- /**
- * Returns the application label of blockedActivity. If that fails, the original activity will
- * be returned.
- */
- private String findBlockedApplicationLabel(String blockedActivity) {
- String label = blockedActivity;
- // Attempt to update blockedActivity name to application label.
- try {
- ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(
- ComponentName.unflattenFromString(blockedActivity).getPackageName(), 0);
- CharSequence appLabel = getPackageManager().getApplicationLabel(applicationInfo);
- if (appLabel != null) {
- label = appLabel.toString();
- }
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- }
- return label;
- }
-
@Override
protected void onResume() {
super.onResume();
+
+ // Display message about the current blocked activity, and optionally show an exit button
+ // to restart the blocked task (stack of activities) if its root activity is DO.
+
+ // blockedActivity is expected to be always passed in as the topmost activity of task.
+ String blockedActivity = getIntent().getStringExtra(INTENT_KEY_BLOCKED_ACTIVITY);
+ mBlockedTitle.setText(getString(R.string.activity_blocked_string,
+ findHumanReadableLabel(blockedActivity)));
+ if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
+ Log.d(CarLog.TAG_AM, "Blocking activity " + blockedActivity);
+ }
+
+ // taskId is available as extra if the task can be restarted.
+ mBlockedTaskId = getIntent().getIntExtra(EXTRA_BLOCKED_TASK, INVALID_TASK_ID);
+
+ mExitButton.setVisibility(mBlockedTaskId == INVALID_TASK_ID ? View.GONE : View.VISIBLE);
+ if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG) && mBlockedTaskId == INVALID_TASK_ID) {
+ Log.d(CarLog.TAG_AM, "Blocked task ID is not available. Hiding exit button.");
+ }
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
}
@Override
@@ -130,4 +152,57 @@
finish();
}
}
+
+ /**
+ * Returns a human-readable string for {@code flattenComponentName}.
+ *
+ * <p>It first attempts to return the application label for this activity. If that fails,
+ * it will return the last part in the activity name.
+ */
+ private String findHumanReadableLabel(String flattenComponentName) {
+ ComponentName componentName = ComponentName.unflattenFromString(flattenComponentName);
+ String label = null;
+ // Attempt to find application label.
+ try {
+ ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(
+ componentName.getPackageName(), 0);
+ CharSequence appLabel = getPackageManager().getApplicationLabel(applicationInfo);
+ if (appLabel != null) {
+ label = appLabel.toString();
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
+ Log.i(CarLog.TAG_AM, "Could not find package for component name "
+ + componentName.toString());
+ }
+ }
+ if (TextUtils.isEmpty(label)) {
+ label = componentName.getClass().getSimpleName();
+ }
+ return label;
+ }
+
+ private void handleFinish() {
+ if (!mCar.isConnected()) {
+ mExitRequested = true;
+ return;
+ }
+ if (isFinishing()) {
+ return;
+ }
+
+ // Lock on self (assuming single instance) to avoid restarting the same task twice.
+ synchronized (this) {
+ try {
+ CarPackageManager carPm = (CarPackageManager)
+ mCar.getCarManager(Car.PACKAGE_SERVICE);
+ carPm.restartTask(mBlockedTaskId);
+ } catch (CarNotConnectedException e) {
+ // We should never be here since Car connection is already checked.
+ Log.e(CarLog.TAG_AM, "Car connection is not available.", e);
+ return;
+ }
+ finish();
+ }
+ }
}
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index 916bf1c..930a9e4 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -45,6 +45,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Process;
+import android.text.format.DateFormat;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -76,6 +77,7 @@
// Delimiters to parse packages and activities in the configuration XML resource.
private static final String PACKAGE_DELIMITER = ",";
private static final String PACKAGE_ACTIVITY_DELIMITER = "/";
+ private static final int LOG_SIZE = 20;
private final Context mContext;
private final SystemActivityMonitoringService mSystemActivityMonitoringService;
@@ -84,6 +86,9 @@
private final HandlerThread mHandlerThread;
private final PackageHandler mHandler;
+ // For dumpsys logging.
+ private final LinkedList<String> mBlockedActivityLogs = new LinkedList<>();
+
// Store the white list and black list strings from the resource file.
private String mConfiguredWhitelist;
private String mConfiguredBlacklist;
@@ -157,6 +162,14 @@
doSetAppBlockingPolicy(packageName, policy, flags, true /*setNow*/);
}
+ /**
+ * Restarts the requested task. If task with {@code taskId} does not exist, do nothing.
+ */
+ @Override
+ public void restartTask(int taskId) {
+ mSystemActivityMonitoringService.restartTask(taskId);
+ }
+
private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags,
boolean setNow) {
if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING)
@@ -801,6 +814,7 @@
writer.println("mHasParsedPackages:" + mHasParsedPackages);
writer.println("mBootLockedIntentRx:" + mBootLockedIntentRx);
writer.println("ActivityRestricted:" + mUxRestrictionsListener.isRestricted());
+ writer.println(String.join("\n", mBlockedActivityLogs));
writer.print(dumpPoliciesLocked(true));
}
}
@@ -879,11 +893,42 @@
" not allowed, will block, number of tasks in stack:" +
topTask.stackInfo.taskIds.length);
}
+ StringBuilder blockedActivityLog = new StringBuilder();
Intent newActivityIntent = new Intent();
newActivityIntent.setComponent(mActivityBlockingActivity);
newActivityIntent.putExtra(
ActivityBlockingActivity.INTENT_KEY_BLOCKED_ACTIVITY,
topTask.topActivity.flattenToString());
+ blockedActivityLog.append("Blocked activity ")
+ .append(topTask.topActivity.flattenToShortString())
+ .append(". Task id ").append(topTask.taskId);
+
+ // If root activity of blocked task is DO, also pass its task id into blocking activity,
+ // which uses the id to display a button for restarting the blocked task.
+ for (int i = 0; i < topTask.stackInfo.taskIds.length; i++) {
+ // topTask.taskId is the task that should be blocked.
+ if (topTask.stackInfo.taskIds[i] == topTask.taskId) {
+ // stackInfo represents an ActivityStack. Its fields taskIds and taskNames
+ // are 1:1 mapped, where taskNames is the name of root activity in this task.
+ String taskRootActivity = topTask.stackInfo.taskNames[i];
+
+ ComponentName rootActivityName = ComponentName.unflattenFromString(
+ taskRootActivity);
+ if (isActivityDistractionOptimized(
+ rootActivityName.getPackageName(), rootActivityName.getClassName())) {
+ newActivityIntent.putExtra(
+ ActivityBlockingActivity.EXTRA_BLOCKED_TASK, topTask.taskId);
+ if (Log.isLoggable(CarLog.TAG_PACKAGE, Log.INFO)) {
+ Log.i(CarLog.TAG_PACKAGE, "Blocked task " + topTask.taskId
+ + " has DO root activity " + taskRootActivity);
+ }
+ blockedActivityLog.append(". Root DO activity ")
+ .append(rootActivityName.flattenToShortString());
+ }
+ break;
+ }
+ }
+ addLog(blockedActivityLog.toString());
mSystemActivityMonitoringService.blockActivity(topTask, newActivityIntent);
}
@@ -926,6 +971,23 @@
}
/**
+ * Append one line of log for dumpsys.
+ *
+ * <p>Maintains the size of log by {@link #LOG_SIZE} and appends tag and timestamp to the line.
+ */
+ private void addLog(String log) {
+ while (mBlockedActivityLogs.size() >= LOG_SIZE) {
+ mBlockedActivityLogs.remove();
+ }
+ StringBuffer sb = new StringBuffer()
+ .append(CarLog.TAG_PACKAGE).append(':')
+ .append(DateFormat.format(
+ "MM-dd HH:mm:ss", System.currentTimeMillis())).append(": ")
+ .append(log);
+ mBlockedActivityLogs.add(sb.toString());
+ }
+
+ /**
* Reading policy and setting policy can take time. Run it in a separate handler thread.
*/
private class PackageHandler extends Handler {
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
new file mode 100644
index 0000000..1c830f2
--- /dev/null
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import android.annotation.NonNull;
+import android.car.user.CarUserManagerHelper;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.util.Log;
+
+import com.android.car.CarServiceBase;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+
+/**
+ * User service for cars. Manages users at boot time. Including:
+ *
+ * <ol>
+ * <li> Creates a secondary admin user on first run.
+ * <li> Log in to a default user.
+ * <ol/>
+ */
+public class CarUserService extends BroadcastReceiver implements CarServiceBase {
+ // Place holder for user name of the first user created.
+ @VisibleForTesting
+ static final String OWNER_NAME = "Owner";
+ private static final String TAG = "CarUserService";
+ private final Context mContext;
+ private final CarUserManagerHelper mCarUserManagerHelper;
+
+ public CarUserService(
+ @NonNull Context context, @NonNull CarUserManagerHelper carUserManagerHelper) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "constructed");
+ }
+ mContext = context;
+ mCarUserManagerHelper = carUserManagerHelper;
+ }
+
+ @Override
+ public void init() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "init");
+ }
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+
+ mContext.registerReceiver(this, filter);
+ }
+
+ @Override
+ public void release() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "release");
+ }
+ mContext.unregisterReceiver(this);
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ writer.println(TAG);
+ writer.println("Context: " + mContext);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "onReceive " + intent);
+ }
+
+ if (intent.getAction() == Intent.ACTION_LOCKED_BOOT_COMPLETED) {
+ if (mCarUserManagerHelper.getAllUsers().size() == 0) {
+ UserInfo admin = mCarUserManagerHelper.createNewAdminUser(OWNER_NAME);
+ mCarUserManagerHelper.switchToUser(admin);
+ } else {
+ // Add logic for boot into default user.
+ }
+ }
+ }
+}
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index 30313c0..a57d800 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -397,6 +397,11 @@
return super.getSystemService(name);
}
}
+
+ @Override
+ public Context getApplicationContext() {
+ return this;
+ }
}
static final class MockStorageMonitoringInterface implements StorageMonitoringInterface {}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
similarity index 91%
rename from tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java
rename to tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
index ff24b8e..480b84b 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
@@ -57,7 +57,7 @@
* 4. {@link CarUserManagerHelper.OnUsersUpdateListener} registers a listener for user updates.
*/
@RunWith(AndroidJUnit4.class)
-public class CarUserManagerTest {
+public class CarUserManagerHelperTest {
@Mock
private Context mContext;
@Mock
@@ -142,34 +142,6 @@
.containsExactly(mCurrentProcessUser, otherUser1, otherUser2, otherUser3);
}
- // Get all users should exclude system user by default.
- @Test
- public void testGetAllSwitchableUsers() {
- UserInfo user1 = createUserInfoForId(10);
- UserInfo user2 = createUserInfoForId(11);
- UserInfo user3 = createUserInfoForId(12);
-
- List<UserInfo> testUsers = new ArrayList<>();
- testUsers.add(mSystemUser);
- testUsers.add(user1);
- testUsers.add(user2);
- testUsers.add(user3);
-
- when(mUserManager.getUsers(true)).thenReturn(new ArrayList<>(testUsers));
-
- // Should return all 3 non-system users.
- assertThat(mHelper.getAllUsers().size())
- .isEqualTo(3);
-
- when(mUserManager.getUserInfo(UserHandle.myUserId())).thenReturn(user1);
- // Should return user 10, 11 and 12.
- assertThat(mHelper.getAllSwitchableUsers().size())
- .isEqualTo(3);
- assertThat(mHelper.getAllSwitchableUsers()).contains(user1);
- assertThat(mHelper.getAllSwitchableUsers()).contains(user2);
- assertThat(mHelper.getAllSwitchableUsers()).contains(user3);
- }
-
@Test
public void testUserCanBeRemoved() {
UserInfo testInfo = new UserInfo();
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
new file mode 100644
index 0000000..faa7bd0
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.user.CarUserManagerHelper;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * This class contains unit tests for the {@link CarUserService}.
+ *
+ * The following mocks are used:
+ * <ol>
+ * <li> {@link Context} provides system services and resources.
+ * <li> {@link CarUserManagerHelper} provides user info and actions.
+ * <ol/>
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarUserServiceTest {
+ private CarUserService mCarUserService;
+
+ @Mock
+ private Context mMockContext;
+
+ @Mock
+ private Context mApplicationContext;
+
+ @Mock
+ private CarUserManagerHelper mCarUserManagerHelper;
+
+ /**
+ * Initialize all of the objects with the @Mock annotation.
+ */
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mMockContext.getApplicationContext()).thenReturn(mApplicationContext);
+
+ mCarUserService = new CarUserService(mMockContext, mCarUserManagerHelper);
+ }
+
+ /**
+ * Test that the {@link CarUserService} registers to receive the locked boot completed
+ * intent.
+ */
+ @Test
+ public void testRegistersToReceiveEvents() {
+ ArgumentCaptor<IntentFilter> argument = ArgumentCaptor.forClass(IntentFilter.class);
+ mCarUserService.init();
+ verify(mMockContext).registerReceiver(eq(mCarUserService), argument.capture());
+ IntentFilter intentFilter = argument.getValue();
+ assertThat(intentFilter.countActions()).isEqualTo(1);
+
+ assertThat(intentFilter.getAction(0)).isEqualTo(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+ }
+
+ /**
+ * Test that the {@link CarUserService} unregisters its event receivers.
+ */
+ @Test
+ public void testUnregistersEventReceivers() {
+ mCarUserService.release();
+ verify(mMockContext).unregisterReceiver(mCarUserService);
+ }
+
+ /**
+ * Test that the {@link CarUserService} starts up a secondary admin user upon first run.
+ */
+ @Test
+ public void testStartsSecondaryAdminUserOnFirstRun() {
+ List<UserInfo> users = new ArrayList<>();
+
+ int adminUserId = 10;
+ UserInfo admin = new UserInfo(adminUserId, CarUserService.OWNER_NAME, UserInfo.FLAG_ADMIN);
+
+ doReturn(users).when(mCarUserManagerHelper).getAllUsers();
+ // doReturn(users).when(mCarUserManagerHelper.getAllUsers());
+ doReturn(admin).when(mCarUserManagerHelper).createNewAdminUser(CarUserService.OWNER_NAME);
+ doReturn(true).when(mCarUserManagerHelper).switchToUser(admin);
+
+ mCarUserService.onReceive(mMockContext,
+ new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED));
+
+ verify(mCarUserManagerHelper).createNewAdminUser(CarUserService.OWNER_NAME);
+ verify(mCarUserManagerHelper).switchToUser(admin);
+ }
+}
diff --git a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
index 2bf442d..59868d5 100644
--- a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
+++ b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
@@ -49,7 +49,6 @@
newConfig.prop = propConfig.prop;
newConfig.access = propConfig.access;
newConfig.changeMode = propConfig.changeMode;
- newConfig.configFlags = propConfig.configFlags;
newConfig.configString = propConfig.configString;
newConfig.minSampleRate = propConfig.minSampleRate;
newConfig.maxSampleRate = propConfig.maxSampleRate;
@@ -82,12 +81,6 @@
}
@CheckResult
- public VehiclePropConfigBuilder setConfigFlags(int configFlags) {
- mConfig.configFlags = configFlags;
- return this;
- }
-
- @CheckResult
public VehiclePropConfigBuilder setConfigString(String configString) {
mConfig.configString = configString;
return this;