Merge "More transition fixes" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 0177e4f..a9bb90f3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4280,6 +4280,7 @@
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 7956826..a9324d9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4412,6 +4412,7 @@
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 264b5eb..84e8b26 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4280,6 +4280,7 @@
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 536c4a8..8bc1aa3 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1193,13 +1193,52 @@
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 @@
}
// 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/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 06b712e..ea4f4eb 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -506,6 +506,22 @@
renderer.renderGlop(state, glop);
}
+void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, const BakedOpState& state) {
+ SkPaint paint;
+ paint.setColor(op.color);
+ paint.setXfermodeMode(op.mode);
+
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(state.roundRectClipState)
+ .setMeshUnitQuad()
+ .setFillPaint(paint, state.alpha)
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewMapUnitToRect(state.computedState.clipState->rect)
+ .build();
+ renderer.renderGlop(state, glop);
+}
+
void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) {
renderer.renderFunctor(op, state);
}
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index fae8e48..0ebb886 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -572,6 +572,12 @@
deferOvalOp(*resolvedOp);
}
+void FrameBuilder::deferColorOp(const ColorOp& op) {
+ BakedOpState* bakedState = tryBakeUnboundedOpState(op);
+ if (!bakedState) return; // quick rejected
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
+}
+
void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
if (!bakedState) return; // quick rejected
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 96a57b6..64c604a 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -90,6 +90,7 @@
UNMERGEABLE_OP_FN(ArcOp) \
UNMERGEABLE_OP_FN(BitmapMeshOp) \
UNMERGEABLE_OP_FN(BitmapRectOp) \
+ UNMERGEABLE_OP_FN(ColorOp) \
UNMERGEABLE_OP_FN(FunctorOp) \
UNMERGEABLE_OP_FN(LinesOp) \
UNMERGEABLE_OP_FN(OvalOp) \
@@ -256,6 +257,16 @@
const float* radius;
};
+struct ColorOp : RecordedOp {
+ // Note: unbounded op that will fillclip, so no bounds/matrix needed
+ ColorOp(const ClipBase* localClip, int color, SkXfermode::Mode mode)
+ : RecordedOp(RecordedOpId::ColorOp, Rect(), Matrix4::identity(), localClip, nullptr)
+ , color(color)
+ , mode(mode) {}
+ const int color;
+ const SkXfermode::Mode mode;
+};
+
struct FunctorOp : RecordedOp {
// Note: undefined record-time bounds, since this op fills the clip
// TODO: explicitly define bounds
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 4eeadb7..f43dade 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -234,10 +234,10 @@
// android/graphics/Canvas draw operations
// ----------------------------------------------------------------------------
void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) {
- SkPaint paint;
- paint.setColor(color);
- paint.setXfermodeMode(mode);
- drawPaint(paint);
+ addOp(alloc().create_trivial<ColorOp>(
+ getRecordedClip(),
+ color,
+ mode));
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index e1c9319..059e9ae 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -42,17 +42,20 @@
sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
- std::function<void(Matrix4*)> transformSetupCallback) {
+ const SkMatrix& transform) {
+ Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
+
+ sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
+ layerUpdater->setSize(width, height);
+ layerUpdater->setTransform(&transform);
+
+ // updateLayer so it's ready to draw
bool isOpaque = true;
bool forceFilter = true;
GLenum renderTarget = GL_TEXTURE_EXTERNAL_OES;
-
- Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, forceFilter,
- renderTarget, Matrix4::identity().data);
- transformSetupCallback(&(layer->getTransform()));
+ renderTarget, Matrix4::identity().data);
- sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
return layerUpdater;
}
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 73027e2..2d1e2e9 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -122,7 +122,7 @@
static sp<DeferredLayerUpdater> createTextureLayerUpdater(
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
- std::function<void(Matrix4*)> transformSetupCallback);
+ const SkMatrix& transform);
template<class CanvasType>
static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 99400c6..dca56d4 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -387,9 +387,7 @@
};
auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- [](Matrix4* transform) {
- transform->loadTranslate(5, 5, 0);
- });
+ SkMatrix::MakeTrans(5, 5));
auto node = TestUtils::createNode(0, 0, 200, 200,
[&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
@@ -429,7 +427,31 @@
EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
}
-RENDERTHREAD_TEST(FrameBuilder, renderNode) {
+RENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
+ class ColorTestRenderer : public TestRendererBase {
+ public:
+ void onColorOp(const ColorOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
+ << "Color op should be expanded to bounds of surrounding";
+ }
+ };
+
+ auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setClipToBounds(false);
+ canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
+ });
+
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ TestUtils::createSyncedNodeList(unclippedColorView),
+ sLightGeometry, Caches::getInstance());
+ ColorTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
+}
+
+TEST(FrameBuilder, renderNode) {
class RenderNodeTestRenderer : public TestRendererBase {
public:
void onRectOp(const RectOp& op, const BakedOpState& state) override {
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 42dabd3..1c240db 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -226,9 +226,9 @@
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
auto op = *(dl->getOps()[0]);
- EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_EQ(RecordedOpId::ColorOp, op.opId);
EXPECT_EQ(nullptr, op.localClip);
- EXPECT_TRUE(op.unmappedBounds.contains(Rect(200, 200))) << "Expect recording/clip bounds";
+ EXPECT_TRUE(op.unmappedBounds.isEmpty()) << "Expect undefined recorded bounds";
}
TEST(RecordingCanvas, backgroundAndImage) {
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 7c9591d..acf94f4c 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -1039,6 +1039,15 @@
}
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 @@
}
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 2c34523..58d2da7 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 @@
}
@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 7be9f9d..e3ca3ea 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 @@
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 @@
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/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index fb9b1ce..4848523 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1262,6 +1262,7 @@
return null;
}
+ @Override
public void setWallpaperComponentChecked(ComponentName name, String callingPackage) {
if (isWallpaperSupported(callingPackage) && isWallpaperSettingAllowed(callingPackage)) {
setWallpaperComponent(name);
@@ -1269,6 +1270,7 @@
}
// ToDo: Remove this version of the function
+ @Override
public void setWallpaperComponent(ComponentName name) {
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
@@ -1281,7 +1283,9 @@
final long ident = Binder.clearCallingIdentity();
try {
wallpaper.imageWallpaperPending = false;
- bindWallpaperComponentLocked(name, false, true, wallpaper, null);
+ if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
+ wallpaper.wallpaperId = makeWallpaperIdLocked();
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/tools/layoutlib/.idea/codeStyleSettings.xml b/tools/layoutlib/.idea/codeStyleSettings.xml
index 89f7b34..ac90d1e 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 6c775b9..ea320c7 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 @@
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 4e4fcd0..0c53753 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 @@
// 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 @@
return SUCCESS.createResult();
}
-
/**
* Prepares the scene for action.
* <p>
@@ -320,10 +319,11 @@
}
}
- 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 @@
} 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 c2f06e8..a5561fa 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.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 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 @@
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 @@
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 @@
}
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 @@
return null;
}
}
+
/**
* Initialize the bridge and the resource maps.
*/
@@ -325,8 +311,7 @@
@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 @@
.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 @@
@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 @@
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 @@
@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 @@
@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 @@
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 @@
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 6c16ed0..96ae523 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.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 @@
}
};
}
+
+ @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 c79b662..1110494 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 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);
}
}