Loading services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +6 −14 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.res.Resources.ID_NULL; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import static com.android.server.appwidget.AppWidgetXmlUtil.deserializeWidgetSizesStr; import static com.android.server.appwidget.AppWidgetXmlUtil.serializeWidgetSizes; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.Manifest; Loading Loading @@ -164,7 +166,6 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import java.util.function.LongSupplier; import java.util.stream.Collectors; class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider, OnCrossProfileWidgetProvidersChangeListener { Loading @@ -179,7 +180,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private static final String STATE_FILENAME = "appwidgets.xml"; private static final String KEY_SIZES = "sizes"; private static final String SIZE_SEPARATOR = ","; private static final int MIN_UPDATE_PERIOD = DEBUG ? 0 : 30 * 60 * 1000; // 30 minutes Loading Loading @@ -2718,9 +2718,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku List<SizeF> sizes = widget.options.getParcelableArrayList( AppWidgetManager.OPTION_APPWIDGET_SIZES, SizeF.class); if (sizes != null) { String sizeStr = sizes.stream().map(SizeF::toString) .collect(Collectors.joining(SIZE_SEPARATOR)); out.attribute(null, KEY_SIZES, sizeStr); out.attribute(null, KEY_SIZES, serializeWidgetSizes(sizes)); } if (saveRestoreCompleted) { boolean restoreCompleted = widget.options.getBoolean( Loading Loading @@ -2754,15 +2752,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight); } String sizesStr = parser.getAttributeValue(null, KEY_SIZES); if (sizesStr != null) { try { ArrayList<SizeF> sizes = Arrays.stream(sizesStr.split(SIZE_SEPARATOR)) .map(SizeF::parseSizeF) .collect(Collectors.toCollection(ArrayList::new)); ArrayList<SizeF> sizes = deserializeWidgetSizesStr(sizesStr); if (sizes != null) { options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, sizes); } catch (NumberFormatException e) { Slog.e(TAG, "Error parsing widget sizes", e); } } int category = parser.getAttributeIntHex(null, "host_category", AppWidgetProviderInfo.WIDGET_CATEGORY_UNKNOWN); Loading services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java +28 −0 Original line number Diff line number Diff line Loading @@ -22,12 +22,18 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.os.Build; import android.text.TextUtils; import android.util.SizeF; import android.util.Slog; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; /** * @hide Loading Loading @@ -59,6 +65,7 @@ public class AppWidgetXmlUtil { private static final String ATTR_DESCRIPTION_RES = "description_res"; private static final String ATTR_PROVIDER_INHERITANCE = "provider_inheritance"; private static final String ATTR_OS_FINGERPRINT = "os_fingerprint"; private static final String SIZE_SEPARATOR = ","; /** * @hide Loading Loading @@ -137,4 +144,25 @@ public class AppWidgetXmlUtil { ATTR_PROVIDER_INHERITANCE, false); return info; } @NonNull static String serializeWidgetSizes(@NonNull List<SizeF> sizes) { return sizes.stream().map(SizeF::toString) .collect(Collectors.joining(SIZE_SEPARATOR)); } @Nullable static ArrayList<SizeF> deserializeWidgetSizesStr(@Nullable String sizesStr) { if (sizesStr == null || sizesStr.isEmpty()) { return null; } try { return Arrays.stream(sizesStr.split(SIZE_SEPARATOR)) .map(SizeF::parseSizeF) .collect(Collectors.toCollection(ArrayList::new)); } catch (NumberFormatException e) { Slog.e(TAG, "Error parsing widget sizes", e); return null; } } } services/tests/servicestests/src/com/android/server/appwidget/AppWidgetXmlUtilTest.kt 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.server.appwidget import android.util.SizeF import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.server.appwidget.AppWidgetXmlUtil.deserializeWidgetSizesStr import com.android.server.appwidget.AppWidgetXmlUtil.serializeWidgetSizes import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class AppWidgetXmlUtilTest { private val sizes = ArrayList<SizeF>() private val sizeStr = "1.0x2.1,-9.91x6291.134,0.0x0.0" @Before fun setup() { sizes.add(SizeF(1.0f, 2.1f)) sizes.add(SizeF(-9.91f, 6291.134f)) sizes.add(SizeF(0f, 0f)) } @Test fun serializeWidgetSizes() { val serializedSizeStr = serializeWidgetSizes(sizes) assertThat(serializedSizeStr).isEqualTo(sizeStr) } @Test fun deserializeWidgetSizesStr() { val deserializedSizes = deserializeWidgetSizesStr(sizeStr) assertThat(deserializedSizes).isEqualTo(sizes) } @Test fun deserializeInvalidWidgetSizesStr1() { assertThat(deserializeWidgetSizesStr("abc,def")).isEqualTo(null) } @Test fun deserializeInvalidWidgetSizesStr2() { assertThat(deserializeWidgetSizesStr("+30x9,90")).isEqualTo(null) } @Test fun deserializeNullWidgetSizesStr1() { assertThat(deserializeWidgetSizesStr(null)).isEqualTo(null) } @Test fun deserializeEmptyWidgetSizesStr1() { assertThat(deserializeWidgetSizesStr("")).isEqualTo(null) } @Test fun deserializeEmptyWidgetSizesStr2() { assertThat(deserializeWidgetSizesStr(",")).isEqualTo(ArrayList<SizeF>()) } @Test fun deserializeEmptyWidgetSizesStr3() { assertThat(deserializeWidgetSizesStr(",,,")).isEqualTo(ArrayList<SizeF>()) } } Loading
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +6 −14 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.res.Resources.ID_NULL; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import static com.android.server.appwidget.AppWidgetXmlUtil.deserializeWidgetSizesStr; import static com.android.server.appwidget.AppWidgetXmlUtil.serializeWidgetSizes; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.Manifest; Loading Loading @@ -164,7 +166,6 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import java.util.function.LongSupplier; import java.util.stream.Collectors; class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider, OnCrossProfileWidgetProvidersChangeListener { Loading @@ -179,7 +180,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private static final String STATE_FILENAME = "appwidgets.xml"; private static final String KEY_SIZES = "sizes"; private static final String SIZE_SEPARATOR = ","; private static final int MIN_UPDATE_PERIOD = DEBUG ? 0 : 30 * 60 * 1000; // 30 minutes Loading Loading @@ -2718,9 +2718,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku List<SizeF> sizes = widget.options.getParcelableArrayList( AppWidgetManager.OPTION_APPWIDGET_SIZES, SizeF.class); if (sizes != null) { String sizeStr = sizes.stream().map(SizeF::toString) .collect(Collectors.joining(SIZE_SEPARATOR)); out.attribute(null, KEY_SIZES, sizeStr); out.attribute(null, KEY_SIZES, serializeWidgetSizes(sizes)); } if (saveRestoreCompleted) { boolean restoreCompleted = widget.options.getBoolean( Loading Loading @@ -2754,15 +2752,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight); } String sizesStr = parser.getAttributeValue(null, KEY_SIZES); if (sizesStr != null) { try { ArrayList<SizeF> sizes = Arrays.stream(sizesStr.split(SIZE_SEPARATOR)) .map(SizeF::parseSizeF) .collect(Collectors.toCollection(ArrayList::new)); ArrayList<SizeF> sizes = deserializeWidgetSizesStr(sizesStr); if (sizes != null) { options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, sizes); } catch (NumberFormatException e) { Slog.e(TAG, "Error parsing widget sizes", e); } } int category = parser.getAttributeIntHex(null, "host_category", AppWidgetProviderInfo.WIDGET_CATEGORY_UNKNOWN); Loading
services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java +28 −0 Original line number Diff line number Diff line Loading @@ -22,12 +22,18 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.os.Build; import android.text.TextUtils; import android.util.SizeF; import android.util.Slog; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; /** * @hide Loading Loading @@ -59,6 +65,7 @@ public class AppWidgetXmlUtil { private static final String ATTR_DESCRIPTION_RES = "description_res"; private static final String ATTR_PROVIDER_INHERITANCE = "provider_inheritance"; private static final String ATTR_OS_FINGERPRINT = "os_fingerprint"; private static final String SIZE_SEPARATOR = ","; /** * @hide Loading Loading @@ -137,4 +144,25 @@ public class AppWidgetXmlUtil { ATTR_PROVIDER_INHERITANCE, false); return info; } @NonNull static String serializeWidgetSizes(@NonNull List<SizeF> sizes) { return sizes.stream().map(SizeF::toString) .collect(Collectors.joining(SIZE_SEPARATOR)); } @Nullable static ArrayList<SizeF> deserializeWidgetSizesStr(@Nullable String sizesStr) { if (sizesStr == null || sizesStr.isEmpty()) { return null; } try { return Arrays.stream(sizesStr.split(SIZE_SEPARATOR)) .map(SizeF::parseSizeF) .collect(Collectors.toCollection(ArrayList::new)); } catch (NumberFormatException e) { Slog.e(TAG, "Error parsing widget sizes", e); return null; } } }
services/tests/servicestests/src/com/android/server/appwidget/AppWidgetXmlUtilTest.kt 0 → 100644 +86 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.server.appwidget import android.util.SizeF import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.server.appwidget.AppWidgetXmlUtil.deserializeWidgetSizesStr import com.android.server.appwidget.AppWidgetXmlUtil.serializeWidgetSizes import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class AppWidgetXmlUtilTest { private val sizes = ArrayList<SizeF>() private val sizeStr = "1.0x2.1,-9.91x6291.134,0.0x0.0" @Before fun setup() { sizes.add(SizeF(1.0f, 2.1f)) sizes.add(SizeF(-9.91f, 6291.134f)) sizes.add(SizeF(0f, 0f)) } @Test fun serializeWidgetSizes() { val serializedSizeStr = serializeWidgetSizes(sizes) assertThat(serializedSizeStr).isEqualTo(sizeStr) } @Test fun deserializeWidgetSizesStr() { val deserializedSizes = deserializeWidgetSizesStr(sizeStr) assertThat(deserializedSizes).isEqualTo(sizes) } @Test fun deserializeInvalidWidgetSizesStr1() { assertThat(deserializeWidgetSizesStr("abc,def")).isEqualTo(null) } @Test fun deserializeInvalidWidgetSizesStr2() { assertThat(deserializeWidgetSizesStr("+30x9,90")).isEqualTo(null) } @Test fun deserializeNullWidgetSizesStr1() { assertThat(deserializeWidgetSizesStr(null)).isEqualTo(null) } @Test fun deserializeEmptyWidgetSizesStr1() { assertThat(deserializeWidgetSizesStr("")).isEqualTo(null) } @Test fun deserializeEmptyWidgetSizesStr2() { assertThat(deserializeWidgetSizesStr(",")).isEqualTo(ArrayList<SizeF>()) } @Test fun deserializeEmptyWidgetSizesStr3() { assertThat(deserializeWidgetSizesStr(",,,")).isEqualTo(ArrayList<SizeF>()) } }