Merge "Cancel current work in PrintDocumentAdatper if printing is cancelled." into klp-dev
diff --git a/core/java/android/net/PacProxySelector.java b/core/java/android/net/PacProxySelector.java
index b674324..8a2c2b6 100644
--- a/core/java/android/net/PacProxySelector.java
+++ b/core/java/android/net/PacProxySelector.java
@@ -97,7 +97,7 @@
} catch (Exception e) {
port = 8080;
}
- ret.add(new Proxy(Type.HTTP, new InetSocketAddress(host, port)));
+ ret.add(new Proxy(Type.HTTP, InetSocketAddress.createUnresolved(host, port)));
}
}
if (ret.size() == 0) {
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index f76e190..da9ba5a 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1255,7 +1255,8 @@
Animator anim = runningAnimators.keyAt(i);
if (anim != null) {
AnimationInfo oldInfo = runningAnimators.get(anim);
- if (oldInfo != null) {
+ if (oldInfo != null && oldInfo.view != null &&
+ oldInfo.view.getContext() == sceneRoot.getContext()) {
boolean cancel = false;
TransitionValues oldValues = oldInfo.values;
View oldView = oldInfo.view;
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index 4af0f51..9f77d5e 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -20,9 +20,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.util.ArrayMap;
import android.util.AttributeSet;
-import android.util.SparseArray;
import android.util.Xml;
import android.view.InflateException;
import android.view.ViewGroup;
@@ -43,15 +41,7 @@
*/
public class TransitionInflater {
- // We only need one inflater for any given context. Also, this allows us to associate
- // ids with unique instances per-Context, used to avoid re-inflating
- // already-inflated resources into new/different instances
- private static final ArrayMap<Context, TransitionInflater> sInflaterMap =
- new ArrayMap<Context, TransitionInflater>();
-
private Context mContext;
- // TODO: do we need id maps for transitions and transitionMgrs as well?
- SparseArray<Scene> mScenes = new SparseArray<Scene>();
private TransitionInflater(Context context) {
mContext = context;
@@ -61,13 +51,7 @@
* Obtains the TransitionInflater from the given context.
*/
public static TransitionInflater from(Context context) {
- TransitionInflater inflater = sInflaterMap.get(context);
- if (inflater != null) {
- return inflater;
- }
- inflater = new TransitionInflater(context);
- sInflaterMap.put(context, inflater);
- return inflater;
+ return new TransitionInflater(context);
}
/**
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 65a2d4d..5392a96 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -959,9 +959,11 @@
if (!mInDrawing) {
if (verifyDrawable(dr)) {
final Rect dirty = dr.getBounds();
+ final int scrollX = mScrollX + mPaddingLeft;
+ final int scrollY = mScrollY + mPaddingTop;
- invalidate(dirty.left + mScrollX, dirty.top + mScrollY,
- dirty.right + mScrollX, dirty.bottom + mScrollY);
+ invalidate(dirty.left + scrollX, dirty.top + scrollY,
+ dirty.right + scrollX, dirty.bottom + scrollY);
} else {
super.invalidateDrawable(dr);
}
diff --git a/docs/downloads/devbytes/ImmersiveMode.zip b/docs/downloads/devbytes/ImmersiveMode.zip
new file mode 100644
index 0000000..6b82245
--- /dev/null
+++ b/docs/downloads/devbytes/ImmersiveMode.zip
Binary files differ
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index 3e82cbb..61a98b7 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -128,7 +128,7 @@
<p>Three new features that make it easier to understand what players are doing in your game and help you manage game features...</p>
</a></li>
<li><a href="//android-developers.blogspot.com/2013/05/new-ways-to-optimize-your-business-in.html">
- <div class="feed-image" style="background:url('//android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html') no-repeat 0 0;background-size:180px"></div>
+ <div class="feed-image" style="background:url('//3.bp.blogspot.com/-_8WvpdTVGsE/UkxxxrVoNNI/AAAAAAAACj8/FrQyA-BO11c/s1600/gp-referral-ga.png') no-repeat 0 0;background-size:180px"></div>
<h4>Linking Google Analytics with Google Play</h4>
<p>Understanding your users easier through a new integration between Google Analytics and the Google Play Developer Console...</p>
</a></li>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
index 8ccd6fe..36b2446 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardService.java
@@ -68,8 +68,6 @@
}
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
- private boolean mSetHiddenCalled;
- private boolean mIsHidden;
public boolean isShowing() {
return mKeyguardViewMediator.isShowing();
}
@@ -91,10 +89,7 @@
}
public void setHidden(boolean isHidden) {
checkPermission();
- if (mSetHiddenCalled && mIsHidden == isHidden) return;
mKeyguardViewMediator.setHidden(isHidden);
- mSetHiddenCalled = true;
- mIsHidden = isHidden;
}
public void dismiss() {
mKeyguardViewMediator.dismiss();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index d933275..0bfee38 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -98,26 +98,13 @@
}
protected void refresh() {
- Resources res = mContext.getResources();
- Locale locale = Locale.getDefault();
- final String dateFormat = DateFormat.getBestDateTimePattern(locale,
- res.getString(R.string.abbrev_wday_month_day_no_year));
+ Patterns.update(mContext);
- mDateView.setFormat24Hour(dateFormat);
- mDateView.setFormat12Hour(dateFormat);
+ mDateView.setFormat24Hour(Patterns.dateView);
+ mDateView.setFormat12Hour(Patterns.dateView);
- // 12-hour clock.
- // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton
- // format. The following code removes the AM/PM indicator if we didn't want it.
- final String clock12skel = res.getString(R.string.clock_12hr_format);
- String clock12hr = DateFormat.getBestDateTimePattern(locale, clock12skel);
- clock12hr = clock12skel.contains("a") ? clock12hr : clock12hr.replaceAll("a", "").trim();
- mClockView.setFormat12Hour(clock12hr);
-
- // 24-hour clock
- final String clock24skel = res.getString(R.string.clock_24hr_format);
- final String clock24hr = DateFormat.getBestDateTimePattern(locale, clock24skel);
- mClockView.setFormat24Hour(clock24hr);
+ mClockView.setFormat12Hour(Patterns.clockView12);
+ mClockView.setFormat24Hour(Patterns.clockView24);
refreshAlarmStatus();
}
@@ -149,4 +136,35 @@
return LockPatternUtils.ID_DEFAULT_STATUS_WIDGET;
}
+ // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
+ // This is an optimization to ensure we only recompute the patterns when the inputs change.
+ private static final class Patterns {
+ static String dateView;
+ static String clockView12;
+ static String clockView24;
+ static String cacheKey;
+
+ static void update(Context context) {
+ final Locale locale = Locale.getDefault();
+ final Resources res = context.getResources();
+ final String dateViewSkel = res.getString(R.string.abbrev_wday_month_day_no_year);
+ final String clockView12Skel = res.getString(R.string.clock_12hr_format);
+ final String clockView24Skel = res.getString(R.string.clock_24hr_format);
+ final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel;
+ if (key.equals(cacheKey)) return;
+
+ dateView = DateFormat.getBestDateTimePattern(locale, dateViewSkel);
+
+ clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel);
+ // CLDR insists on adding an AM/PM indicator even though it wasn't in the skeleton
+ // format. The following code removes the AM/PM indicator if we didn't want it.
+ if (!clockView12Skel.contains("a")) {
+ clockView12 = clockView12.replaceAll("a", "").trim();
+ }
+
+ clockView24 = DateFormat.getBestDateTimePattern(locale, clockView24Skel);
+
+ cacheKey = key;
+ }
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 520cea3..a849316 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -815,7 +815,7 @@
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onKeyguardVisibilityChanged(isShowing);
+ cb.onKeyguardVisibilityChangedRaw(isShowing);
}
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 76f9637..c08880d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -19,6 +19,7 @@
import android.app.admin.DevicePolicyManager;
import android.graphics.Bitmap;
import android.media.AudioManager;
+import android.os.SystemClock;
import android.view.WindowManagerPolicy;
import com.android.internal.telephony.IccCardConstants;
@@ -27,6 +28,11 @@
* Callback for general information relevant to lock screen.
*/
class KeyguardUpdateMonitorCallback {
+
+ private static final long VISIBILITY_CHANGED_COLLAPSE_MS = 1000;
+ private long mVisibilityChangedCalled;
+ private boolean mShowing;
+
/**
* Called when the battery status changes, e.g. when plugged in or unplugged, charge
* level, etc. changes.
@@ -70,6 +76,15 @@
*/
void onKeyguardVisibilityChanged(boolean showing) { }
+ void onKeyguardVisibilityChangedRaw(boolean showing) {
+ final long now = SystemClock.elapsedRealtime();
+ if (showing == mShowing
+ && (now - mVisibilityChangedCalled) < VISIBILITY_CHANGED_COLLAPSE_MS) return;
+ onKeyguardVisibilityChanged(showing);
+ mVisibilityChangedCalled = now;
+ mShowing = showing;
+ }
+
/**
* Called when visibility of lockscreen clock changes, such as when
* obscured by a widget.
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index 596435a..10bcdad 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -117,8 +117,8 @@
if (!proxy.equals(Proxy.NO_PROXY)) {
// Only Inets created by PacProxySelector.
InetSocketAddress inetSocketAddress =
- (InetSocketAddress)list.get(0).address();
- server = new Socket(inetSocketAddress.getAddress(),
+ (InetSocketAddress)proxy.address();
+ server = new Socket(inetSocketAddress.getHostName(),
inetSocketAddress.getPort());
sendLine(server, requestLine);
} else {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 7c61c44..594f683 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -77,6 +77,7 @@
import android.net.wimax.WimaxManagerConstants;
import android.os.AsyncTask;
import android.os.Binder;
+import android.os.Build;
import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
@@ -141,6 +142,7 @@
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.URL;
+import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -154,6 +156,10 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+
/**
* @hide
*/
@@ -4066,8 +4072,28 @@
static class CheckMp extends
AsyncTask<CheckMp.Params, Void, Integer> {
private static final String CHECKMP_TAG = "CheckMp";
+
+ // adb shell setprop persist.checkmp.testfailures 1 to enable testing failures
+ private static boolean mTestingFailures;
+
+ // Choosing 4 loops as half of them will use HTTPS and the other half HTTP
+ private static final int MAX_LOOPS = 4;
+
+ // Number of milli-seconds to complete all of the retires
public static final int MAX_TIMEOUT_MS = 60000;
+
+ // The socket should retry only 5 seconds, the default is longer
private static final int SOCKET_TIMEOUT_MS = 5000;
+
+ // Sleep time for network errors
+ private static final int NET_ERROR_SLEEP_SEC = 3;
+
+ // Sleep time for network route establishment
+ private static final int NET_ROUTE_ESTABLISHMENT_SLEEP_SEC = 3;
+
+ // Short sleep time for polling :(
+ private static final int POLLING_SLEEP_SEC = 1;
+
private Context mContext;
private ConnectivityService mCs;
private TelephonyManager mTm;
@@ -4093,6 +4119,31 @@
}
}
+ // As explained to me by Brian Carlstrom and Kenny Root, Certificates can be
+ // issued by name or ip address, for Google its by name so when we construct
+ // this HostnameVerifier we'll pass the original Uri and use it to verify
+ // the host. If the host name in the original uril fails we'll test the
+ // hostname parameter just incase things change.
+ static class CheckMpHostnameVerifier implements HostnameVerifier {
+ Uri mOrgUri;
+
+ CheckMpHostnameVerifier(Uri orgUri) {
+ mOrgUri = orgUri;
+ }
+
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
+ String orgUriHost = mOrgUri.getHost();
+ boolean retVal = hv.verify(orgUriHost, session) || hv.verify(hostname, session);
+ if (DBG) {
+ log("isMobileOk: hostnameVerify retVal=" + retVal + " hostname=" + hostname
+ + " orgUriHost=" + orgUriHost);
+ }
+ return retVal;
+ }
+ }
+
/**
* The call back object passed in Params. onComplete will be called
* on the main thread.
@@ -4103,6 +4154,13 @@
}
public CheckMp(Context context, ConnectivityService cs) {
+ if (Build.IS_DEBUGGABLE) {
+ mTestingFailures =
+ SystemProperties.getInt("persist.checkmp.testfailures", 0) == 1;
+ } else {
+ mTestingFailures = false;
+ }
+
mContext = context;
mCs = cs;
@@ -4174,7 +4232,7 @@
mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
break;
}
- sleep(1);
+ sleep(POLLING_SLEEP_SEC);
}
}
@@ -4192,7 +4250,7 @@
}
if (VDBG) log("isMobileOk: hipri not started yet");
result = CMP_RESULT_CODE_NO_CONNECTION;
- sleep(1);
+ sleep(POLLING_SLEEP_SEC);
}
// Continue trying to connect until time has run out
@@ -4208,7 +4266,7 @@
log("isMobileOk: not connected ni=" +
mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
}
- sleep(1);
+ sleep(POLLING_SLEEP_SEC);
result = CMP_RESULT_CODE_NO_CONNECTION;
continue;
}
@@ -4226,7 +4284,7 @@
// Get of the addresses associated with the url host. We need to use the
// address otherwise HttpURLConnection object will use the name to get
- // the addresses and is will try every address but that will bypass the
+ // the addresses and will try every address but that will bypass the
// route to host we setup and the connection could succeed as the default
// interface might be connected to the internet via wifi or other interface.
InetAddress[] addresses;
@@ -4263,14 +4321,14 @@
int addrTried = 0;
while (true) {
- // Loop through at most 3 valid addresses or until
+ // Loop through at most MAX_LOOPS valid addresses or until
// we run out of time
- if (addrTried++ >= 3) {
- log("too many loops tried - giving up");
+ if (addrTried++ >= MAX_LOOPS) {
+ log("isMobileOk: too many loops tried - giving up");
break;
}
if (SystemClock.elapsedRealtime() >= endTime) {
- log("spend too much time - giving up");
+ log("isMobileOk: spend too much time - giving up");
break;
}
@@ -4283,25 +4341,37 @@
// Wait a short time to be sure the route is established ??
log("isMobileOk:"
+ " wait to establish route to hostAddr=" + hostAddr);
- sleep(3);
+ sleep(NET_ROUTE_ESTABLISHMENT_SLEEP_SEC);
} else {
log("isMobileOk:"
+ " could not establish route to hostAddr=" + hostAddr);
+ // Wait a short time before the next attempt
+ sleep(NET_ERROR_SLEEP_SEC);
continue;
}
- // Rewrite the url to have numeric address to use the specific route.
- // Add a pointless random query param to fool proxies into not caching.
- URL newUrl = new URL(orgUri.getScheme(),
- hostAddr.getHostAddress(),
- orgUri.getPath() + "?q=" + rand.nextInt(Integer.MAX_VALUE));
+ // Rewrite the url to have numeric address to use the specific route
+ // using http for half the attempts and https for the other half.
+ // Doing https first and http second as on a redirected walled garden
+ // such as t-mobile uses we get a SocketTimeoutException: "SSL
+ // handshake timed out" which we declare as
+ // CMP_RESULT_CODE_NO_TCP_CONNECTION. We could change this, but by
+ // having http second we will be using logic used for some time.
+ URL newUrl;
+ String scheme = (addrTried <= (MAX_LOOPS/2)) ? "https" : "http";
+ newUrl = new URL(scheme, hostAddr.getHostAddress(),
+ orgUri.getPath());
log("isMobileOk: newUrl=" + newUrl);
HttpURLConnection urlConn = null;
try {
- // Open the connection set the request header and get the response
- urlConn = (HttpURLConnection) newUrl.openConnection(
+ // Open the connection set the request headers and get the response
+ urlConn = (HttpURLConnection)newUrl.openConnection(
java.net.Proxy.NO_PROXY);
+ if (scheme.equals("https")) {
+ ((HttpsURLConnection)urlConn).setHostnameVerifier(
+ new CheckMpHostnameVerifier(orgUri));
+ }
urlConn.setInstanceFollowRedirects(false);
urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS);
urlConn.setReadTimeout(SOCKET_TIMEOUT_MS);
@@ -4320,10 +4390,17 @@
urlConn.disconnect();
urlConn = null;
+ if (mTestingFailures) {
+ // Pretend no connection, this tests using http and https
+ result = CMP_RESULT_CODE_NO_CONNECTION;
+ log("isMobileOk: TESTING_FAILURES, pretend no connction");
+ continue;
+ }
+
if (responseCode == 204) {
// Return
result = CMP_RESULT_CODE_CONNECTABLE;
- log("isMobileOk: X expected responseCode=" + responseCode
+ log("isMobileOk: X got expected responseCode=" + responseCode
+ " result=" + result);
return result;
} else {
@@ -4337,12 +4414,14 @@
result = CMP_RESULT_CODE_REDIRECTED;
}
} catch (Exception e) {
- log("isMobileOk: HttpURLConnection Exception e=" + e);
+ log("isMobileOk: HttpURLConnection Exception" + e);
result = CMP_RESULT_CODE_NO_TCP_CONNECTION;
if (urlConn != null) {
urlConn.disconnect();
urlConn = null;
}
+ sleep(NET_ERROR_SLEEP_SEC);
+ continue;
}
}
log("isMobileOk: X loops|timed out result=" + result);
@@ -4370,7 +4449,7 @@
log("isMobileOk: connected ni=" +
mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI));
}
- sleep(1);
+ sleep(POLLING_SLEEP_SEC);
continue;
}
}
@@ -4435,7 +4514,7 @@
}
}
- private void log(String s) {
+ private static void log(String s) {
Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s);
}
}