diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index fde8bfe7cadd8..bb1f393b99bcd 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -31,12 +31,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.content.pm.ServiceInfo; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -45,11 +39,9 @@ import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; -import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; import android.util.Slog; -import android.util.Xml; import android.view.ActionMode; import android.view.Display; import android.view.KeyEvent; @@ -65,14 +57,9 @@ import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityEvent; -import com.android.internal.R; import com.android.internal.util.DumpUtils; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import java.io.FileDescriptor; -import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.function.Consumer; @@ -172,9 +159,8 @@ import java.util.function.Consumer; * */ public class DreamService extends Service implements Window.Callback { - private static final String TAG = DreamService.class.getSimpleName(); - private final String mTag = TAG + "[" + getClass().getSimpleName() + "]"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private final String mTag = + DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; /** * The name of the dream manager service. @@ -204,11 +190,6 @@ public class DreamService extends Service implements Window.Callback { */ public static final String DREAM_META_DATA = "android.service.dream"; - /** - * Name of the root tag under which a Dream defines its metadata in an XML file. - */ - private static final String DREAM_META_DATA_ROOT_TAG = "dream"; - /** * Extra containing a boolean for whether to show complications on the overlay. * @hide @@ -258,16 +239,13 @@ public class DreamService extends Service implements Window.Callback { mRequests = new ArrayDeque<>(); } - public void bind(Context context, @Nullable ComponentName overlayService, - ComponentName dreamService) { + public void bind(Context context, @Nullable ComponentName overlayService) { if (overlayService == null) { return; } final Intent overlayIntent = new Intent(); overlayIntent.setComponent(overlayService); - overlayIntent.putExtra(EXTRA_SHOW_COMPLICATIONS, - fetchShouldShowComplications(context, dreamService)); context.bindService(overlayIntent, this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE); @@ -989,8 +967,7 @@ public class DreamService extends Service implements Window.Callback { // Connect to the overlay service if present. if (!mWindowless) { - mOverlayConnection.bind(this, intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT), - new ComponentName(this, getClass())); + mOverlayConnection.bind(this, intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT)); } return mDreamServiceWrapper; @@ -1103,84 +1080,6 @@ public class DreamService extends Service implements Window.Callback { // end public api - /** - * Parses and returns metadata of the dream service indicated by the service info. Returns null - * if metadata cannot be found. - * - * Note that {@link ServiceInfo} must be fetched with {@link PackageManager#GET_META_DATA} flag. - * - * @hide - */ - @Nullable - public static DreamMetadata getDreamMetadata(Context context, ServiceInfo serviceInfo) { - final PackageManager pm = context.getPackageManager(); - - final TypedArray rawMetadata = readMetadata(pm, serviceInfo); - if (rawMetadata == null) return null; - - final DreamMetadata metadata = new DreamMetadata( - convertToComponentName(rawMetadata.getString( - com.android.internal.R.styleable.Dream_settingsActivity), serviceInfo), - rawMetadata.getDrawable( - com.android.internal.R.styleable.Dream_previewImage), - rawMetadata.getBoolean(R.styleable.Dream_showClockAndComplications, - DEFAULT_SHOW_COMPLICATIONS)); - rawMetadata.recycle(); - return metadata; - } - - /** - * Returns the raw XML metadata fetched from the ${@link ServiceInfo}. - * - * Returns null if the ${@link ServiceInfo} doesn't contain valid dream metadata. - */ - @Nullable - private static TypedArray readMetadata(PackageManager pm, ServiceInfo serviceInfo) { - if (serviceInfo == null || serviceInfo.metaData == null) { - return null; - } - - try (XmlResourceParser parser = - serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA)) { - if (parser == null) { - if (DEBUG) Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " metadata"); - return null; - } - - final Resources res = pm.getResourcesForApplication(serviceInfo.applicationInfo); - final AttributeSet attrs = Xml.asAttributeSet(parser); - while (true) { - final int type = parser.next(); - if (type == XmlPullParser.END_DOCUMENT || type == XmlPullParser.START_TAG) { - break; - } - } - - if (!parser.getName().equals(DREAM_META_DATA_ROOT_TAG)) { - if (DEBUG) { - Log.w(TAG, "Metadata does not start with " + DREAM_META_DATA_ROOT_TAG + " tag"); - } - return null; - } - - return res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream); - } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) { - if (DEBUG) Log.e(TAG, "Error parsing: " + serviceInfo.packageName, e); - return null; - } - } - - private static ComponentName convertToComponentName(String flattenedString, - ServiceInfo serviceInfo) { - if (flattenedString == null) return null; - - if (!flattenedString.contains("/")) { - return new ComponentName(serviceInfo.packageName, flattenedString); - } - - return ComponentName.unflattenFromString(flattenedString); - } - /** * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed. * @@ -1343,30 +1242,6 @@ public class DreamService extends Service implements Window.Callback { return (oldFlags&~mask) | (flags&mask); } - /** - * Fetches metadata of the dream indicated by the ${@link ComponentName}, and returns whether - * the dream should show complications on the overlay. If not defined, returns - * ${@link DreamService#DEFAULT_SHOW_COMPLICATIONS}. - */ - private static boolean fetchShouldShowComplications(Context context, - ComponentName componentName) { - final PackageManager pm = context.getPackageManager(); - - try { - final ServiceInfo si = pm.getServiceInfo(componentName, - PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA)); - final DreamMetadata metadata = getDreamMetadata(context, si); - - if (metadata != null) { - return metadata.showComplications; - } - } catch (PackageManager.NameNotFoundException e) { - if (DEBUG) Log.w(TAG, "cannot find component " + componentName.flattenToShortString()); - } - - return DEFAULT_SHOW_COMPLICATIONS; - } - @Override protected void dump(final FileDescriptor fd, PrintWriter pw, final String[] args) { DumpUtils.dumpAsync(mHandler, (pw1, prefix) -> dumpOnHandler(fd, pw1, args), pw, "", 1000); @@ -1427,27 +1302,4 @@ public class DreamService extends Service implements Window.Callback { onWindowCreated(a.getWindow()); } } - - /** - * Represents metadata defined in {@link android.R.styleable#Dream <dream>}. - * - * @hide - */ - public static final class DreamMetadata { - @Nullable - public final ComponentName settingsActivity; - - @Nullable - public final Drawable previewImage; - - @Nullable - public final boolean showComplications; - - DreamMetadata(ComponentName settingsActivity, Drawable previewImage, - boolean showComplications) { - this.settingsActivity = settingsActivity; - this.previewImage = previewImage; - this.showComplications = showComplications; - } - } } diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java index 6ef8d3938471f..a000c099347d1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java @@ -26,6 +26,8 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.os.RemoteException; import android.os.ServiceManager; @@ -33,14 +35,21 @@ import android.provider.Settings; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.text.TextUtils; +import android.util.AttributeSet; import android.util.Log; +import android.util.Xml; import com.android.settingslib.R; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; @@ -161,7 +170,7 @@ public class DreamBackend { PackageManager pm = mContext.getPackageManager(); Intent dreamIntent = new Intent(DreamService.SERVICE_INTERFACE); List resolveInfos = pm.queryIntentServices(dreamIntent, - PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA)); + PackageManager.GET_META_DATA); List dreamInfos = new ArrayList<>(resolveInfos.size()); for (ResolveInfo resolveInfo : resolveInfos) { final ComponentName componentName = getDreamComponentName(resolveInfo); @@ -176,18 +185,15 @@ public class DreamBackend { dreamInfo.componentName = componentName; dreamInfo.isActive = dreamInfo.componentName.equals(activeDream); - final DreamService.DreamMetadata dreamMetadata = DreamService.getDreamMetadata(mContext, - resolveInfo.serviceInfo); - if (dreamMetadata != null) { - dreamInfo.settingsComponentName = dreamMetadata.settingsActivity; - dreamInfo.previewImage = dreamMetadata.previewImage; - } + final DreamMetadata dreamMetadata = getDreamMetadata(pm, resolveInfo); + dreamInfo.settingsComponentName = dreamMetadata.mSettingsActivity; + dreamInfo.previewImage = dreamMetadata.mPreviewImage; if (dreamInfo.previewImage == null) { dreamInfo.previewImage = mDreamPreviewDefault; } dreamInfos.add(dreamInfo); } - dreamInfos.sort(mComparator); + Collections.sort(dreamInfos, mComparator); return dreamInfos; } @@ -477,6 +483,67 @@ public class DreamBackend { return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); } + private static final class DreamMetadata { + @Nullable + Drawable mPreviewImage; + @Nullable + ComponentName mSettingsActivity; + } + + @Nullable + private static TypedArray readMetadata(PackageManager pm, ServiceInfo serviceInfo) { + if (serviceInfo == null || serviceInfo.metaData == null) { + return null; + } + try (XmlResourceParser parser = + serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA)) { + if (parser == null) { + Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " meta-data"); + return null; + } + Resources res = pm.getResourcesForApplication(serviceInfo.applicationInfo); + AttributeSet attrs = Xml.asAttributeSet(parser); + while (true) { + final int type = parser.next(); + if (type == XmlPullParser.END_DOCUMENT || type == XmlPullParser.START_TAG) { + break; + } + } + String nodeName = parser.getName(); + if (!"dream".equals(nodeName)) { + Log.w(TAG, "Meta-data does not start with dream tag"); + return null; + } + return res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream); + } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) { + Log.w(TAG, "Error parsing : " + serviceInfo.packageName, e); + return null; + } + } + + private static ComponentName convertToComponentName(String flattenedString, + ServiceInfo serviceInfo) { + if (flattenedString == null) return null; + + if (flattenedString.indexOf('/') < 0) { + flattenedString = serviceInfo.packageName + "/" + flattenedString; + } + return ComponentName.unflattenFromString(flattenedString); + } + + private static DreamMetadata getDreamMetadata(PackageManager pm, ResolveInfo resolveInfo) { + DreamMetadata result = new DreamMetadata(); + if (resolveInfo == null) return result; + TypedArray rawMetadata = readMetadata(pm, resolveInfo.serviceInfo); + if (rawMetadata == null) return result; + result.mSettingsActivity = convertToComponentName(rawMetadata.getString( + com.android.internal.R.styleable.Dream_settingsActivity), resolveInfo.serviceInfo); + result.mPreviewImage = rawMetadata.getDrawable( + com.android.internal.R.styleable.Dream_previewImage); + rawMetadata.recycle(); + return result; + } + private static void logd(String msg, Object... args) { if (DEBUG) { Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args)); diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 53cab9ed80cf5..d9f73d9aa54e2 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -130,19 +130,6 @@ android:resource="@xml/test_account_type2_authenticator"/> - - - - - - - - diff --git a/services/tests/servicestests/res/xml/test_dream_metadata.xml b/services/tests/servicestests/res/xml/test_dream_metadata.xml deleted file mode 100644 index aa054f1e9fa4f..0000000000000 --- a/services/tests/servicestests/res/xml/test_dream_metadata.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java deleted file mode 100644 index b489a2a6b6c25..0000000000000 --- a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2022 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.dreams; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.ServiceInfo; -import android.service.dreams.DreamService; - -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class DreamServiceTest { - @Test - public void testMetadataParsing() { - final String testDreamServiceComponent = "com.android.server.dreams/.TestDreamService"; - final String testSettingsActivity = "com.android.server.dreams/.TestDreamSettingsActivity"; - - final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - - try { - final ServiceInfo si = context.getPackageManager().getServiceInfo( - ComponentName.unflattenFromString(testDreamServiceComponent), - PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA)); - final DreamService.DreamMetadata metadata = DreamService.getDreamMetadata(context, si); - - assertEquals(0, metadata.settingsActivity.compareTo( - ComponentName.unflattenFromString(testSettingsActivity))); - assertFalse(metadata.showComplications); - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java b/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java deleted file mode 100644 index 3c99a9829275b..0000000000000 --- a/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2022 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.dreams; - -import android.service.dreams.DreamService; - -/** - * Dream service implementation for unit testing. - */ -public class TestDreamService extends DreamService { -}