Merge "Ensure input events are processed in-order in the application."
diff --git a/api/current.txt b/api/current.txt
index 86b6d8f..5dc32ae 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14788,6 +14788,7 @@
field public static final int FLAG_ONEWAY = 1; // 0x1
field public static final int INTERFACE_TRANSACTION = 1598968902; // 0x5f4e5446
field public static final int LAST_CALL_TRANSACTION = 16777215; // 0xffffff
+ field public static final int LIKE_TRANSACTION = 1598835019; // 0x5f4c494b
field public static final int PING_TRANSACTION = 1599098439; // 0x5f504e47
field public static final int TWEET_TRANSACTION = 1599362900; // 0x5f545754
}
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 34c0c2a..db72585 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -184,6 +184,7 @@
DIR *d;
struct dirent *de;
int64_t avail;
+ char datadir[PKG_PATH_MAX];
avail = disk_free();
if (avail < 0) return -1;
@@ -191,9 +192,14 @@
LOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
if (avail >= free_size) return 0;
- d = opendir(android_data_dir.path);
+ if (create_persona_path(datadir, 0)) {
+ LOGE("couldn't get directory for persona 0");
+ return -1;
+ }
+
+ d = opendir(datadir);
if (d == NULL) {
- LOGE("cannot open %s: %s\n", android_data_dir.path, strerror(errno));
+ LOGE("cannot open %s: %s\n", datadir, strerror(errno));
return -1;
}
dfd = dirfd(d);
@@ -578,19 +584,6 @@
return -1;
}
-int create_move_path(char path[PKG_PATH_MAX],
- const char* pkgname,
- const char* leaf,
- uid_t persona)
-{
- if ((android_data_dir.len + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) {
- return -1;
- }
-
- sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
- return 0;
-}
-
void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
struct stat* statbuf)
{
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index c5872b8..173cabf 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -105,6 +105,11 @@
int create_persona_path(char path[PKG_PATH_MAX],
uid_t persona);
+int create_move_path(char path[PKG_PATH_MAX],
+ const char* pkgname,
+ const char* leaf,
+ uid_t persona);
+
int is_valid_package_name(const char* pkgname);
int create_cache_path(char path[PKG_PATH_MAX], const char *src);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 1128fce..7cb9b37 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -34,6 +34,16 @@
#define TEST_SYSTEM_DIR1 "/system/app/"
#define TEST_SYSTEM_DIR2 "/vendor/app/"
+#define REALLY_LONG_APP_NAME "com.example." \
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
+ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
+ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
+ "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_"
+
namespace android {
class UtilsTest : public testing::Test {
@@ -210,7 +220,7 @@
TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
dir_rec_t test1;
- EXPECT_EQ(-1, get_path_from_string(&test1, NULL))
+ EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
<< "Should not allow NULL as a path.";
}
@@ -327,6 +337,50 @@
<< "Package path should be in /data/app-private/";
}
+TEST_F(UtilsTest, CreatePersonaPath_Primary) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(0, create_persona_path(path, 0))
+ << "Should successfully build primary user path.";
+
+ EXPECT_STREQ("/data/data/", path)
+ << "Primary user should have correct path";
+}
+
+TEST_F(UtilsTest, CreatePersonaPath_Secondary) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(0, create_persona_path(path, 1))
+ << "Should successfully build primary user path.";
+
+ EXPECT_STREQ("/data/user/1/", path)
+ << "Primary user should have correct path";
+}
+
+TEST_F(UtilsTest, CreateMovePath_Primary) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0))
+ << "Should be able to create move path for primary user";
+
+ EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path)
+ << "Primary user package directory should be created correctly";
+}
+
+TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0))
+ << "Should fail to create move path for primary user";
+}
+
+TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
+ char path[PKG_PATH_MAX];
+
+ EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0))
+ << "Should fail to create move path for primary user";
+}
+
TEST_F(UtilsTest, CopyAndAppend_Normal) {
//int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix)
dir_rec_t dst;
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 3099b83..a53a93c 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -109,7 +109,7 @@
uid_len = 0;
} else {
persona_prefix = SECONDARY_USER_PREFIX;
- uid_len = snprintf(NULL, 0, "%d", persona);
+ uid_len = snprintf(NULL, 0, "%d/", persona);
}
char *dst = path;
@@ -126,7 +126,7 @@
LOGE("Error building user path");
return -1;
}
- int ret = snprintf(dst, dst_size, "%d", persona);
+ int ret = snprintf(dst, dst_size, "%d/", persona);
if (ret < 0 || (size_t) ret != uid_len) {
LOGE("Error appending persona id to path");
return -1;
@@ -135,6 +135,20 @@
return 0;
}
+int create_move_path(char path[PKG_PATH_MAX],
+ const char* pkgname,
+ const char* leaf,
+ uid_t persona)
+{
+ if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
+ >= PKG_PATH_MAX) {
+ return -1;
+ }
+
+ sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
+ return 0;
+}
+
/**
* Checks whether the package name is valid. Returns -1 on error and
* 0 on success.
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 81defd6..0586d9e 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -128,6 +128,19 @@
int TWEET_TRANSACTION = ('_'<<24)|('T'<<16)|('W'<<8)|'T';
/**
+ * IBinder protocol transaction code: tell an app asynchronously that the
+ * caller likes it. The app is responsible for incrementing and maintaining
+ * its own like counter, and may display this value to the user to indicate the
+ * quality of the app. This is an optional command that applications do not
+ * need to handle, so the default implementation is to do nothing.
+ *
+ * <p>There is no response returned and nothing about the
+ * system will be functionally affected by it, but it will improve the
+ * app's self-esteem.
+ */
+ int LIKE_TRANSACTION = ('_'<<24)|('L'<<16)|('I'<<8)|'K';
+
+ /**
* Flag to {@link #transact}: this is a one-way call, meaning that the
* caller returns immediately, without waiting for a result from the
* callee. Applies only if the caller and callee are in different
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 787bcdd..1fab1ca 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9384,42 +9384,59 @@
mPositionY = mTempCoords[1];
}
- public boolean isVisible(int positionX, int positionY) {
- final TextView textView = TextView.this;
-
- if (mTempRect == null) mTempRect = new Rect();
- final Rect clip = mTempRect;
- clip.left = getCompoundPaddingLeft();
- clip.top = getExtendedPaddingTop();
- clip.right = textView.getWidth() - getCompoundPaddingRight();
- clip.bottom = textView.getHeight() - getExtendedPaddingBottom();
-
- final ViewParent parent = textView.getParent();
- if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) {
- return false;
- }
-
- int posX = mPositionX + positionX;
- int posY = mPositionY + positionY;
-
- // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal.
- return posX >= clip.left - 1 && posX <= clip.right + 1 &&
- posY >= clip.top && posY <= clip.bottom;
- }
-
- public boolean isOffsetVisible(int offset) {
- final int line = mLayout.getLineForOffset(offset);
- final int lineBottom = mLayout.getLineBottom(line);
- final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset);
- return isVisible(primaryHorizontal + viewportToContentHorizontalOffset(),
- lineBottom + viewportToContentVerticalOffset());
- }
-
public void onScrollChanged() {
mScrollHasChanged = true;
}
}
+ private boolean isPositionVisible(int positionX, int positionY) {
+ synchronized (sTmpPosition) {
+ final float[] position = sTmpPosition;
+ position[0] = positionX;
+ position[1] = positionY;
+ View view = this;
+
+ while (view != null) {
+ if (view != this) {
+ // Local scroll is already taken into account in positionX/Y
+ position[0] -= view.getScrollX();
+ position[1] -= view.getScrollY();
+ }
+
+ if (position[0] < 0 || position[1] < 0 ||
+ position[0] > view.getWidth() || position[1] > view.getHeight()) {
+ return false;
+ }
+
+ if (!view.getMatrix().isIdentity()) {
+ view.getMatrix().mapPoints(position);
+ }
+
+ position[0] += view.getLeft();
+ position[1] += view.getTop();
+
+ final ViewParent parent = view.getParent();
+ if (parent instanceof View) {
+ view = (View) parent;
+ } else {
+ // We've reached the ViewRoot, stop iterating
+ view = null;
+ }
+ }
+ }
+
+ // We've been able to walk up the view hierarchy and the position was never clipped
+ return true;
+ }
+
+ private boolean isOffsetVisible(int offset) {
+ final int line = mLayout.getLineForOffset(offset);
+ final int lineBottom = mLayout.getLineBottom(line);
+ final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset);
+ return isPositionVisible(primaryHorizontal + viewportToContentHorizontalOffset(),
+ lineBottom + viewportToContentVerticalOffset());
+ }
+
@Override
protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
super.onScrollChanged(horiz, vert, oldHoriz, oldVert);
@@ -9518,7 +9535,7 @@
public void updatePosition(int parentPositionX, int parentPositionY,
boolean parentPositionChanged, boolean parentScrolled) {
// Either parentPositionChanged or parentScrolled is true, check if still visible
- if (isShowing() && getPositionListener().isOffsetVisible(getTextOffset())) {
+ if (isShowing() && isOffsetVisible(getTextOffset())) {
if (parentScrolled) computeLocalPosition();
updatePosition(parentPositionX, parentPositionY);
} else {
@@ -10542,7 +10559,7 @@
return false;
}
- return getPositionListener().isVisible(mPositionX + mHotspotX, mPositionY);
+ return TextView.this.isPositionVisible(mPositionX + mHotspotX, mPositionY);
}
public abstract int getCurrentCursorOffset();
@@ -11518,6 +11535,7 @@
private Path mHighlightPath;
private boolean mHighlightPathBogus = true;
private static final RectF sTempRect = new RectF();
+ private static final float[] sTmpPosition = new float[2];
// XXX should be much larger
private static final int VERY_WIDE = 1024*1024;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 3372d1c..ae7a3b5 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -477,8 +477,9 @@
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint();
- LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
- text.text(), text.length(), count, x, y, paint);
+ float length = getFloat();
+ LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, OP_NAMES[op],
+ text.text(), text.length(), count, x, y, paint, length);
}
break;
case ResetShader: {
@@ -837,9 +838,10 @@
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint();
- DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
- text.text(), text.length(), count, x, y, paint);
- renderer.drawText(text.text(), text.length(), count, x, y, paint);
+ float length = getFloat();
+ DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent,
+ OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length);
+ renderer.drawText(text.text(), text.length(), count, x, y, paint, length);
}
break;
case ResetShader: {
@@ -1196,13 +1198,14 @@
}
void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
- float x, float y, SkPaint* paint) {
+ float x, float y, SkPaint* paint, float length) {
if (count <= 0) return;
addOp(DisplayList::DrawText);
addText(text, bytesCount);
addInt(count);
addPoint(x, y);
addPaint(paint);
+ addFloat(length < 0.0f ? paint->measureText(text, bytesCount) : length);
}
void DisplayListRenderer::resetShader() {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index ab475bf..ab483fb 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -290,7 +290,7 @@
virtual void drawLines(float* points, int count, SkPaint* paint);
virtual void drawPoints(float* points, int count, SkPaint* paint);
virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
- SkPaint* paint);
+ SkPaint* paint, float length);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 3c838fc..a60ac08 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2063,7 +2063,7 @@
}
void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
- float x, float y, SkPaint* paint) {
+ float x, float y, SkPaint* paint, float length) {
if (text == NULL || count == 0) {
return;
}
@@ -2080,20 +2080,26 @@
paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
#endif
- float length = -1.0f;
switch (paint->getTextAlign()) {
case SkPaint::kCenter_Align:
- length = paint->measureText(text, bytesCount);
+ if (length < 0.0f) length = paint->measureText(text, bytesCount);
x -= length / 2.0f;
break;
case SkPaint::kRight_Align:
- length = paint->measureText(text, bytesCount);
+ if (length < 0.0f) length = paint->measureText(text, bytesCount);
x -= length;
break;
default:
break;
}
+ SkPaint::FontMetrics metrics;
+ paint->getFontMetrics(&metrics, 0.0f);
+ if (quickReject(x, y + metrics.fTop,
+ x + (length >= 0.0f ? length : INT_MAX / 2), y + metrics.fBottom)) {
+ return;
+ }
+
const float oldX = x;
const float oldY = y;
const bool pureTranslate = mSnapshot->transform->isPureTranslate();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 2fc88e1..cd9ff93 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -123,7 +123,7 @@
virtual void drawLines(float* points, int count, SkPaint* paint);
virtual void drawPoints(float* points, int count, SkPaint* paint);
virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
- SkPaint* paint);
+ SkPaint* paint, float length = -1.0f);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 2dcd80d..2232995 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -34,6 +34,7 @@
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.PointF;
+import android.hardware.CameraSound;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
@@ -49,6 +50,7 @@
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.ImageView;
+
import com.android.systemui.R;
import java.io.File;
@@ -254,6 +256,8 @@
private float mBgPadding;
private float mBgPaddingScale;
+ private CameraSound mCameraSound;
+
/**
* @param context everything needs a context :(
@@ -303,6 +307,9 @@
// Scale has to account for both sides of the bg
mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);
mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
+
+ // Setup the Camera shutter sound
+ mCameraSound = new CameraSound();
}
/**
@@ -413,6 +420,9 @@
mScreenshotLayout.post(new Runnable() {
@Override
public void run() {
+ // Play the shutter sound to notify that we've taken a screenshot
+ mCameraSound.playSound(CameraSound.SHUTTER_CLICK);
+
mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mScreenshotView.buildLayer();
mScreenshotAnimation.start();
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index d34087f..16eeb7ba 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -163,7 +163,6 @@
} catch (IllegalArgumentException e) {
// ignore; report -1
}
- mCacheFileStats.restat(CACHE_PATH);
EventLog.writeEvent(EventLogTags.FREE_STORAGE_LEFT,
mFreeMem, mFreeSystem, mFreeCache);
}