diff options
13 files changed, 217 insertions, 93 deletions
diff --git a/api/current.txt b/api/current.txt index 0177e4f29de7..a9bb90f3e8ad 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4280,6 +4280,7 @@ package android.app { public class DownloadManager { method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean); + method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri); method public long enqueue(android.app.DownloadManager.Request); method public static java.lang.Long getMaxBytesOverMobile(android.content.Context); method public java.lang.String getMimeTypeForDownloadedFile(long); diff --git a/api/system-current.txt b/api/system-current.txt index 7956826ee43e..a9324d996837 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4412,6 +4412,7 @@ package android.app { public class DownloadManager { method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean); + method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri); method public long enqueue(android.app.DownloadManager.Request); method public static java.lang.Long getMaxBytesOverMobile(android.content.Context); method public java.lang.String getMimeTypeForDownloadedFile(long); diff --git a/api/test-current.txt b/api/test-current.txt index 264b5eb4186e..84e8b2653768 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4280,6 +4280,7 @@ package android.app { public class DownloadManager { method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean); + method public long addCompletedDownload(java.lang.String, java.lang.String, boolean, java.lang.String, java.lang.String, long, boolean, android.net.Uri, android.net.Uri); method public long enqueue(android.app.DownloadManager.Request); method public static java.lang.Long getMaxBytesOverMobile(android.content.Context); method public java.lang.String getMimeTypeForDownloadedFile(long); diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 536c4a865fce..8bc1aa393c38 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -1193,13 +1193,52 @@ public class DownloadManager { boolean isMediaScannerScannable, String mimeType, String path, long length, boolean showNotification) { return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path, - length, showNotification, false); + length, showNotification, false, null, null); + } + + /** + * Adds a file to the downloads database system, so it could appear in Downloads App + * (and thus become eligible for management by the Downloads App). + * <p> + * It is helpful to make the file scannable by MediaScanner by setting the param + * isMediaScannerScannable to true. It makes the file visible in media managing + * applications such as Gallery App, which could be a useful purpose of using this API. + * + * @param title the title that would appear for this file in Downloads App. + * @param description the description that would appear for this file in Downloads App. + * @param isMediaScannerScannable true if the file is to be scanned by MediaScanner. Files + * scanned by MediaScanner appear in the applications used to view media (for example, + * Gallery app). + * @param mimeType mimetype of the file. + * @param path absolute pathname to the file. The file should be world-readable, so that it can + * be managed by the Downloads App and any other app that is used to read it (for example, + * Gallery app to display the file, if the file contents represent a video/image). + * @param length length of the downloaded file + * @param showNotification true if a notification is to be sent, false otherwise + * @param uri the original HTTP URI of the download + * @param referer the HTTP Referer for the download + * @return an ID for the download entry added to the downloads app, unique across the system + * This ID is used to make future calls related to this download. + */ + public long addCompletedDownload(String title, String description, + boolean isMediaScannerScannable, String mimeType, String path, long length, + boolean showNotification, Uri uri, Uri referer) { + return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path, + length, showNotification, false, uri, referer); } /** {@hide} */ public long addCompletedDownload(String title, String description, boolean isMediaScannerScannable, String mimeType, String path, long length, boolean showNotification, boolean allowWrite) { + return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path, + length, showNotification, allowWrite, null, null); + } + + /** {@hide} */ + public long addCompletedDownload(String title, String description, + boolean isMediaScannerScannable, String mimeType, String path, long length, + boolean showNotification, boolean allowWrite, Uri uri, Uri referer) { // make sure the input args are non-null/non-zero validateArgumentIsNonEmpty("title", title); validateArgumentIsNonEmpty("description", description); @@ -1210,10 +1249,18 @@ public class DownloadManager { } // if there is already an entry with the given path name in downloads.db, return its id - Request request = new Request(NON_DOWNLOADMANAGER_DOWNLOAD) - .setTitle(title) + Request request; + if (uri != null) { + request = new Request(uri); + } else { + request = new Request(NON_DOWNLOADMANAGER_DOWNLOAD); + } + request.setTitle(title) .setDescription(description) .setMimeType(mimeType); + if (referer != null) { + request.addRequestHeader("Referer", referer.toString()); + } ContentValues values = request.toContentValues(null); values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD); diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 7c9591d68254..acf94f4cf7f6 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -1039,6 +1039,15 @@ public final class TvInputInfo implements Parcelable { } Settings.Secure.putStringForUser(context.getContentResolver(), Settings.Secure.TV_INPUT_HIDDEN_INPUTS, builder.toString(), userId); + + // Notify of the TvInputInfo changes. + TvInputManager tm = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE); + for (String inputId : hiddenInputIds) { + TvInputInfo info = tm.getTvInputInfo(inputId); + if (info != null) { + tm.updateTvInputInfo(info); + } + } } /** @@ -1069,6 +1078,15 @@ public final class TvInputInfo implements Parcelable { } Settings.Secure.putStringForUser(context.getContentResolver(), Settings.Secure.TV_INPUT_CUSTOM_LABELS, builder.toString(), userId); + + // Notify of the TvInputInfo changes. + TvInputManager tm = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE); + for (String inputId : customLabels.keySet()) { + TvInputInfo info = tm.getTvInputInfo(inputId); + if (info != null) { + tm.updateTvInputInfo(info); + } + } } private static void ensureValidField(String value) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java index 2c345232fbbf..58d2da7a262c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java @@ -105,7 +105,11 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { } @Override - public void onMoveToFullscreen() { } + public void onMoveToFullscreen() { + // Recents should be dismissed when PIP moves to fullscreen. If not, Recents will + // be unnecessarily shown in the scenario: PIP->Fullscreen->PIP. + dismissRecentsToLaunchTargetTaskOrHome(); + } @Override public void onPipResizeAboutToStart() { } diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 7be9f9d69bff..e3ca3ea90443 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1363,6 +1363,15 @@ class ActivityStarter { intentActivity.task, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront"); mMovedToFront = true; + } else if ((launchStack.mStackId == DOCKED_STACK_ID + || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) + && (mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) { + // If we want to launch adjacent and mTargetStack is not the computed + // launch stack - move task to top of computed stack. + mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId, + launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide", + ANIMATE); + mMovedToFront = true; } mOptions = null; } @@ -1770,26 +1779,41 @@ class ActivityStarter { if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) { return null; } + // Otherwise handle adjacent launch. // The parent activity doesn't want to launch the activity on top of itself, but // instead tries to put it onto other side in side-by-side mode. final ActivityStack parentStack = task != null ? task.stack : r.mInitialActivityContainer != null ? r.mInitialActivityContainer.mStack : mSupervisor.mFocusedStack; - if (parentStack != null && parentStack.mStackId == DOCKED_STACK_ID) { - // If parent was in docked stack, the natural place to launch another activity - // will be fullscreen, so it can appear alongside the docked window. - return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP); + + if (parentStack != mSupervisor.mFocusedStack) { + // If task's parent stack is not focused - use it during adjacent launch. + return parentStack; } else { - // If the parent is not in the docked stack, we check if there is docked window - // and if yes, we will launch into that stack. If not, we just put the new - // activity into parent's stack, because we can't find a better place. - final ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID); - if (stack != null && stack.getStackVisibilityLocked(r) == STACK_INVISIBLE) { - // There is a docked stack, but it isn't visible, so we can't launch into that. - return null; + if (mSupervisor.mFocusedStack != null && task == mSupervisor.mFocusedStack.topTask()) { + // If task is already on top of focused stack - use it. We don't want to move the + // existing focused task to adjacent stack, just deliver new intent in this case. + return mSupervisor.mFocusedStack; + } + + if (parentStack != null && parentStack.mStackId == DOCKED_STACK_ID) { + // If parent was in docked stack, the natural place to launch another activity + // will be fullscreen, so it can appear alongside the docked window. + return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, + ON_TOP); } else { - return stack; + // If the parent is not in the docked stack, we check if there is docked window + // and if yes, we will launch into that stack. If not, we just put the new + // activity into parent's stack, because we can't find a better place. + final ActivityStack dockedStack = mSupervisor.getStack(DOCKED_STACK_ID); + if (dockedStack != null + && dockedStack.getStackVisibilityLocked(r) == STACK_INVISIBLE) { + // There is a docked stack, but it isn't visible, so we can't launch into that. + return null; + } else { + return dockedStack; + } } } } diff --git a/tools/layoutlib/.idea/codeStyleSettings.xml b/tools/layoutlib/.idea/codeStyleSettings.xml index 89f7b341fb8b..ac90d1e540be 100644 --- a/tools/layoutlib/.idea/codeStyleSettings.xml +++ b/tools/layoutlib/.idea/codeStyleSettings.xml @@ -40,6 +40,7 @@ <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> </XML> <codeStyleSettings language="JAVA"> + <option name="KEEP_LINE_BREAKS" value="false" /> <option name="ALIGN_MULTILINE_PARAMETERS" value="false" /> <option name="CALL_PARAMETERS_WRAP" value="1" /> <option name="METHOD_PARAMETERS_WRAP" value="1" /> @@ -55,6 +56,7 @@ <option name="DOWHILE_BRACE_FORCE" value="3" /> <option name="WHILE_BRACE_FORCE" value="3" /> <option name="FOR_BRACE_FORCE" value="3" /> + <option name="WRAP_LONG_LINES" value="true" /> <arrangement> <groups> <group> diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java index 6c775b906d1e..ea320c701c24 100644 --- a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java +++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java @@ -647,15 +647,15 @@ public class Resources_Delegate { static String getResourceName(Resources resources, int resid) throws NotFoundException { boolean[] platformOut = new boolean[1]; Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, platformOut); - String namespace; + String packageName; if (resourceInfo != null) { if (platformOut[0]) { - namespace = SdkConstants.ANDROID_NS_NAME; + packageName = SdkConstants.ANDROID_NS_NAME; } else { - namespace = resources.mContext.getPackageName(); - namespace = namespace == null ? SdkConstants.APP_PREFIX : namespace; + packageName = resources.mContext.getPackageName(); + packageName = packageName == null ? SdkConstants.APP_PREFIX : packageName; } - return namespace + ':' + resourceInfo.getFirst().getName() + '/' + + return packageName + ':' + resourceInfo.getFirst().getName() + '/' + resourceInfo.getSecond(); } throwException(resid, null); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index 4e4fcd0aff2d..0c537533479e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -122,7 +122,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso // build the context mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources, - mParams.getAssets(), mParams.getLayoutlibCallback(), getConfiguration(), + mParams.getAssets(), mParams.getLayoutlibCallback(), getConfiguration(mParams), mParams.getTargetSdkVersion(), mParams.isRtlSupported()); setUp(); @@ -130,7 +130,6 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso return SUCCESS.createResult(); } - /** * Prepares the scene for action. * <p> @@ -320,10 +319,11 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso } } - private Configuration getConfiguration() { + // VisibleForTesting + public static Configuration getConfiguration(RenderParams params) { Configuration config = new Configuration(); - HardwareConfig hardwareConfig = mParams.getHardwareConfig(); + HardwareConfig hardwareConfig = params.getHardwareConfig(); ScreenSize screenSize = hardwareConfig.getScreenSize(); if (screenSize != null) { @@ -392,7 +392,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso } else { config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_UNDEFINED; } - String locale = getParams().getLocale(); + String locale = params.getLocale(); if (locale != null && !locale.isEmpty()) config.locale = new Locale(locale); // TODO: fill in more config info. diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java index c2f06e8b9aa2..a5561fab953c 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java @@ -29,11 +29,14 @@ import com.android.ide.common.resources.ResourceResolver; import com.android.ide.common.resources.configuration.FolderConfiguration; import com.android.io.FolderWrapper; import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.android.BridgeContext; +import com.android.layoutlib.bridge.impl.RenderAction; import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback; import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; import com.android.resources.Density; import com.android.resources.Navigation; +import com.android.resources.ResourceType; import com.android.utils.ILogger; import org.junit.AfterClass; @@ -42,13 +45,15 @@ import org.junit.Test; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.util.DisplayMetrics; import java.io.File; -import java.io.FileFilter; import java.io.IOException; import java.net.URL; import java.util.Arrays; -import java.util.Comparator; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; @@ -160,13 +165,8 @@ public class Main { if (!host.isDirectory()) { return null; } - File[] hosts = host.listFiles(new FileFilter() { - @Override - public boolean accept(File path) { - return path.isDirectory() && (path.getName().startsWith("linux-") || path.getName() - .startsWith("darwin-")); - } - }); + File[] hosts = host.listFiles(path -> path.isDirectory() && + (path.getName().startsWith("linux-") || path.getName().startsWith("darwin-"))); for (File hostOut : hosts) { String platformDir = getPlatformDirFromHostOut(hostOut); if (platformDir != null) { @@ -184,12 +184,9 @@ public class Main { if (!sdkDir.isDirectory()) { return null; } - File[] sdkDirs = sdkDir.listFiles(new FileFilter() { - @Override - public boolean accept(File path) { - // We need to search for $TARGET_PRODUCT (usually, sdk_phone_armv7) - return path.isDirectory() && path.getName().startsWith("sdk"); - } + File[] sdkDirs = sdkDir.listFiles(path -> { + // We need to search for $TARGET_PRODUCT (usually, sdk_phone_armv7) + return path.isDirectory() && path.getName().startsWith("sdk"); }); for (File dir : sdkDirs) { String platformDir = getPlatformDirFromHostOutSdkSdk(dir); @@ -201,46 +198,34 @@ public class Main { } private static String getPlatformDirFromHostOutSdkSdk(File sdkDir) { - File[] possibleSdks = sdkDir.listFiles(new FileFilter() { - @Override - public boolean accept(File path) { - return path.isDirectory() && path.getName().contains("android-sdk"); - } - }); + File[] possibleSdks = sdkDir.listFiles( + path -> path.isDirectory() && path.getName().contains("android-sdk")); for (File possibleSdk : possibleSdks) { File platformsDir = new File(possibleSdk, "platforms"); - File[] platforms = platformsDir.listFiles(new FileFilter() { - @Override - public boolean accept(File path) { - return path.isDirectory() && path.getName().startsWith("android-"); - } - }); + File[] platforms = platformsDir.listFiles( + path -> path.isDirectory() && path.getName().startsWith("android-")); if (platforms == null || platforms.length == 0) { continue; } - Arrays.sort(platforms, new Comparator<File>() { - // Codenames before ints. Higher APIs precede lower. - @Override - public int compare(File o1, File o2) { - final int MAX_VALUE = 1000; - String suffix1 = o1.getName().substring("android-".length()); - String suffix2 = o2.getName().substring("android-".length()); - int suff1, suff2; - try { - suff1 = Integer.parseInt(suffix1); - } catch (NumberFormatException e) { - suff1 = MAX_VALUE; - } - try { - suff2 = Integer.parseInt(suffix2); - } catch (NumberFormatException e) { - suff2 = MAX_VALUE; - } - if (suff1 != MAX_VALUE || suff2 != MAX_VALUE) { - return suff2 - suff1; - } - return suffix2.compareTo(suffix1); + Arrays.sort(platforms, (o1, o2) -> { + final int MAX_VALUE = 1000; + String suffix1 = o1.getName().substring("android-".length()); + String suffix2 = o2.getName().substring("android-".length()); + int suff1, suff2; + try { + suff1 = Integer.parseInt(suffix1); + } catch (NumberFormatException e) { + suff1 = MAX_VALUE; + } + try { + suff2 = Integer.parseInt(suffix2); + } catch (NumberFormatException e) { + suff2 = MAX_VALUE; } + if (suff1 != MAX_VALUE || suff2 != MAX_VALUE) { + return suff2 - suff1; + } + return suffix2.compareTo(suffix1); }); return platforms[0].getAbsolutePath(); } @@ -261,6 +246,7 @@ public class Main { return null; } } + /** * Initialize the bridge and the resource maps. */ @@ -325,8 +311,7 @@ public class Main { @Test public void testExpand() throws ClassNotFoundException { // Create the layout pull parser. - LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + - "expand_vert_layout.xml"); + LayoutPullParser parser = createLayoutPullParser("expand_vert_layout.xml"); // Create LayoutLibCallback. LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); layoutLibCallback.initResources(); @@ -348,8 +333,7 @@ public class Main { .setScreenHeight(300) .setDensity(Density.XHIGH) .setNavigation(Navigation.NONAV); - parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + - "expand_horz_layout.xml"); + parser = createLayoutPullParser("expand_horz_layout.xml"); params = getSessionParams(parser, customConfigGenerator, layoutLibCallback, "Theme.Material.Light.NoActionBar.Fullscreen", false, RenderingMode.H_SCROLL, 22); @@ -361,8 +345,7 @@ public class Main { @Test public void testVectorAnimation() throws ClassNotFoundException { // Create the layout pull parser. - LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + - "indeterminate_progressbar.xml"); + LayoutPullParser parser = createLayoutPullParser("indeterminate_progressbar.xml"); // Create LayoutLibCallback. LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); layoutLibCallback.initResources(); @@ -373,8 +356,7 @@ public class Main { renderAndVerify(params, "animated_vector.png", TimeUnit.SECONDS.toNanos(2)); - parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + - "indeterminate_progressbar.xml"); + parser = createLayoutPullParser("indeterminate_progressbar.xml"); params = getSessionParams(parser, ConfigGenerator.NEXUS_5, layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false, RenderingMode.V_SCROLL, 22); @@ -388,8 +370,7 @@ public class Main { @Test public void testVectorDrawable() throws ClassNotFoundException { // Create the layout pull parser. - LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + - "vector_drawable.xml"); + LayoutPullParser parser = createLayoutPullParser("vector_drawable.xml"); // Create LayoutLibCallback. LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); layoutLibCallback.initResources(); @@ -405,8 +386,7 @@ public class Main { @Test public void testScrolling() throws ClassNotFoundException { // Create the layout pull parser. - LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + - "scrolled.xml"); + LayoutPullParser parser = createLayoutPullParser("scrolled.xml"); // Create LayoutLibCallback. LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); layoutLibCallback.initResources(); @@ -435,6 +415,39 @@ public class Main { assertEquals(690, rootLayout.getChildren().get(5).getChildren().get(0).getRight()); } + @Test + public void testGetResourceNameVariants() throws Exception { + // Setup + SessionParams params = createSessionParams("", ConfigGenerator.NEXUS_4); + AssetManager assetManager = AssetManager.getSystem(); + DisplayMetrics metrics = new DisplayMetrics(); + Configuration configuration = RenderAction.getConfiguration(params); + Resources resources = new Resources(assetManager, metrics, configuration); + resources.mLayoutlibCallback = params.getLayoutlibCallback(); + resources.mContext = + new BridgeContext(params.getProjectKey(), metrics, params.getResources(), + params.getAssets(), params.getLayoutlibCallback(), configuration, + params.getTargetSdkVersion(), params.isRtlSupported()); + // Test + assertEquals("android:style/ButtonBar", + resources.getResourceName(android.R.style.ButtonBar)); + assertEquals("android", resources.getResourcePackageName(android.R.style.ButtonBar)); + assertEquals("ButtonBar", resources.getResourceEntryName(android.R.style.ButtonBar)); + assertEquals("style", resources.getResourceTypeName(android.R.style.ButtonBar)); + int id = resources.mLayoutlibCallback.getResourceId(ResourceType.STRING, "app_name"); + assertEquals("com.android.layoutlib.test.myapplication:string/app_name", + resources.getResourceName(id)); + assertEquals("com.android.layoutlib.test.myapplication", + resources.getResourcePackageName(id)); + assertEquals("string", resources.getResourceTypeName(id)); + assertEquals("app_name", resources.getResourceEntryName(id)); + } + + @NonNull + private LayoutPullParser createLayoutPullParser(String layoutPath) { + return new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutPath); + } + /** * Create a new rendering session and test that rendering the given layout doesn't throw any * exceptions and matches the provided image. @@ -505,16 +518,21 @@ public class Main { private RenderResult renderAndVerify(String layoutFileName, String goldenFileName, ConfigGenerator deviceConfig) throws ClassNotFoundException { + SessionParams params = createSessionParams(layoutFileName, deviceConfig); + return renderAndVerify(params, goldenFileName); + } + + private SessionParams createSessionParams(String layoutFileName, ConfigGenerator deviceConfig) + throws ClassNotFoundException { // Create the layout pull parser. - LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutFileName); + LayoutPullParser parser = createLayoutPullParser(layoutFileName); // Create LayoutLibCallback. LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger()); layoutLibCallback.initResources(); // TODO: Set up action bar handler properly to test menu rendering. // Create session params. - SessionParams params = getSessionParams(parser, deviceConfig, + return getSessionParams(parser, deviceConfig, layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22); - return renderAndVerify(params, goldenFileName); } /** diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java index 6c16ed01ca54..96ae523006b3 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java @@ -24,7 +24,9 @@ import com.android.ide.common.rendering.api.LayoutlibCallback; import com.android.ide.common.rendering.api.ParserFactory; import com.android.ide.common.rendering.api.ResourceReference; import com.android.ide.common.rendering.api.ResourceValue; +import com.android.ide.common.rendering.api.SessionParams.Key; import com.android.ide.common.resources.IntArrayWrapper; +import com.android.layoutlib.bridge.android.RenderParamsFlags; import com.android.resources.ResourceType; import com.android.util.Pair; import com.android.utils.ILogger; @@ -176,4 +178,12 @@ public class LayoutLibTestCallback extends LayoutlibCallback { } }; } + + @Override + public <T> T getFlag(Key<T> key) { + if (key.equals(RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE)) { + return (T) PACKAGE_NAME; + } + return null; + } } diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java index c79b66281efc..111049474461 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutPullParser.java @@ -56,9 +56,7 @@ public class LayoutPullParser extends KXmlParser implements ILayoutPullParser{ public LayoutPullParser(File layoutFile) { try { init(new FileInputStream(layoutFile)); - } catch (XmlPullParserException e) { - throw new IOError(e); - } catch (FileNotFoundException e) { + } catch (XmlPullParserException | FileNotFoundException e) { throw new IOError(e); } } |