New mechanism to enable ventors to present Google legal items
dynamically.
Bug: 113576118
Test: RunCarSettingsRoboTests, Manual Test
Change-Id: I1a00c9aa305c548b692bc820519eada460c826f5
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d9e64fa..7c6dc05 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -263,8 +263,13 @@
</activity>
<activity android:name=".system.ThirdPartyLicensesActivity"
+ android:label="@string/settings_license_activity_title"
android:configChanges="orientation|keyboardHidden|screenSize"
android:windowSoftInputMode="adjustResize">
+ <intent-filter>
+ <action android:name="android.settings.THIRD_PARTY_LICENSE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
</activity>
<!-- This logic is copied from phone.-->
diff --git a/res/xml/legal_information_fragment.xml b/res/xml/legal_information_fragment.xml
index 5e1541a..e7e343f 100644
--- a/res/xml/legal_information_fragment.xml
+++ b/res/xml/legal_information_fragment.xml
@@ -19,18 +19,22 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/legal_information">
+
+ <!-- Terms and conditions -->
+ <Preference
+ android:key="terms"
+ android:title="@string/terms_title"
+ settings:controller="com.android.car.settings.system.legal.TermsPreferenceController"/>
+
+ <!-- System WebView License information -->
<Preference
android:key="@string/pk_system_license_entry"
android:title="@string/webview_license_title"
- settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController">
- <intent android:action="android.settings.WEBVIEW_LICENSE"/>
- </Preference>
+ settings:controller="com.android.car.settings.system.legal.WebViewLicensePreferenceController"/>
+
<Preference
android:key="@string/pk_third_party_license_entry"
android:title="@string/settings_license_activity_title"
- settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController">
- <intent
- android:targetClass="com.android.car.settings.system.ThirdPartyLicensesActivity"
- android:targetPackage="com.android.car.settings"/>
- </Preference>
+ settings:controller="com.android.car.settings.system.legal.ThirdPartyLicensePreferenceController"/>
+
</PreferenceScreen>
diff --git a/src/com/android/car/settings/system/legal/LegalPreferenceController.java b/src/com/android/car/settings/system/legal/LegalPreferenceController.java
new file mode 100644
index 0000000..d05c852
--- /dev/null
+++ b/src/com/android/car/settings/system/legal/LegalPreferenceController.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019 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.settings.system.legal;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import androidx.preference.Preference;
+
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.common.PreferenceController;
+
+import java.util.List;
+
+/**
+ * Base class for legal preferences. Locates an activity coupled with the given intent and updates
+ * the preference accordingly.
+ */
+public abstract class LegalPreferenceController extends PreferenceController<Preference> {
+ private final PackageManager mPackageManager;
+ private ResolveInfo mResolveInfo;
+
+ public LegalPreferenceController(Context context, String preferenceKey,
+ FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
+ super(context, preferenceKey, fragmentController, uxRestrictions);
+ mPackageManager = context.getPackageManager();
+ }
+
+ @Override
+ protected Class<Preference> getPreferenceType() {
+ return Preference.class;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ mResolveInfo = findMatchingSpecificActivity();
+ return mResolveInfo != null ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ protected void updateState(Preference preference) {
+ if (mResolveInfo == null) {
+ return;
+ }
+
+ // Replace the intent with this specific activity.
+ preference.setIntent(new Intent().setClassName(
+ mResolveInfo.activityInfo.packageName,
+ mResolveInfo.activityInfo.name));
+
+ preference.setTitle(mResolveInfo.loadLabel(mPackageManager));
+ }
+
+ /** Intent with a matching system activity to display legal disclaimers or licenses. */
+ protected abstract Intent getIntent();
+
+ private ResolveInfo findMatchingSpecificActivity() {
+ Intent intent = getIntent();
+ if (intent == null) {
+ return null;
+ }
+
+ // Find the activity that is in the system image.
+ List<ResolveInfo> list = mPackageManager.queryIntentActivities(intent, /* flags= */ 0);
+ if (list == null) {
+ return null;
+ }
+
+ for (ResolveInfo resolveInfo : list) {
+ if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ != 0) {
+ return resolveInfo;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/car/settings/system/legal/TermsPreferenceController.java b/src/com/android/car/settings/system/legal/TermsPreferenceController.java
new file mode 100644
index 0000000..5381a64
--- /dev/null
+++ b/src/com/android/car/settings/system/legal/TermsPreferenceController.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.settings.system.legal;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.car.settings.common.FragmentController;
+
+/** Links to a system activity that displays Terms and Conditions. */
+public class TermsPreferenceController extends LegalPreferenceController {
+ private static final Intent INTENT = new Intent("android.settings.TERMS");
+
+ public TermsPreferenceController(Context context, String preferenceKey,
+ FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
+ super(context, preferenceKey, fragmentController, uxRestrictions);
+ }
+
+ @Override
+ protected Intent getIntent() {
+ return INTENT;
+ }
+}
diff --git a/src/com/android/car/settings/system/legal/ThirdPartyLicensePreferenceController.java b/src/com/android/car/settings/system/legal/ThirdPartyLicensePreferenceController.java
new file mode 100644
index 0000000..c239bc9
--- /dev/null
+++ b/src/com/android/car/settings/system/legal/ThirdPartyLicensePreferenceController.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.settings.system.legal;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.car.settings.common.FragmentController;
+
+/** Links to a system activity that displays a list of third party licenses. */
+public class ThirdPartyLicensePreferenceController extends LegalPreferenceController {
+ private static final Intent INTENT = new Intent("android.settings.THIRD_PARTY_LICENSE");
+
+ public ThirdPartyLicensePreferenceController(Context context, String preferenceKey,
+ FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
+ super(context, preferenceKey, fragmentController, uxRestrictions);
+ }
+
+ @Override
+ protected Intent getIntent() {
+ return INTENT;
+ }
+}
diff --git a/src/com/android/car/settings/system/legal/WebViewLicensePreferenceController.java b/src/com/android/car/settings/system/legal/WebViewLicensePreferenceController.java
new file mode 100644
index 0000000..e25f7c2
--- /dev/null
+++ b/src/com/android/car/settings/system/legal/WebViewLicensePreferenceController.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 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.settings.system.legal;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.car.settings.common.FragmentController;
+
+/** Links to a system activity that displays System Webview Licenses. */
+public class WebViewLicensePreferenceController extends LegalPreferenceController {
+ private static final Intent INTENT = new Intent("android.settings.WEBVIEW_LICENSE");
+
+ public WebViewLicensePreferenceController(Context context, String preferenceKey,
+ FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
+ super(context, preferenceKey, fragmentController, uxRestrictions);
+ }
+
+ @Override
+ protected Intent getIntent() {
+ return INTENT;
+ }
+}
diff --git a/tests/robotests/src/com/android/car/settings/system/legal/LegalPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/system/legal/LegalPreferenceControllerTest.java
new file mode 100644
index 0000000..a01e6ef
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/system/legal/LegalPreferenceControllerTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2019 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.settings.system.legal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.Preference;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.common.PreferenceControllerTestHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.shadows.ShadowPackageManager;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/** Unit test for {@link LegalPreferenceController}. */
+@RunWith(CarSettingsRobolectricTestRunner.class)
+public class LegalPreferenceControllerTest {
+ private static class TestLegalPreferenceControllerTest extends
+ LegalPreferenceController {
+
+ private static final Intent INTENT = new Intent("test_intent");
+
+ TestLegalPreferenceControllerTest(Context context, String preferenceKey,
+ FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
+ super(context, preferenceKey, fragmentController, uxRestrictions);
+ }
+
+ @Override
+ protected Intent getIntent() {
+ return INTENT;
+ }
+ }
+
+ private static final String TEST_LABEL = "test_label";
+ private Context mContext;
+ private PreferenceControllerTestHelper<TestLegalPreferenceControllerTest> mControllerHelper;
+ private Preference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mPreference = new Preference(mContext);
+ mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
+ TestLegalPreferenceControllerTest.class, mPreference);
+ }
+
+ @Test
+ public void refreshUi_intentResolvesToActivity_isVisible() {
+ Intent intent = mControllerHelper.getController().getIntent();
+
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = "some.test.package";
+ activityInfo.name = "SomeActivity";
+ activityInfo.applicationInfo = new ApplicationInfo();
+ activityInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+ ResolveInfo resolveInfo = new ResolveInfo() {
+ @Override
+ public CharSequence loadLabel(PackageManager pm) {
+ return TEST_LABEL;
+ }
+ };
+ resolveInfo.activityInfo = activityInfo;
+ List<ResolveInfo> list = new LinkedList();
+ list.add(resolveInfo);
+
+ ShadowPackageManager packageManager = Shadows.shadowOf(mContext.getPackageManager());
+ packageManager.addResolveInfoForIntent(intent, list);
+
+ mControllerHelper.markState(Lifecycle.State.CREATED);
+ mControllerHelper.getController().refreshUi();
+
+ assertThat(mPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void refreshUi_intentResolvesToActivity_updatesTitle() {
+ Intent intent = mControllerHelper.getController().getIntent();
+
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = "some.test.package";
+ activityInfo.name = "SomeActivity";
+ activityInfo.applicationInfo = new ApplicationInfo();
+ activityInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+ ResolveInfo resolveInfo = new ResolveInfo() {
+ @Override
+ public CharSequence loadLabel(PackageManager pm) {
+ return TEST_LABEL;
+ }
+ };
+ resolveInfo.activityInfo = activityInfo;
+ List<ResolveInfo> list = new LinkedList();
+ list.add(resolveInfo);
+
+ ShadowPackageManager packageManager = Shadows.shadowOf(mContext.getPackageManager());
+ packageManager.addResolveInfoForIntent(intent, list);
+
+ mControllerHelper.markState(Lifecycle.State.CREATED);
+ mControllerHelper.getController().refreshUi();
+
+ assertThat(mPreference.getTitle()).isEqualTo(TEST_LABEL);
+ }
+
+ @Test
+ public void refreshUi_intentResolvesToActivity_updatesIntentToSpecificActivity() {
+ Intent intent = mControllerHelper.getController().getIntent();
+
+ String packageName = "com.android.car.settings.testutils";
+ String activityName = "BaseTestActivity";
+
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = packageName;
+ activityInfo.name = activityName;
+ activityInfo.applicationInfo = new ApplicationInfo();
+ activityInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+ ResolveInfo resolveInfo = new ResolveInfo() {
+ @Override
+ public CharSequence loadLabel(PackageManager pm) {
+ return TEST_LABEL;
+ }
+ };
+ resolveInfo.activityInfo = activityInfo;
+ List<ResolveInfo> list = new LinkedList();
+ list.add(resolveInfo);
+
+ ShadowPackageManager packageManager = Shadows.shadowOf(mContext.getPackageManager());
+ packageManager.addResolveInfoForIntent(intent, list);
+
+ mControllerHelper.markState(Lifecycle.State.CREATED);
+ mControllerHelper.getController().refreshUi();
+
+ assertThat(mPreference.getIntent().getComponent().flattenToString()).isEqualTo(
+ packageName + "/" + activityName);
+ }
+
+ @Test
+ public void refreshUi_intentResolvesToNull_isNotVisible() {
+ ShadowPackageManager packageManager = Shadows.shadowOf(mContext.getPackageManager());
+
+ packageManager.addResolveInfoForIntent(mControllerHelper.getController().getIntent(),
+ Collections.emptyList());
+
+ mControllerHelper.markState(Lifecycle.State.CREATED);
+ mControllerHelper.getController().refreshUi();
+
+ assertThat(mPreference.isVisible()).isFalse();
+ }
+}