Merge "Refine the SchedulesProvider" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
e0ffd803d5
19
packages/SettingsLib/SchedulesProvider/res/values/config.xml
Normal file
19
packages/SettingsLib/SchedulesProvider/res/values/config.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 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>
|
||||
<!-- Package name for the caller of the Schedules provider. -->
|
||||
<string name="config_schedules_provider_caller_package" translatable="false">com.android.settings</string>
|
||||
</resources>
|
||||
@@ -24,9 +24,9 @@ import android.text.TextUtils;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* This is a schedule data item. It contains the schedule title text, the summary text which
|
||||
* displays on the summary of the Settings preference and an {@link Intent}. Intent is able to
|
||||
* launch the editing page of the schedule data when user clicks this item (preference).
|
||||
* Schedule data item containing the schedule title text, the summary text which is displayed on the
|
||||
* summary of the Settings preference and an {@link Intent} which Settings will launch when the
|
||||
* user clicks on the preference.
|
||||
*/
|
||||
public class ScheduleInfo implements Parcelable {
|
||||
private static final String TAG = "ScheduleInfo";
|
||||
@@ -40,7 +40,7 @@ public class ScheduleInfo implements Parcelable {
|
||||
mIntent = builder.mIntent;
|
||||
}
|
||||
|
||||
protected ScheduleInfo(Parcel in) {
|
||||
private ScheduleInfo(Parcel in) {
|
||||
mTitle = in.readString();
|
||||
mSummary = in.readString();
|
||||
mIntent = in.readParcelable(Intent.class.getClassLoader());
|
||||
@@ -48,8 +48,6 @@ public class ScheduleInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* Returns the title text.
|
||||
*
|
||||
* @return The title.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
@@ -57,15 +55,14 @@ public class ScheduleInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* Returns the summary text.
|
||||
*
|
||||
* @return The summary.
|
||||
*/
|
||||
public String getSummary() {
|
||||
return mSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Intent}.
|
||||
* Returns an {@link Intent} which Settings will launch when the user clicks on a schedule
|
||||
* preference.
|
||||
*/
|
||||
public Intent getIntent() {
|
||||
return mIntent;
|
||||
@@ -107,19 +104,15 @@ public class ScheduleInfo implements Parcelable {
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "title : " + mTitle + " summary : " + mSummary + (mIntent == null
|
||||
? " and intent is null." : ".");
|
||||
return "title: " + mTitle + ", summary: " + mSummary + ", intent: " + mIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple builder for {@link ScheduleInfo}.
|
||||
*/
|
||||
public static class Builder {
|
||||
@NonNull
|
||||
private String mTitle;
|
||||
@NonNull
|
||||
private String mSummary;
|
||||
@NonNull
|
||||
private Intent mIntent;
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,19 +21,18 @@ import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemProperties;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* This provider is a bridge for client apps to provide the schedule data.
|
||||
* Client provider needs to implement their {@link #getScheduleInfoList()} and returns a list of
|
||||
* {@link ScheduleInfo}.
|
||||
* A bridge for client apps to provide the schedule data. Client provider needs to implement
|
||||
* {@link #getScheduleInfoList()} returning a list of {@link ScheduleInfo}.
|
||||
*/
|
||||
public abstract class SchedulesProvider extends ContentProvider {
|
||||
public static final String METHOD_GENERATE_SCHEDULE_INFO_LIST = "generateScheduleInfoList";
|
||||
@@ -46,9 +45,8 @@ public abstract class SchedulesProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Cursor query(
|
||||
Uri uri, String[] projection, String selection, String[] selectionArgs,
|
||||
String sortOrder) {
|
||||
public final Cursor query(Uri uri, String[] projection, String selection,
|
||||
String[] selectionArgs, String sortOrder) {
|
||||
throw new UnsupportedOperationException("Query operation is not supported currently.");
|
||||
}
|
||||
|
||||
@@ -74,18 +72,24 @@ public abstract class SchedulesProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of the schedule information.
|
||||
*
|
||||
* @return a list of the {@link ScheduleInfo}.
|
||||
* Returns the list of the schedule information.
|
||||
*/
|
||||
public abstract ArrayList<ScheduleInfo> getScheduleInfoList();
|
||||
|
||||
/**
|
||||
* Returns a bundle which contains a list of {@link ScheduleInfo} and data types:
|
||||
* scheduleInfoList : ArrayList<ScheduleInfo>
|
||||
* Returns a bundle which contains a list of {@link ScheduleInfo}s:
|
||||
*
|
||||
* <ul>
|
||||
* <li>scheduleInfoList: ArrayList<ScheduleInfo>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
|
||||
if (!TextUtils.equals(getCallingPackage(),
|
||||
getContext().getText(R.string.config_schedules_provider_caller_package))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Bundle bundle = new Bundle();
|
||||
if (METHOD_GENERATE_SCHEDULE_INFO_LIST.equals(method)) {
|
||||
final ArrayList<ScheduleInfo> scheduleInfoList = filterInvalidData(
|
||||
@@ -98,36 +102,40 @@ public abstract class SchedulesProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* To filter the invalid schedule info.
|
||||
* Filters our invalid schedule infos from {@code schedulesInfoList}.
|
||||
*
|
||||
* @param scheduleInfoList The list of the {@link ScheduleInfo}.
|
||||
* @return The valid list of the {@link ScheduleInfo}.
|
||||
* @return valid {@link SchedulesInfo}s if {@code schedulesInfoList} is not null. Otherwise,
|
||||
* null.
|
||||
*/
|
||||
private ArrayList<ScheduleInfo> filterInvalidData(ArrayList<ScheduleInfo> scheduleInfoList) {
|
||||
@Nullable
|
||||
private ArrayList<ScheduleInfo> filterInvalidData(
|
||||
@Nullable ArrayList<ScheduleInfo> scheduleInfoList) {
|
||||
if (scheduleInfoList == null) {
|
||||
Log.d(TAG, "package : " + getContext().getPackageName() + " has no scheduling data.");
|
||||
return null;
|
||||
}
|
||||
// Dump invalid data in debug mode.
|
||||
if (SystemProperties.getInt("ro.debuggable", 0) == 1) {
|
||||
new Thread(() -> {
|
||||
dumpInvalidData(scheduleInfoList);
|
||||
}).start();
|
||||
dumpInvalidData(scheduleInfoList);
|
||||
}
|
||||
final List<ScheduleInfo> filteredList = scheduleInfoList
|
||||
return scheduleInfoList
|
||||
.stream()
|
||||
.filter(scheduleInfo -> scheduleInfo.isValid())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new ArrayList<>(filteredList);
|
||||
.filter(ScheduleInfo::isValid)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
private void dumpInvalidData(ArrayList<ScheduleInfo> scheduleInfoList) {
|
||||
Log.d(TAG, "package : " + getContext().getPackageName()
|
||||
+ " provided some scheduling data are invalid.");
|
||||
scheduleInfoList
|
||||
final boolean hasInvalidData = scheduleInfoList
|
||||
.stream()
|
||||
.filter(scheduleInfo -> !scheduleInfo.isValid())
|
||||
.forEach(scheduleInfo -> Log.d(TAG, scheduleInfo.toString()));
|
||||
.anyMatch(scheduleInfo -> !scheduleInfo.isValid());
|
||||
|
||||
if (hasInvalidData) {
|
||||
Log.w(TAG, "package : " + getContext().getPackageName()
|
||||
+ " provided some scheduling data that are invalid.");
|
||||
scheduleInfoList
|
||||
.stream()
|
||||
.filter(scheduleInfo -> !scheduleInfo.isValid())
|
||||
.forEach(scheduleInfo -> Log.w(TAG, scheduleInfo.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settingslib.schedulesprovider;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class ScheduleInfoTest {
|
||||
private static final String TEST_TITLE = "Night Light";
|
||||
private static final String TEST_SUMMARY = "Night Light summary";
|
||||
private static final String TEST_EMPTY_SUMMARY = "";
|
||||
|
||||
@Test
|
||||
public void builder_usedValidArguments_isValid() {
|
||||
final Intent intent = createTestIntent();
|
||||
final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
|
||||
|
||||
assertThat(info).isNotNull();
|
||||
assertThat(info.isValid()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builder_useEmptySummary_isInvalid() {
|
||||
final Intent intent = createTestIntent();
|
||||
final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY, intent);
|
||||
|
||||
assertThat(info).isNotNull();
|
||||
assertThat(info.isValid()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builder_intentIsNull_isInvalid() {
|
||||
final ScheduleInfo info = new ScheduleInfo.Builder()
|
||||
.setTitle(TEST_TITLE)
|
||||
.setSummary(TEST_SUMMARY)
|
||||
.build();
|
||||
|
||||
assertThat(info).isNotNull();
|
||||
assertThat(info.isValid()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTitle_setValidTitle_shouldReturnSameCorrectTitle() {
|
||||
final Intent intent = createTestIntent();
|
||||
final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
|
||||
|
||||
assertThat(info.getTitle()).isEqualTo(TEST_TITLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSummary_setValidSummary_shouldReturnSameCorrectSummary() {
|
||||
final Intent intent = createTestIntent();
|
||||
final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
|
||||
|
||||
assertThat(info.getSummary()).isEqualTo(TEST_SUMMARY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIntent_setValidIntent_shouldReturnSameCorrectIntent() {
|
||||
final Intent intent = createTestIntent();
|
||||
final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
|
||||
|
||||
assertThat(info.getIntent()).isEqualTo(intent);
|
||||
}
|
||||
|
||||
private static Intent createTestIntent() {
|
||||
return new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
|
||||
Intent.CATEGORY_DEFAULT);
|
||||
}
|
||||
|
||||
private static ScheduleInfo createTestScheduleInfo(String title, String summary,
|
||||
Intent intent) {
|
||||
return new ScheduleInfo.Builder()
|
||||
.setTitle(title)
|
||||
.setSummary(summary)
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settingslib.schedulesprovider;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class SchedulesProviderTest {
|
||||
private static final String INVALID_PACKAGE = "com.android.sunny";
|
||||
private static final String VALID_PACKAGE = "com.android.settings";
|
||||
private static final String INVALID_METHOD = "queryTestData";
|
||||
private TestSchedulesProvider mProvider;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mProvider = Robolectric.setupContentProvider(TestSchedulesProvider.class);
|
||||
shadowOf(mProvider).setCallingPackage(VALID_PACKAGE);
|
||||
mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void call_invalidCallingPkg_returnNull() {
|
||||
shadowOf(mProvider).setCallingPackage(INVALID_PACKAGE);
|
||||
|
||||
final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
|
||||
null /* arg */, null /* extras */);
|
||||
|
||||
assertThat(bundle).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void call_invalidMethod_returnBundleWithoutScheduleInfoData() {
|
||||
final Bundle bundle = mProvider.call(INVALID_METHOD, null /* arg */, null /* extras */);
|
||||
|
||||
assertThat(bundle).isNotNull();
|
||||
assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void call_validMethod_returnScheduleInfoData() {
|
||||
final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
|
||||
null /* arg */, null /* extras */);
|
||||
|
||||
assertThat(bundle).isNotNull();
|
||||
assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue();
|
||||
final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList(
|
||||
SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST);
|
||||
assertThat(infos).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void call_addTwoValidData_returnScheduleInfoData() {
|
||||
mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos());
|
||||
final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
|
||||
null /* arg */, null /* extras */);
|
||||
|
||||
assertThat(bundle).isNotNull();
|
||||
assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue();
|
||||
final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList(
|
||||
SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST);
|
||||
assertThat(infos).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void call_addTwoValidDataAndOneInvalidData_returnTwoScheduleInfoData() {
|
||||
mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo());
|
||||
final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
|
||||
null /* arg */, null /* extras */);
|
||||
|
||||
assertThat(bundle).isNotNull();
|
||||
assertThat(bundle.containsKey(SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST)).isTrue();
|
||||
final ArrayList<ScheduleInfo> infos = bundle.getParcelableArrayList(
|
||||
SchedulesProvider.BUNDLE_SCHEDULE_INFO_LIST);
|
||||
assertThat(infos).hasSize(2);
|
||||
}
|
||||
|
||||
private static class TestSchedulesProvider extends SchedulesProvider {
|
||||
private ArrayList<ScheduleInfo> mScheduleInfos = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public ArrayList<ScheduleInfo> getScheduleInfoList() {
|
||||
return mScheduleInfos;
|
||||
}
|
||||
|
||||
void setScheduleInfos(ArrayList<ScheduleInfo> scheduleInfos) {
|
||||
mScheduleInfos = scheduleInfos;
|
||||
}
|
||||
|
||||
private static ArrayList<ScheduleInfo> createOneValidScheduleInfo() {
|
||||
final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
|
||||
final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
|
||||
Intent.CATEGORY_DEFAULT);
|
||||
final ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
|
||||
"Night Light").setSummary("This a sunny test").setIntent(intent).build();
|
||||
scheduleInfos.add(info);
|
||||
|
||||
return scheduleInfos;
|
||||
}
|
||||
|
||||
private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos() {
|
||||
final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
|
||||
Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
|
||||
Intent.CATEGORY_DEFAULT);
|
||||
ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
|
||||
"Night Light").setSummary("This a sunny test").setIntent(intent).build();
|
||||
scheduleInfos.add(info);
|
||||
|
||||
intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
|
||||
Intent.CATEGORY_DEFAULT);
|
||||
info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
|
||||
"Display summary").setIntent(intent).build();
|
||||
scheduleInfos.add(info);
|
||||
|
||||
return scheduleInfos;
|
||||
}
|
||||
|
||||
private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo() {
|
||||
final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
|
||||
Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
|
||||
Intent.CATEGORY_DEFAULT);
|
||||
ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
|
||||
"Night Light").setSummary("This a sunny test").setIntent(intent).build();
|
||||
scheduleInfos.add(info);
|
||||
|
||||
intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
|
||||
Intent.CATEGORY_DEFAULT);
|
||||
info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
|
||||
"Display summary").setIntent(intent).build();
|
||||
scheduleInfos.add(info);
|
||||
|
||||
intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
|
||||
Intent.CATEGORY_DEFAULT);
|
||||
info = new ScheduleInfo.Builder().setTitle("").setSummary("Display summary").setIntent(
|
||||
intent).build();
|
||||
scheduleInfos.add(info);
|
||||
|
||||
return scheduleInfos;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user