Merge "Historical notification access API."
diff --git a/Android.mk b/Android.mk
index 25c050e..d6d01d88 100644
--- a/Android.mk
+++ b/Android.mk
@@ -703,29 +703,6 @@
# explicitly specify that online-sdk depends on framework-res and any generated docs
$(full_target): framework-res-package-target
-# ==== docs for the s.a.c site (on the google app engine server) =======================
-# include $(CLEAR_VARS)
-
-# LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
-# LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
-# LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
-# LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
-# LOCAL_DROIDDOC_HTML_DIR:=../../docs/source.android.com/src
-# LOCAL_ADDITIONAL_HTML_DIR:=
-# LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
-# LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
-# LOCAL_MODULE := online-sac
-#
-# LOCAL_DROIDDOC_OPTIONS:= \
-# $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-# -toroot / \
-# -hdf android.whichdoc online \
-# -hdf sac true
-#
-# LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
-#
-# include $(BUILD_DROIDDOC)
-
# ==== docs for the web (on the devsite app engine server) =======================
include $(CLEAR_VARS)
LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
@@ -757,6 +734,7 @@
# explicitly specify that ds depends on framework-res and any generated docs
$(full_target): framework-res-package-target
+
#==== reference docs for GCM =======================
include $(CLEAR_VARS)
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 6641f2c..28fd05f 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -820,7 +820,7 @@
* and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which
* always set msg.obj to the handler.
*/
- boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj == mSmHandlerObj);
+ boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj != mSmHandlerObj);
if (mLogRecords.logOnlyTransitions()) {
/** Record only if there is a transition */
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 08e2332..62f268d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1179,6 +1179,10 @@
delete bounds;
}
+ // We must clear the list of dirty rects before we
+ // call setupDraw() to prevent stencil setup to do
+ // the same thing again
+ mLayers.clear();
setupDraw(false);
setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
@@ -1195,9 +1199,8 @@
for (uint32_t i = 0; i < count; i++) {
delete mLayers.itemAt(i);
}
+ mLayers.clear();
}
-
- mLayers.clear();
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 1afcb46..1a75ea8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -189,7 +189,10 @@
vOffset += glyph->mBitmapTop + height;
SkPoint destination[4];
- measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
+ bool ok = measure.getPosTan(x + hOffset + glyph->mBitmapLeft + halfWidth, position, tangent);
+ if (!ok) {
+ ALOGW("The path for drawTextOnPath is empty or null");
+ }
// Move along the tangent and offset by the normal
destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index f930a03..5d27966 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -19,7 +19,6 @@
#define LOG_TAG "MediaScannerJNI"
#include <utils/Log.h>
#include <utils/threads.h>
-#include <utils/Unicode.h>
#include <media/mediascanner.h>
#include <media/stagefright/StagefrightMediaScanner.h>
@@ -57,6 +56,53 @@
return OK;
}
+// stolen from dalvik/vm/checkJni.cpp
+static bool isValidUtf8(const char* bytes) {
+ while (*bytes != '\0') {
+ unsigned char utf8 = *(bytes++);
+ // Switch on the high four bits.
+ switch (utf8 >> 4) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ // Bit pattern 0xxx. No need for any extra bytes.
+ break;
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0f:
+ /*
+ * Bit pattern 10xx or 1111, which are illegal start bytes.
+ * Note: 1111 is valid for normal UTF-8, but not the
+ * modified UTF-8 used here.
+ */
+ return false;
+ case 0x0e:
+ // Bit pattern 1110, so there are two additional bytes.
+ utf8 = *(bytes++);
+ if ((utf8 & 0xc0) != 0x80) {
+ return false;
+ }
+ // Fall through to take care of the final byte.
+ case 0x0c:
+ case 0x0d:
+ // Bit pattern 110x, so there is one additional byte.
+ utf8 = *(bytes++);
+ if ((utf8 & 0xc0) != 0x80) {
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
class MyMediaScannerClient : public MediaScannerClient
{
public:
@@ -124,11 +170,8 @@
mEnv->ExceptionClear();
return NO_MEMORY;
}
-
- // Check if the value is valid UTF-8 string and replace
- // any un-printable characters with '?' when it's not.
char *cleaned = NULL;
- if (utf8_length(value) == -1) {
+ if (!isValidUtf8(value)) {
cleaned = strdup(value);
char *chp = cleaned;
char ch;
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index dc54eae..e79b2c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -45,6 +45,8 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
@@ -162,7 +164,7 @@
if (convertView == null) {
convertView = createView(parent);
}
- ViewHolder holder = (ViewHolder) convertView.getTag();
+ final ViewHolder holder = (ViewHolder) convertView.getTag();
// index is reverse since most recent appears at the bottom...
final int index = mRecentTaskDescriptions.size() - position - 1;
@@ -191,24 +193,49 @@
holder.calloutLine.setTranslationY(0f);
}
}
- mItemToAnimateInWhenWindowAnimationIsFinished = holder;
- final int translation = -getResources().getDimensionPixelSize(
- R.dimen.status_bar_recents_app_icon_translate_distance);
- final Configuration config = getResources().getConfiguration();
- if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
- holder.iconView.setAlpha(0f);
- holder.iconView.setTranslationX(translation);
- holder.labelView.setAlpha(0f);
- holder.labelView.setTranslationX(translation);
- holder.calloutLine.setAlpha(0f);
- holder.calloutLine.setTranslationX(translation);
- } else {
- holder.iconView.setAlpha(0f);
- holder.iconView.setTranslationY(translation);
- }
- if (!mWaitingForWindowAnimation) {
- animateInIconOfFirstTask();
- }
+ mItemToAnimateInWhenWindowAnimationIsFinished = null;
+
+ final ViewTreeObserver observer = getViewTreeObserver();
+ final OnGlobalLayoutListener animateFirstIcon = new OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ if (mItemToAnimateInWhenWindowAnimationIsFinished != null) {
+ holder.iconView.setAlpha(1f);
+ holder.iconView.setTranslationX(0f);
+ holder.iconView.setTranslationY(0f);
+ holder.labelView.setAlpha(1f);
+ holder.labelView.setTranslationX(0f);
+ holder.labelView.setTranslationY(0f);
+ if (holder.calloutLine != null) {
+ holder.calloutLine.setAlpha(1f);
+ holder.calloutLine.setTranslationX(0f);
+ holder.calloutLine.setTranslationY(0f);
+ }
+ }
+ mItemToAnimateInWhenWindowAnimationIsFinished = holder;
+ int translation = -getResources().getDimensionPixelSize(
+ R.dimen.status_bar_recents_app_icon_translate_distance);
+ final Configuration config = getResources().getConfiguration();
+ if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ translation = -translation;
+ }
+ holder.iconView.setAlpha(0f);
+ holder.iconView.setTranslationX(translation);
+ holder.labelView.setAlpha(0f);
+ holder.labelView.setTranslationX(translation);
+ holder.calloutLine.setAlpha(0f);
+ holder.calloutLine.setTranslationX(translation);
+ } else {
+ holder.iconView.setAlpha(0f);
+ holder.iconView.setTranslationY(translation);
+ }
+ if (!mWaitingForWindowAnimation) {
+ animateInIconOfFirstTask();
+ }
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ };
+ observer.addOnGlobalLayoutListener(animateFirstIcon);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3bac146..f941f89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -597,6 +597,10 @@
y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
+ recentsItemTopPadding + thumbBgPadding + statusBarHeight);
}
+ if (mLayoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ x = dm.widthPixels - x - res
+ .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
+ }
ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
getStatusBarView(),
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 62eccdf..03dcced 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -746,6 +746,14 @@
mActivityManager = ActivityManagerNative.getDefault();
mBatteryStats = BatteryStatsService.getService();
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+ mAppOps.startWatchingMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, null,
+ new AppOpsManager.Callback() {
+ @Override
+ public void opChanged(int op, String packageName) {
+ updateAppOpsState();
+ }
+ }
+ );
// Get persisted window scale setting
mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
@@ -2150,7 +2158,10 @@
win.attach();
mWindowMap.put(client.asBinder(), win);
if (win.mAppOp != AppOpsManager.OP_NONE) {
- mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
+ if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage())
+ != AppOpsManager.MODE_ALLOWED) {
+ win.setAppOpVisibilityLw(false);
+ }
}
if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
@@ -2439,6 +2450,27 @@
mInputMonitor.updateInputWindowsLw(true /*force*/);
}
+ public void updateAppOpsState() {
+ synchronized(mWindowMap) {
+ boolean changed = false;
+ for (int i=0; i<mDisplayContents.size(); i++) {
+ DisplayContent display = mDisplayContents.valueAt(i);
+ WindowList windows = display.getWindowList();
+ for (int j=0; j<windows.size(); j++) {
+ final WindowState win = windows.get(j);
+ if (win.mAppOp != AppOpsManager.OP_NONE) {
+ changed |= win.setAppOpVisibilityLw(mAppOps.checkOpNoThrow(win.mAppOp,
+ win.getOwningUid(),
+ win.getOwningPackage()) == AppOpsManager.MODE_ALLOWED);
+ }
+ }
+ }
+ if (changed) {
+ scheduleAnimationLocked();
+ }
+ }
+ }
+
static void logSurface(WindowState w, String msg, RuntimeException where) {
String str = " SURFACE " + msg + ": " + w;
if (where != null) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 6648e56..8dda544 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -96,6 +96,7 @@
int mSystemUiVisibility;
boolean mPolicyVisibility = true;
boolean mPolicyVisibilityAfterAnim = true;
+ boolean mAppOpVisibility = true;
boolean mAppFreezing;
boolean mAttachedHidden; // is our parent window hidden?
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
@@ -982,6 +983,10 @@
+ this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
return false;
}
+ if (!mAppOpVisibility) {
+ // Being hidden due to app op request.
+ return false;
+ }
if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
// Already showing.
return false;
@@ -1053,6 +1058,25 @@
return true;
}
+ public boolean setAppOpVisibilityLw(boolean state) {
+ if (mAppOpVisibility != state) {
+ mAppOpVisibility = state;
+ if (state) {
+ // If the policy visibility had last been to hide, then this
+ // will incorrectly show at this point since we lost that
+ // information. Not a big deal -- for the windows that have app
+ // ops modifies they should only be hidden by policy due to the
+ // lock screen, and the user won't be changing this if locked.
+ // Plus it will quickly be fixed the next time we do a layout.
+ showLw(true, false);
+ } else {
+ hideLw(true, false);
+ }
+ return true;
+ }
+ return false;
+ }
+
@Override
public boolean isAlive() {
return mClient.asBinder().isBinderAlive();
@@ -1179,11 +1203,14 @@
pw.print(" mSystemUiVisibility=0x");
pw.println(Integer.toHexString(mSystemUiVisibility));
}
- if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) {
+ if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || !mAppOpVisibility
+ || mAttachedHidden) {
pw.print(prefix); pw.print("mPolicyVisibility=");
pw.print(mPolicyVisibility);
pw.print(" mPolicyVisibilityAfterAnim=");
pw.print(mPolicyVisibilityAfterAnim);
+ pw.print(" mAppOpVisibility=");
+ pw.print(mAppOpVisibility);
pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
}
if (!mRelayoutCalled || mLayoutNeeded) {
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 35dea24..d7a58b6 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -26,7 +26,7 @@
public final class CellInfoLte extends CellInfo implements Parcelable {
private static final String LOG_TAG = "CellInfoLte";
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private CellIdentityLte mCellIdentityLte;
private CellSignalStrengthLte mCellSignalStrengthLte;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 77604a4..1589fec 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -1332,10 +1332,19 @@
P2pStateMachine.this, mGroup.getInterface());
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
WifiP2pDevice groupOwner = mGroup.getOwner();
- /* update group owner details with the ones found at discovery */
- groupOwner.updateSupplicantDetails(mPeers.get(groupOwner.deviceAddress));
- mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
- sendPeersChangedBroadcast();
+ WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
+ if (peer != null) {
+ // update group owner details with peer details found at discovery
+ groupOwner.updateSupplicantDetails(peer);
+ mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
+ sendPeersChangedBroadcast();
+ } else {
+ // A supplicant bug can lead to reporting an invalid
+ // group owner address (all zeroes) at times. Avoid a
+ // crash, but continue group creation since it is not
+ // essential.
+ logw("Unknown group owner " + groupOwner);
+ }
}
transitionTo(mGroupCreatedState);
break;