Merge "Only use default backgrounds when not extending AlertDialog style" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 334f789..a0d47e4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36795,7 +36795,6 @@
method public deprecated void onGlobalFocusChanged(android.view.View, android.view.View);
method public void onPause();
method public void onResume();
- method public static void optOutDataReductionProxy();
method public boolean overlayHorizontalScrollbar();
method public boolean overlayVerticalScrollbar();
method public boolean pageDown(boolean);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 6cc6fb2..ebeaf34 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1917,7 +1917,7 @@
mPeople = new ArrayList<String>();
mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L ?
- NotificationColorUtil.getInstance() : null;
+ NotificationColorUtil.getInstance(mContext) : null;
}
/**
@@ -2890,7 +2890,7 @@
}
private void processLegacyAction(Action action, RemoteViews button) {
- if (!isLegacy() || mColorUtil.isGrayscale(mContext, action.icon)) {
+ if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.icon)) {
button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
mContext.getResources().getColor(R.color.notification_action_color_filter),
PorterDuff.Mode.MULTIPLY);
@@ -2909,7 +2909,7 @@
* Apply any necessary background to smallIcons being used in the largeIcon spot.
*/
private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) {
- if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) {
+ if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, largeIconId)) {
applyLargeIconBackground(contentView);
}
}
@@ -2920,7 +2920,7 @@
*/
// TODO: also check bounds, transparency, that sort of thing.
private void processLargeLegacyIcon(Bitmap largeIcon, RemoteViews contentView) {
- if (isLegacy() && mColorUtil.isGrayscale(largeIcon)) {
+ if (isLegacy() && mColorUtil.isGrayscaleIcon(largeIcon)) {
applyLargeIconBackground(contentView);
} else {
removeLargeIconBackground(contentView);
@@ -2956,7 +2956,7 @@
*/
private void processSmallRightIcon(int smallIconDrawableId,
RemoteViews contentView) {
- if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) {
+ if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, smallIconDrawableId)) {
contentView.setDrawableParameters(R.id.right_icon, false, -1,
0xFFFFFFFF,
PorterDuff.Mode.SRC_ATOP, -1);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index e1f19ee..edfa7af3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1810,21 +1810,6 @@
}
/**
- * Sets whether the application wants to opt out from using the Data Reduction Proxy
- * service.
- * Data reduction proxy can only be enabled by the user and will almost always be
- * transparent to the application. In rare cases where using the proxy interferes
- * with the app, the application developer can use this API to opt out from using the
- * proxy. Note that this may increase network bandwidth usage.
- *
- * See <a href=http://developer.chrome.com/multidevice/data-compression>
- * Data Compression Proxy</a>
- */
- public static void optOutDataReductionProxy() {
- getFactory().getStatics().optOutDataReductionProxy();
- }
-
- /**
* Gets the list of currently loaded plugins.
*
* @return the list of currently loaded plugins
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 48f3ca3..20bb932 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -61,12 +61,6 @@
/**
* Implements the API method:
- * {@link android.webkit.WebView#optOutDataReductionProxy() }
- */
- void optOutDataReductionProxy();
-
- /**
- * Implements the API method:
* {@link android.webkit.WebView#setSlowWholeDocumentDrawEnabled(boolean) }
*/
void enableSlowWholeDocumentDraw();
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index ee17b78..345eafb 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1878,6 +1878,9 @@
if (mOnValueChangeListener != null) {
mOnValueChangeListener.onValueChange(this, previous, mValue);
}
+
+ mAccessibilityNodeProvider.sendAccessibilityEventForVirtualText(
+ AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
/**
@@ -2556,6 +2559,7 @@
getLocationOnScreen(locationOnScreen);
boundsInScreen.offset(locationOnScreen[0], locationOnScreen[1]);
info.setBoundsInScreen(boundsInScreen);
+ info.setLiveRegion(View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE);
return info;
}
diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java
index a5ce6e0ca..c153904 100644
--- a/core/java/com/android/internal/util/ImageUtils.java
+++ b/core/java/com/android/internal/util/ImageUtils.java
@@ -17,6 +17,10 @@
package com.android.internal.util;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
/**
* Utility class for image analysis and processing.
@@ -31,17 +35,49 @@
// Alpha amount for which values below are considered transparent.
private static final int ALPHA_TOLERANCE = 50;
+ // Size of the smaller bitmap we're actually going to scan.
+ private static final int COMPACT_BITMAP_SIZE = 64; // pixels
+
private int[] mTempBuffer;
+ private Bitmap mTempCompactBitmap;
+ private Canvas mTempCompactBitmapCanvas;
+ private Paint mTempCompactBitmapPaint;
+ private final Matrix mTempMatrix = new Matrix();
/**
* Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect
* gray".
+ *
+ * Instead of scanning every pixel in the bitmap, we first resize the bitmap to no more than
+ * COMPACT_BITMAP_SIZE^2 pixels using filtering. The hope is that any non-gray color elements
+ * will survive the squeezing process, contaminating the result with color.
*/
public boolean isGrayscale(Bitmap bitmap) {
- final int height = bitmap.getHeight();
- final int width = bitmap.getWidth();
- int size = height*width;
+ int height = bitmap.getHeight();
+ int width = bitmap.getWidth();
+ // shrink to a more manageable (yet hopefully no more or less colorful) size
+ if (height > COMPACT_BITMAP_SIZE || width > COMPACT_BITMAP_SIZE) {
+ if (mTempCompactBitmap == null) {
+ mTempCompactBitmap = Bitmap.createBitmap(
+ COMPACT_BITMAP_SIZE, COMPACT_BITMAP_SIZE, Bitmap.Config.ARGB_8888
+ );
+ mTempCompactBitmapCanvas = new Canvas(mTempCompactBitmap);
+ mTempCompactBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mTempCompactBitmapPaint.setFilterBitmap(true);
+ }
+ mTempMatrix.reset();
+ mTempMatrix.setScale(
+ (float) COMPACT_BITMAP_SIZE / width,
+ (float) COMPACT_BITMAP_SIZE / height,
+ 0, 0);
+ mTempCompactBitmapCanvas.drawColor(0, PorterDuff.Mode.SRC); // select all, erase
+ mTempCompactBitmapCanvas.drawBitmap(bitmap, mTempMatrix, mTempCompactBitmapPaint);
+ bitmap = mTempCompactBitmap;
+ width = height = COMPACT_BITMAP_SIZE;
+ }
+
+ final int size = height*width;
ensureBufferSize(size);
bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height);
for (int i = 0; i < size; i++) {
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 665055c..3249ea3 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -50,23 +50,36 @@
private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
- public static NotificationColorUtil getInstance() {
+ private final int mGrayscaleIconMaxSize; // @dimen/notification_large_icon_width (64dp)
+
+ public static NotificationColorUtil getInstance(Context context) {
synchronized (sLock) {
if (sInstance == null) {
- sInstance = new NotificationColorUtil();
+ sInstance = new NotificationColorUtil(context);
}
return sInstance;
}
}
+ private NotificationColorUtil(Context context) {
+ mGrayscaleIconMaxSize = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_large_icon_width);
+ }
+
/**
- * Checks whether a bitmap is grayscale. Grayscale here means "very close to a perfect
- * gray".
+ * Checks whether a Bitmap is a small grayscale icon.
+ * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp".
*
* @param bitmap The bitmap to test.
- * @return Whether the bitmap is grayscale.
+ * @return True if the bitmap is grayscale; false if it is color or too large to examine.
*/
- public boolean isGrayscale(Bitmap bitmap) {
+ public boolean isGrayscaleIcon(Bitmap bitmap) {
+ // quick test: reject large bitmaps
+ if (bitmap.getWidth() > mGrayscaleIconMaxSize
+ || bitmap.getHeight() > mGrayscaleIconMaxSize) {
+ return false;
+ }
+
synchronized (sLock) {
Pair<Boolean, Integer> cached = mGrayscaleBitmapCache.get(bitmap);
if (cached != null) {
@@ -92,22 +105,22 @@
}
/**
- * Checks whether a drawable is grayscale. Grayscale here means "very close to a perfect
- * gray".
+ * Checks whether a Drawable is a small grayscale icon.
+ * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp".
*
* @param d The drawable to test.
- * @return Whether the drawable is grayscale.
+ * @return True if the bitmap is grayscale; false if it is color or too large to examine.
*/
- public boolean isGrayscale(Drawable d) {
+ public boolean isGrayscaleIcon(Drawable d) {
if (d == null) {
return false;
} else if (d instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) d;
- return bd.getBitmap() != null && isGrayscale(bd.getBitmap());
+ return bd.getBitmap() != null && isGrayscaleIcon(bd.getBitmap());
} else if (d instanceof AnimationDrawable) {
AnimationDrawable ad = (AnimationDrawable) d;
int count = ad.getNumberOfFrames();
- return count > 0 && isGrayscale(ad.getFrame(0));
+ return count > 0 && isGrayscaleIcon(ad.getFrame(0));
} else if (d instanceof VectorDrawable) {
// We just assume you're doing the right thing if using vectors
return true;
@@ -117,16 +130,16 @@
}
/**
- * Checks whether a drawable with a resoure id is grayscale. Grayscale here means "very close
- * to a perfect gray".
+ * Checks whether a drawable with a resoure id is a small grayscale icon.
+ * Grayscale here means "very close to a perfect gray"; icon means "no larger than 64dp".
*
* @param context The context to load the drawable from.
- * @return Whether the drawable is grayscale.
+ * @return True if the bitmap is grayscale; false if it is color or too large to examine.
*/
- public boolean isGrayscale(Context context, int drawableResId) {
+ public boolean isGrayscaleIcon(Context context, int drawableResId) {
if (drawableResId != 0) {
try {
- return isGrayscale(context.getDrawable(drawableResId));
+ return isGrayscaleIcon(context.getDrawable(drawableResId));
} catch (Resources.NotFoundException ex) {
Log.e(TAG, "Drawable not found: " + drawableResId);
return false;
diff --git a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml b/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
deleted file mode 100644
index ce6eebc..0000000
--- a/core/tests/ConnectivityManagerTest/assets/accesspoints.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <accesspoint>
- <ssid>opennet</ssid>
- <security>NONE</security>
- </accesspoint>
- <accesspoint>
- <ssid>GoogleGuest</ssid>
- <security>NONE</security>
- </accesspoint>
- <accesspoint>
- <ssid>securenetdhcp</ssid>
- <security>PSK</security>
- <password>androidwifi</password>
- </accesspoint>
- <accesspoint>
- <ssid>securenetstatic</ssid>
- <security>PSK</security>
- <password>androidwifi</password>
- <ip>192.168.14.2</ip>
- <gateway>192.168.14.1</gateway>
- <networkprefixlength>24</networkprefixlength>
- <dns1>192.168.14.1</dns1>
- <dns2>192.168.1.9</dns2>
- </accesspoint>
-<!-- TODO: This AP is outdated and only supports 2.4GHz.
- Need to switch to a new dual-band AP.
- Enable this test case again once the configuration is completed.
- bug#: 9470594
- <accesspoint>
- <ssid>botnet</ssid>
- <security>EAP</security>
- <eap>PEAP</eap>
- <phase2>MSCHAPV2</phase2>
- <identity>donut</identity>
- <password>android</password>
- </accesspoint>
--->
-</resources>
-
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
deleted file mode 100644
index 1222c8b..0000000
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.connectivitymanagertest;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import android.net.IpConfiguration.IpAssignment;
-import android.net.IpConfiguration.ProxySettings;
-import android.net.LinkAddress;
-import android.net.RouteInfo;
-import android.net.StaticIpConfiguration;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.AuthAlgorithm;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiEnterpriseConfig;
-
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * Help class to process configurations of access points saved in an XML file.
- * The configurations of an access point is included in tag
- * <accesspoint></accesspoint>. The supported configuration includes: ssid,
- * security, eap, phase2, identity, password, anonymousidentity, cacert, usercert,
- * in which each is included in the corresponding tags. Static IP setting is also supported.
- * Tags that can be used include: ip, gateway, networkprefixlength, dns1, dns2. All access points
- * have to be enclosed in tags of <resources></resources>.
- *
- * The following is a sample configuration file for an access point using EAP-PEAP with MSCHAP2.
- * <resources>
- * <accesspoint>
- * <ssid>testnet</ssid>
- * <security>EAP</security>
- * <eap>PEAP</eap>
- * <phase2>MSCHAP2</phase2>
- * <identity>donut</identity</identity>
- * <password>abcdefgh</password>
- * </accesspoint>
- * </resources>
- *
- * Note:ssid and security have to be the first two tags
- * for static ip setting, tag "ip" should be listed before other fields: dns, gateway,
- * networkprefixlength.
- */
-public class AccessPointParserHelper {
- static final int NONE = 0;
- static final int WEP = 1;
- static final int PSK = 2;
- static final int EAP = 3;
-
- List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
-
- private int getSecurityType (String security) {
- if (security.equalsIgnoreCase("NONE")) {
- return NONE;
- } else if (security.equalsIgnoreCase("WEP")) {
- return WEP;
- } else if (security.equalsIgnoreCase("PSK")) {
- return PSK;
- } else if (security.equalsIgnoreCase("EAP")) {
- return EAP;
- } else {
- return -1;
- }
- }
-
- private boolean validateEapValue(String value) {
- if (value.equalsIgnoreCase("PEAP") ||
- value.equalsIgnoreCase("TLS") ||
- value.equalsIgnoreCase("TTLS")) {
- return true;
- } else {
- return false;
- }
- }
-
- DefaultHandler mHandler = new DefaultHandler() {
-
- boolean ssid = false;
- boolean security = false;
- boolean password = false;
- boolean ip = false;
- boolean gateway = false;
- boolean networkprefix = false;
- boolean dns1 = false;
- boolean dns2 = false;
- boolean eap = false;
- boolean phase2 = false;
- boolean identity = false;
- boolean anonymousidentity = false;
- boolean cacert = false;
- boolean usercert = false;
- WifiConfiguration config = null;
- int securityType = NONE;
- StaticIpConfiguration mStaticIpConfiguration = null;
- InetAddress mInetAddr = null;
-
- @Override
- public void startElement(String uri, String localName, String tagName,
- Attributes attributes) throws SAXException {
- if (tagName.equalsIgnoreCase("accesspoint")) {
- config = new WifiConfiguration();
- }
- if (tagName.equalsIgnoreCase("ssid")) {
- ssid = true;
- }
- if (tagName.equalsIgnoreCase("security")) {
- security = true;
- }
- if (tagName.equalsIgnoreCase("password")) {
- password = true;
- }
- if (tagName.equalsIgnoreCase("eap")) {
- eap = true;
- }
- if (tagName.equalsIgnoreCase("phase2")) {
- phase2 = true;
- }
- if (tagName.equalsIgnoreCase("identity")) {
- identity = true;
- }
- if (tagName.equalsIgnoreCase("anonymousidentity")) {
- anonymousidentity = true;
- }
- if (tagName.equalsIgnoreCase("cacert")) {
- cacert = true;
- }
- if (tagName.equalsIgnoreCase("usercert")) {
- usercert = true;
- }
- if (tagName.equalsIgnoreCase("ip")) {
- mStaticIpConfiguration = new StaticIpConfiguration();
- ip = true;
- }
- if (tagName.equalsIgnoreCase("gateway")) {
- gateway = true;
- }
- if (tagName.equalsIgnoreCase("networkprefixlength")) {
- networkprefix = true;
- }
- if (tagName.equalsIgnoreCase("dns1")) {
- dns1 = true;
- }
- if (tagName.equalsIgnoreCase("dns2")) {
- dns2 = true;
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String tagName) throws SAXException {
- if (tagName.equalsIgnoreCase("accesspoint")) {
- if (mStaticIpConfiguration != null) {
- config.setIpAssignment(IpAssignment.STATIC);
- config.setStaticIpConfiguration(mStaticIpConfiguration);
- } else {
- config.setIpAssignment(IpAssignment.DHCP);
- }
- config.setProxySettings(ProxySettings.NONE);
- networks.add(config);
- mStaticIpConfiguration = null;
- }
- }
-
- @Override
- public void characters(char ch[], int start, int length) throws SAXException {
- if (ssid) {
- config.SSID = new String(ch, start, length);
- ssid = false;
- }
- if (security) {
- String securityStr = (new String(ch, start, length)).toUpperCase();
- securityType = getSecurityType(securityStr);
- switch (securityType) {
- case NONE:
- config.allowedKeyManagement.set(KeyMgmt.NONE);
- break;
- case WEP:
- config.allowedKeyManagement.set(KeyMgmt.NONE);
- config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
- config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
- break;
- case PSK:
- config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
- break;
- case EAP:
- config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
- config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
- // Initialize other fields.
- config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
- config.enterpriseConfig.setCaCertificateAlias("");
- config.enterpriseConfig.setClientCertificateAlias("");
- config.enterpriseConfig.setIdentity("");
- config.enterpriseConfig.setAnonymousIdentity("");
- break;
- default:
- throw new SAXException();
- }
- security = false;
- }
- if (password) {
- String passwordStr = new String(ch, start, length);
- int len = passwordStr.length();
- if (len == 0) {
- throw new SAXException();
- }
- if (securityType == WEP) {
- if ((len == 10 || len == 26 || len == 58) &&
- passwordStr.matches("[0-9A-Fa-f]*")) {
- config.wepKeys[0] = passwordStr;
- } else {
- config.wepKeys[0] = '"' + passwordStr + '"';
- }
- } else if (securityType == PSK) {
- if (passwordStr.matches("[0-9A-Fa-f]{64}")) {
- config.preSharedKey = passwordStr;
- } else {
- config.preSharedKey = '"' + passwordStr + '"';
- }
- } else if (securityType == EAP) {
- config.enterpriseConfig.setPassword(passwordStr);
- } else {
- throw new SAXException();
- }
- password = false;
- }
- if (eap) {
- String eapValue = new String(ch, start, length);
- if (!validateEapValue(eapValue)) {
- throw new SAXException();
- }
- if (eapValue.equals("TLS")) {
- config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
- } else if (eapValue.equals("TTLS")) {
- config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS);
- } else if (eapValue.equals("PEAP")) {
- config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PEAP);
- }
- eap = false;
- }
- if (phase2) {
- String phase2Value = new String(ch, start, length);
- if (phase2Value.equals("PAP")) {
- config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.PAP);
- } else if (phase2Value.equals("MSCHAP")) {
- config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAP);
- } else if (phase2Value.equals("MSCHAPV2")) {
- config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAPV2);
- } else if (phase2Value.equals("GTC")) {
- config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
- }
- phase2 = false;
- }
- if (identity) {
- String identityValue = new String(ch, start, length);
- config.enterpriseConfig.setIdentity(identityValue);
- identity = false;
- }
- if (anonymousidentity) {
- String anonyId = new String(ch, start, length);
- config.enterpriseConfig.setAnonymousIdentity(anonyId);
- anonymousidentity = false;
- }
- if (cacert) {
- String cacertValue = new String(ch, start, length);
- config.enterpriseConfig.setCaCertificateAlias(cacertValue);
- cacert = false;
- }
- if (usercert) {
- String usercertValue = new String(ch, start, length);
- config.enterpriseConfig.setClientCertificateAlias(usercertValue);
- usercert = false;
- }
- if (ip) {
- try {
- String ipAddr = new String(ch, start, length);
- if (!InetAddress.isNumeric(ipAddr)) {
- throw new SAXException();
- }
- mInetAddr = InetAddress.getByName(ipAddr);
- } catch (UnknownHostException e) {
- throw new SAXException();
- }
- ip = false;
- }
- if (gateway) {
- try {
- String gwAddr = new String(ch, start, length);
- if (!InetAddress.isNumeric(gwAddr)) {
- throw new SAXException();
- }
- mStaticIpConfiguration.gateway = InetAddress.getByName(gwAddr);
- } catch (UnknownHostException e) {
- throw new SAXException();
- }
- gateway = false;
- }
- if (networkprefix) {
- try {
- int nwPrefixLength = Integer.parseInt(new String(ch, start, length));
- if ((nwPrefixLength < 0) || (nwPrefixLength > 32)) {
- throw new SAXException();
- }
- mStaticIpConfiguration.ipAddress = new LinkAddress(mInetAddr, nwPrefixLength);
- } catch (NumberFormatException e) {
- throw new SAXException();
- }
- networkprefix = false;
- }
- if (dns1) {
- try {
- String dnsAddr = new String(ch, start, length);
- if (!InetAddress.isNumeric(dnsAddr)) {
- throw new SAXException();
- }
- mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr));
- } catch (UnknownHostException e) {
- throw new SAXException();
- }
- dns1 = false;
- }
- if (dns2) {
- try {
- String dnsAddr = new String(ch, start, length);
- if (!InetAddress.isNumeric(dnsAddr)) {
- throw new SAXException();
- }
- mStaticIpConfiguration.dnsServers.add(InetAddress.getByName(dnsAddr));
- } catch (UnknownHostException e) {
- throw new SAXException();
- }
- dns2 = false;
- }
- }
- };
-
- /**
- * Process the InputStream in
- * @param in is the InputStream that can be used for XML parsing
- * @throws Exception
- */
- public AccessPointParserHelper(InputStream in) throws Exception {
- SAXParserFactory factory = SAXParserFactory.newInstance();
- SAXParser saxParser = factory.newSAXParser();
- saxParser.parse(in, mHandler);
- }
-
- public List<WifiConfiguration> getNetworkConfigurations() throws Exception {
- return networks;
- }
-}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index 0f9d8e9..a3c5351 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -26,7 +26,6 @@
import android.net.NetworkInfo.State;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiManager;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -35,10 +34,8 @@
import android.view.KeyEvent;
import java.io.IOException;
-import java.io.InputStream;
import java.net.UnknownHostException;
import java.util.List;
-import java.util.regex.Pattern;
/**
@@ -52,8 +49,6 @@
*/
public class ConnectivityManagerTestBase extends InstrumentationTestCase {
- private static final String LOG_TAG = "ConnectivityManagerTestBase";
- private static final String ACCESS_POINT_FILE = "accesspoints.xml";
private static final String PING_IP_ADDR = "8.8.8.8";
protected static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
@@ -69,9 +64,10 @@
protected static final int FAILURE = 1;
protected static final int INIT = -1;
+ protected final String mLogTag;
+
private ConnectivityReceiver mConnectivityReceiver = null;
private WifiReceiver mWifiReceiver = null;
- private AccessPointParserHelper mParseHelper = null;
private long mLastConnectivityChangeTime = -1;
protected ConnectivityManager mCm;
@@ -82,6 +78,11 @@
/* Control Wifi States */
public WifiManager mWifiManager;
+ public ConnectivityManagerTestBase(String logTag) {
+ super();
+ mLogTag = logTag;
+ }
+
protected long getLastConnectivityChangeTime() {
return mLastConnectivityChangeTime;
}
@@ -94,7 +95,7 @@
@Override
public void onReceive(Context context, Intent intent) {
mLastConnectivityChangeTime = SystemClock.uptimeMillis();
- log("ConnectivityReceiver: " + intent);
+ logv("ConnectivityReceiver: " + intent);
String action = intent.getAction();
if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
@@ -108,7 +109,7 @@
String action = intent.getAction();
Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- log("scan results are available");
+ logv("scan results are available");
synchronized (mWifiScanResultLock) {
mLastScanResult = mWifiManager.getScanResults();
mWifiScanResultLock.notifyAll();
@@ -130,7 +131,7 @@
if (mWifiManager.isWifiApEnabled()) {
// if soft AP is enabled, disable it
mWifiManager.setWifiApEnabled(null, false);
- log("Disable soft ap");
+ logv("Disable soft ap");
}
// register a connectivity receiver for CONNECTIVITY_ACTION;
@@ -148,32 +149,25 @@
mIntentFilter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
mContext.registerReceiver(mWifiReceiver, mIntentFilter);
- log("Clear Wifi before we start the test.");
+ logv("Clear Wifi before we start the test.");
removeConfiguredNetworksAndDisableWifi();
}
- protected List<WifiConfiguration> loadNetworkConfigurations() throws Exception {
- InputStream in = mContext.getAssets().open(ACCESS_POINT_FILE);
- mParseHelper = new AccessPointParserHelper(in);
- return mParseHelper.getNetworkConfigurations();
- }
-
// wait for network connectivity state: CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING,
// DISCONNECTED, UNKNOWN
protected boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
long startTime = SystemClock.uptimeMillis();
while (true) {
NetworkInfo ni = mCm.getNetworkInfo(networkType);
- String niString = ni == null ? "null" : ni.toString();
if (ni != null && expectedState.equals(ni.getState())) {
- log("waitForNetworkState success: " + niString);
+ logv("waitForNetworkState success: %s", ni);
return true;
}
if ((SystemClock.uptimeMillis() - startTime) > timeout) {
- log("waitForNetworkState timeout: " + niString);
+ logv("waitForNetworkState timeout: %s", ni);
return false;
}
- log("waitForNetworkState interim: " + niString);
+ logv("waitForNetworkState interim: %s", ni);
SystemClock.sleep(SHORT_TIMEOUT);
}
}
@@ -185,16 +179,14 @@
while (true) {
int state = mWifiManager.getWifiState();
if (state == expectedState) {
- log("waitForWifiState success: state=" + state);
+ logv("waitForWifiState success: state=" + state);
return true;
}
if ((SystemClock.uptimeMillis() - startTime) > timeout) {
- log(String.format("waitForWifiState timeout: expected=%d, actual=%d",
- expectedState, state));
+ logv("waitForWifiState timeout: expected=%d, actual=%d", expectedState, state);
return false;
}
- log(String.format("waitForWifiState interim: expected=%d, actual=%d",
- expectedState, state));
+ logv("waitForWifiState interim: expected=%d, actual=%d", expectedState, state);
SystemClock.sleep(SHORT_TIMEOUT);
}
}
@@ -206,15 +198,15 @@
while (true) {
int state = mWifiManager.getWifiApState();
if (state == expectedState) {
- log("waitForWifiAPState success: state=" + state);
+ logv("waitForWifiAPState success: state=" + state);
return true;
}
if ((SystemClock.uptimeMillis() - startTime) > timeout) {
- log(String.format("waitForWifiAPState timeout: expected=%d, actual=%d",
+ logv(String.format("waitForWifiAPState timeout: expected=%d, actual=%d",
expectedState, state));
return false;
}
- log(String.format("waitForWifiAPState interim: expected=%d, actual=%d",
+ logv(String.format("waitForWifiAPState interim: expected=%d, actual=%d",
expectedState, state));
SystemClock.sleep(SHORT_TIMEOUT);
}
@@ -269,7 +261,7 @@
// Turn screen off
protected void turnScreenOff() {
- log("Turn screen off");
+ logv("Turn screen off");
PowerManager pm =
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());
@@ -277,7 +269,7 @@
// Turn screen on
protected void turnScreenOn() {
- log("Turn screen on");
+ logv("Turn screen on");
PowerManager pm =
(PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
pm.wakeUp(SystemClock.uptimeMillis());
@@ -305,7 +297,7 @@
// assume the chance that all servers are down is very small
for (int i = 0; i < hostList.length; i++ ) {
String host = hostList[i];
- log("Start ping test, ping " + host);
+ logv("Start ping test, ping " + host);
Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
int status = p.waitFor();
if (status == 0) {
@@ -314,11 +306,11 @@
}
}
} catch (UnknownHostException e) {
- log("Ping test Fail: Unknown Host");
+ logv("Ping test Fail: Unknown Host");
} catch (IOException e) {
- log("Ping test Fail: IOException");
+ logv("Ping test Fail: IOException");
} catch (InterruptedException e) {
- log("Ping test Fail: InterruptedException");
+ logv("Ping test Fail: InterruptedException");
}
}
// ping test timeout
@@ -331,29 +323,22 @@
* We don't verify whether the connection is successful or not, leave this to the test
*/
protected boolean connectToWifi(String knownSSID) {
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = knownSSID;
- config.allowedKeyManagement.set(KeyMgmt.NONE);
+ WifiConfiguration config = WifiConfigurationHelper.createOpenConfig(knownSSID);
return connectToWifiWithConfiguration(config);
}
/**
* Connect to Wi-Fi with the given configuration. Note the SSID in the configuration
* is pure string, we need to convert it to quoted string.
- * @param config
- * @return
*/
protected boolean connectToWifiWithConfiguration(WifiConfiguration config) {
- String ssid = config.SSID;
- config.SSID = convertToQuotedString(ssid);
-
// If Wifi is not enabled, enable it
if (!mWifiManager.isWifiEnabled()) {
- log("Wifi is not enabled, enable it");
+ logv("Wifi is not enabled, enable it");
mWifiManager.setWifiEnabled(true);
// wait for the wifi state change before start scanning.
if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT)) {
- log("wait for WIFI_STATE_ENABLED failed");
+ logv("wait for WIFI_STATE_ENABLED failed");
return false;
}
}
@@ -361,10 +346,13 @@
// Save network configuration and connect to network without scanning
mWifiManager.connect(config,
new WifiManager.ActionListener() {
+ @Override
public void onSuccess() {
}
+
+ @Override
public void onFailure(int reason) {
- log("connect failure " + reason);
+ logv("connect failure " + reason);
}
});
return true;
@@ -376,25 +364,28 @@
protected boolean disconnectAP() {
// remove saved networks
if (!mWifiManager.isWifiEnabled()) {
- log("Enabled wifi before remove configured networks");
+ logv("Enabled wifi before remove configured networks");
mWifiManager.setWifiEnabled(true);
SystemClock.sleep(SHORT_TIMEOUT);
}
List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
if (wifiConfigList == null) {
- log("no configuration list is null");
+ logv("no configuration list is null");
return true;
}
- log("size of wifiConfigList: " + wifiConfigList.size());
+ logv("size of wifiConfigList: " + wifiConfigList.size());
for (WifiConfiguration wifiConfig: wifiConfigList) {
- log("remove wifi configuration: " + wifiConfig.networkId);
+ logv("remove wifi configuration: " + wifiConfig.networkId);
int netId = wifiConfig.networkId;
mWifiManager.forget(netId, new WifiManager.ActionListener() {
+ @Override
public void onSuccess() {
}
+
+ @Override
public void onFailure(int reason) {
- log("Failed to forget " + reason);
+ logv("Failed to forget " + reason);
}
});
}
@@ -431,15 +422,14 @@
long startTime = SystemClock.uptimeMillis();
while (true) {
NetworkInfo ni = mCm.getActiveNetworkInfo();
- String niString = ni == null ? "null" : ni.toString();
if (ni != null && ni.isConnected()) {
return true;
}
if ((SystemClock.uptimeMillis() - startTime) > timeout) {
- log("waitForActiveNetworkConnection timeout: " + niString);
+ logv("waitForActiveNetworkConnection timeout: %s", ni);
return false;
}
- log("waitForActiveNetworkConnection interim: " + niString);
+ logv("waitForActiveNetworkConnection interim: %s", ni);
SystemClock.sleep(SHORT_TIMEOUT);
}
}
@@ -451,12 +441,11 @@
if (ni == null) {
return true;
}
- String niString = ni.toString();
if ((SystemClock.uptimeMillis() - startTime) > timeout) {
- log("waitForActiveNetworkConnection timeout: " + niString);
+ logv("waitForActiveNetworkConnection timeout: %s", ni);
return false;
}
- log("waitForActiveNetworkConnection interim: " + niString);
+ logv("waitForActiveNetworkConnection interim: %s", ni);
SystemClock.sleep(SHORT_TIMEOUT);
}
}
@@ -467,12 +456,9 @@
try {
Process proc = Runtime.getRuntime().exec(new String[]{
"/system/bin/ping", "-W", "30", "-c", "1", PING_IP_ADDR});
- int exitCode = proc.waitFor();
- return exitCode == 0;
- } catch (InterruptedException ie) {
- Log.e(LOG_TAG, "InterruptedException while waiting for ping");
- } catch (IOException ioe) {
- Log.e(LOG_TAG, "IOException during ping", ioe);
+ return proc.waitFor() == 0;
+ } catch (InterruptedException | IOException e) {
+ Log.e(mLogTag, "Ping failed", e);
}
return false;
}
@@ -489,8 +475,8 @@
super.tearDown();
}
- private void log(String message) {
- Log.v(LOG_TAG, message);
+ protected void logv(String format, Object... args) {
+ Log.v(mLogTag, String.format(format, args));
}
/**
@@ -506,22 +492,10 @@
// step 2: verify Wifi state and network state;
assertTrue("wifi state not connected with " + config.SSID,
waitForNetworkState(ConnectivityManager.TYPE_WIFI,
- State.CONNECTED, LONG_TIMEOUT));
+ State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// step 3: verify the current connected network is the given SSID
assertNotNull("no active wifi info", mWifiManager.getConnectionInfo());
assertEquals("SSID mismatch", config.SSID, mWifiManager.getConnectionInfo().getSSID());
}
-
- /**
- * checks if the input is a hexadecimal string of given length
- *
- * @param input string to be checked
- * @param length required length of the string
- * @return
- */
- protected static boolean isHex(String input, int length) {
- Pattern p = Pattern.compile(String.format("[0-9A-Fa-f]{%d}", length));
- return p.matcher(input).matches();
- }
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java
new file mode 100644
index 0000000..f0a8367
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/WifiConfigurationHelper.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.connectivitymanagertest;
+
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkAddress;
+import android.net.StaticIpConfiguration;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiEnterpriseConfig;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper for dealing with creating {@link WifiConfiguration} objects.
+ */
+public class WifiConfigurationHelper {
+ private static final int NONE = 0;
+ private static final int WEP = 1;
+ private static final int PSK = 2;
+ private static final int EAP = 3;
+
+ /**
+ * Private constructor since this a static class.
+ */
+ private WifiConfigurationHelper() {}
+
+ /**
+ * Create a {@link WifiConfiguration} for an open network
+ *
+ * @param ssid The SSID of the wifi network
+ * @return The {@link WifiConfiguration}
+ */
+ public static WifiConfiguration createOpenConfig(String ssid) {
+ WifiConfiguration config = createGenericConfig(ssid);
+
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ return config;
+ }
+
+ /**
+ * Create a {@link WifiConfiguration} for a WEP secured network
+ *
+ * @param ssid The SSID of the wifi network
+ * @param password Either a 10, 26, or 58 character hex string or the plain text password
+ * @return The {@link WifiConfiguration}
+ */
+ public static WifiConfiguration createWepConfig(String ssid, String password) {
+ WifiConfiguration config = createGenericConfig(ssid);
+
+ if (isHex(password, 10) || isHex(password, 26) || isHex(password, 58)) {
+ config.wepKeys[0] = password;
+ } else {
+ config.wepKeys[0] = quotedString(password);
+ }
+
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+ config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+ return config;
+ }
+
+ /**
+ * Create a {@link WifiConfiguration} for a PSK secured network
+ *
+ * @param ssid The SSID of the wifi network
+ * @param password Either a 64 character hex string or the plain text password
+ * @return The {@link WifiConfiguration}
+ */
+ public static WifiConfiguration createPskConfig(String ssid, String password) {
+ WifiConfiguration config = createGenericConfig(ssid);
+
+ if (isHex(password, 64)) {
+ config.preSharedKey = password;
+ } else {
+ config.preSharedKey = quotedString(password);
+ }
+ config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ return config;
+ }
+
+ /**
+ * Create a {@link WifiConfiguration} for an EAP secured network
+ *
+ * @param ssid The SSID of the wifi network
+ * @param password The password
+ * @param eapMethod The EAP method
+ * @param phase2 The phase 2 method or null
+ * @param identity The identity or null
+ * @param anonymousIdentity The anonymous identity or null
+ * @param caCert The CA certificate or null
+ * @param clientCert The client certificate or null
+ * @return The {@link WifiConfiguration}
+ */
+ public static WifiConfiguration createEapConfig(String ssid, String password, int eapMethod,
+ Integer phase2, String identity, String anonymousIdentity, String caCert,
+ String clientCert) {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = quotedString(ssid);
+
+ config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+
+ // Set defaults
+ if (phase2 == null) phase2 = WifiEnterpriseConfig.Phase2.NONE;
+ if (identity == null) identity = "";
+ if (anonymousIdentity == null) anonymousIdentity = "";
+ if (caCert == null) caCert = "";
+ if (clientCert == null) clientCert = "";
+
+ config.enterpriseConfig.setPassword(password);
+ config.enterpriseConfig.setEapMethod(eapMethod);
+ config.enterpriseConfig.setPhase2Method(phase2);
+ config.enterpriseConfig.setIdentity(identity);
+ config.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
+ config.enterpriseConfig.setCaCertificateAlias(caCert);
+ config.enterpriseConfig.setClientCertificateAlias(clientCert);
+ return config;
+ }
+
+ /**
+ * Create a generic {@link WifiConfiguration} used by the other create methods.
+ */
+ private static WifiConfiguration createGenericConfig(String ssid) {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = quotedString(ssid);
+ config.setIpAssignment(IpAssignment.DHCP);
+ config.setProxySettings(ProxySettings.NONE);
+ return config;
+ }
+
+ /**
+ * Parse a JSON string for WiFi configurations stored as a JSON string.
+ * <p>
+ * This json string should be a list of dictionaries, with each dictionary containing a single
+ * wifi configuration. The wifi configuration requires the fields "ssid" and "security" with
+ * security being one of NONE, WEP, PSK, or EAP. If WEP, PSK, or EAP are selected, the field
+ * "password" must also be provided. If EAP is selected, then the fiels "eap", "phase2",
+ * "identity", "ananymous_identity", "ca_cert", and "client_cert" are also required. Lastly,
+ * static IP settings are also supported. If the field "ip" is set, then the fields "gateway",
+ * "prefix_length", "dns1", and "dns2" are required.
+ * </p>
+ * @throws IllegalArgumentException if the input string was not valid JSON or if any mandatory
+ * fields are missing.
+ */
+ public static List<WifiConfiguration> parseJson(String in) {
+ try {
+ JSONArray jsonConfigs = new JSONArray(in);
+ List<WifiConfiguration> wifiConfigs = new ArrayList<>(jsonConfigs.length());
+
+ for (int i = 0; i < jsonConfigs.length(); i++) {
+ JSONObject jsonConfig = jsonConfigs.getJSONObject(i);
+
+ wifiConfigs.add(getWifiConfiguration(jsonConfig));
+ }
+ return wifiConfigs;
+ } catch (JSONException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Parse a {@link JSONObject} and return the wifi configuration.
+ *
+ * @throws IllegalArgumentException if any mandatory fields are missing.
+ */
+ private static WifiConfiguration getWifiConfiguration(JSONObject jsonConfig)
+ throws JSONException {
+ String ssid = jsonConfig.getString("ssid");
+ String password = null;
+ WifiConfiguration config;
+
+ int securityType = getSecurityType(jsonConfig.getString("security"));
+ switch (securityType) {
+ case NONE:
+ config = createOpenConfig(ssid);
+ break;
+ case WEP:
+ password = jsonConfig.getString("password");
+ config = createWepConfig(ssid, password);
+ break;
+ case PSK:
+ password = jsonConfig.getString("password");
+ config = createPskConfig(ssid, password);
+ break;
+ case EAP:
+ password = jsonConfig.getString("password");
+ int eapMethod = getEapMethod(jsonConfig.getString("eap"));
+ Integer phase2 = null;
+ if (jsonConfig.has("phase2")) {
+ phase2 = getPhase2(jsonConfig.getString("phase2"));
+ }
+ String identity = null;
+ if (jsonConfig.has("identity")) {
+ identity = jsonConfig.getString("identity");
+ }
+ String anonymousIdentity = null;
+ if (jsonConfig.has("anonymous_identity")) {
+ anonymousIdentity = jsonConfig.getString("anonymous_identity");
+ }
+ String caCert = null;
+ if (jsonConfig.has("ca_cert")) {
+ caCert = (jsonConfig.getString("ca_cert"));
+ }
+ String clientCert = null;
+ if (jsonConfig.has("client_cert")) {
+ clientCert = jsonConfig.getString("client_cert");
+ }
+ config = createEapConfig(ssid, password, eapMethod, phase2, identity,
+ anonymousIdentity, caCert, clientCert);
+ break;
+ default:
+ // Should never reach here as getSecurityType will already throw an exception
+ throw new IllegalArgumentException();
+ }
+
+ if (jsonConfig.has("ip")) {
+ StaticIpConfiguration staticIpConfig = new StaticIpConfiguration();
+
+ InetAddress ipAddress = getInetAddress(jsonConfig.getString("ip"));
+ int prefixLength = getPrefixLength(jsonConfig.getInt("prefix_length"));
+ staticIpConfig.ipAddress = new LinkAddress(ipAddress, prefixLength);
+ staticIpConfig.gateway = getInetAddress(jsonConfig.getString("gateway"));
+ staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns1")));
+ staticIpConfig.dnsServers.add(getInetAddress(jsonConfig.getString("dns2")));
+
+ config.setIpAssignment(IpAssignment.STATIC);
+ config.setStaticIpConfiguration(staticIpConfig);
+ } else {
+ config.setIpAssignment(IpAssignment.DHCP);
+ }
+
+ config.setProxySettings(ProxySettings.NONE);
+ return config;
+ }
+
+ private static String quotedString(String s) {
+ return String.format("\"%s\"", s);
+ }
+
+ /**
+ * Get the security type from a string.
+ *
+ * @throws IllegalArgumentException if the string is not a supported security type.
+ */
+ private static int getSecurityType(String security) {
+ if ("NONE".equalsIgnoreCase(security)) {
+ return NONE;
+ }
+ if ("WEP".equalsIgnoreCase(security)) {
+ return WEP;
+ }
+ if ("PSK".equalsIgnoreCase(security)) {
+ return PSK;
+ }
+ if ("EAP".equalsIgnoreCase(security)) {
+ return EAP;
+ }
+ throw new IllegalArgumentException("Security type must be one of NONE, WEP, PSK, or EAP");
+ }
+
+ /**
+ * Get the EAP method from a string.
+ *
+ * @throws IllegalArgumentException if the string is not a supported EAP method.
+ */
+ private static int getEapMethod(String eapMethod) {
+ if ("TLS".equalsIgnoreCase(eapMethod)) {
+ return WifiEnterpriseConfig.Eap.TLS;
+ }
+ if ("TTLS".equalsIgnoreCase(eapMethod)) {
+ return WifiEnterpriseConfig.Eap.TTLS;
+ }
+ if ("PEAP".equalsIgnoreCase(eapMethod)) {
+ return WifiEnterpriseConfig.Eap.PEAP;
+ }
+ throw new IllegalArgumentException("EAP method must be one of TLS, TTLS, or PEAP");
+ }
+
+ /**
+ * Get the phase 2 method from a string.
+ *
+ * @throws IllegalArgumentException if the string is not a supported phase 2 method.
+ */
+ private static int getPhase2(String phase2) {
+ if ("PAP".equalsIgnoreCase(phase2)) {
+ return WifiEnterpriseConfig.Phase2.PAP;
+ }
+ if ("MSCHAP".equalsIgnoreCase(phase2)) {
+ return WifiEnterpriseConfig.Phase2.MSCHAP;
+ }
+ if ("MSCHAPV2".equalsIgnoreCase(phase2)) {
+ return WifiEnterpriseConfig.Phase2.MSCHAPV2;
+ }
+ if ("GTC".equalsIgnoreCase(phase2)) {
+ return WifiEnterpriseConfig.Phase2.GTC;
+ }
+ throw new IllegalArgumentException("Phase2 must be one of PAP, MSCHAP, MSCHAPV2, or GTC");
+ }
+
+ /**
+ * Get an {@link InetAddress} from a string
+ *
+ * @throws IllegalArgumentException if the string is not a valid IP address.
+ */
+ private static InetAddress getInetAddress(String ipAddress) {
+ if (!InetAddress.isNumeric(ipAddress)) {
+ throw new IllegalArgumentException(
+ String.format("IP address %s is not numeric", ipAddress));
+ }
+
+ try {
+ return InetAddress.getByName(ipAddress);
+ } catch (UnknownHostException e) {
+ throw new IllegalArgumentException(
+ String.format("IP address %s could not be resolved", ipAddress));
+ }
+ }
+
+ /**
+ * Get the prefix length from an int.
+ *
+ * @throws IllegalArgumentException if the prefix length is less than 0 or greater than 32.
+ */
+ private static int getPrefixLength(int prefixLength) {
+ if (prefixLength < 0 || prefixLength > 32) {
+ throw new IllegalArgumentException("Prefix length cannot be less than 0 or more than 32");
+ }
+ return prefixLength;
+ }
+
+ /**
+ * Utility method to check if a given string is a hexadecimal string of given length
+ */
+ public static boolean isHex(String input, int length) {
+ if (input == null || length < 0) {
+ return false;
+ }
+ return input.matches(String.format("[0-9A-Fa-f]{%d}", length));
+ }
+}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index 01995c7..b280106 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -23,14 +23,15 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
-public class ConnectivityManagerMobileTest extends
- ConnectivityManagerTestBase {
- private static final String TAG = "ConnectivityManagerMobileTest";
+public class ConnectivityManagerMobileTest extends ConnectivityManagerTestBase {
+
+ public ConnectivityManagerMobileTest() {
+ super(ConnectivityManagerMobileTest.class.getSimpleName());
+ }
private String mTestAccessPoint;
private boolean mWifiOnlyFlag;
@@ -46,7 +47,7 @@
// Each test case will start with cellular connection
if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON) == 1) {
- log("airplane is not disabled, disable it.");
+ logv("airplane is not disabled, disable it.");
mCm.setAirplaneMode(false);
}
@@ -77,16 +78,14 @@
assertTrue("not connected to cellular network", extraNetInfo.isConnected());
}
- private void log(String message) {
- Log.v(TAG, message);
- }
+
// Test case 1: Test enabling Wifi without associating with any AP, no broadcast on network
// event should be expected.
@LargeTest
public void test3GToWifiNotification() {
if (mWifiOnlyFlag) {
- Log.v(TAG, getName() + " is excluded for wifi-only test");
+ logv(getName() + " is excluded for wifi-only test");
return;
}
@@ -225,7 +224,7 @@
@LargeTest
public void testDataConnectionWith3GToAmTo3G() {
if (mWifiOnlyFlag) {
- Log.v(TAG, getName() + " is excluded for wifi-only test");
+ logv(getName() + " is excluded for wifi-only test");
return;
}
// disable wifi
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
index eb75b0d..c2b80dc 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiAssociationTest.java
@@ -21,16 +21,15 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
import android.net.wifi.WifiConfiguration.GroupCipher;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.PairwiseCipher;
import android.net.wifi.WifiConfiguration.Protocol;
import android.net.wifi.WifiInfo;
import android.os.Bundle;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import com.android.connectivitymanagertest.WifiAssociationTestRunner;
+import com.android.connectivitymanagertest.WifiConfigurationHelper;
/**
* Test Wi-Fi connection with different configuration
@@ -40,7 +39,6 @@
* -w com.android.connectivitymanagertest/.WifiAssociationTestRunner"
*/
public class WifiAssociationTest extends ConnectivityManagerTestBase {
- private static final String TAG = "WifiAssociationTest";
private String mSsid = null;
private String mPassword = null;
private String mSecurityType = null;
@@ -51,6 +49,10 @@
OPEN, WEP64, WEP128, WPA_TKIP, WPA2_AES
}
+ public WifiAssociationTest() {
+ super(WifiAssociationTest.class.getSimpleName());
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -77,90 +79,58 @@
private void validateFrequencyBand() {
if (mFrequencyBand != null) {
int currentFreq = mWifiManager.getFrequencyBand();
- Log.v(TAG, "read frequency band: " + currentFreq);
+ logv("read frequency band: " + currentFreq);
assertEquals("specified frequency band does not match operational band of WifiManager",
currentFreq, mBand);
}
}
- private void log(String message) {
- Log.v(TAG, message);
- }
-
@LargeTest
public void testWifiAssociation() {
assertNotNull("no test ssid", mSsid);
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = mSsid;
+ WifiConfiguration config = null;
SECURITY_TYPE security = SECURITY_TYPE.valueOf(mSecurityType);
- log("Security type is " + security.toString());
+ logv("Security type is " + security.toString());
switch (security) {
// set network configurations
case OPEN:
- config.allowedKeyManagement.set(KeyMgmt.NONE);
+ config = WifiConfigurationHelper.createOpenConfig(mSsid);
break;
case WEP64:
assertNotNull("password is empty", mPassword);
- config.allowedKeyManagement.set(KeyMgmt.NONE);
- config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
- config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+ // always use hex pair for WEP-40
+ assertTrue(WifiConfigurationHelper.isHex(mPassword, 10));
+ config = WifiConfigurationHelper.createWepConfig(mSsid, mPassword);
config.allowedGroupCiphers.set(GroupCipher.WEP40);
- if (mPassword != null) {
- // always use hex pair for WEP-40
- if (isHex(mPassword, 10)) {
- config.wepKeys[0] = mPassword;
- } else {
- fail("password should be 10-character hex");
- }
- }
break;
case WEP128:
assertNotNull("password is empty", mPassword);
- config.allowedKeyManagement.set(KeyMgmt.NONE);
- config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
- config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+ // always use hex pair for WEP-104
+ assertTrue(WifiConfigurationHelper.isHex(mPassword, 26));
+ config = WifiConfigurationHelper.createWepConfig(mSsid, mPassword);
config.allowedGroupCiphers.set(GroupCipher.WEP104);
- if (mPassword != null) {
- // always use hex pair for WEP-104
- if (isHex(mPassword, 26)) {
- config.wepKeys[0] = mPassword;
- } else {
- fail("password should be 26-character hex");
- }
- }
break;
case WPA_TKIP:
assertNotNull("password is empty", mPassword);
- config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword);
config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
config.allowedProtocols.set(Protocol.WPA);
config.allowedPairwiseCiphers.set(PairwiseCipher.TKIP);
config.allowedGroupCiphers.set(GroupCipher.TKIP);
- if (isHex(mPassword, 64)) {
- config.preSharedKey = mPassword;
- } else {
- config.preSharedKey = '"' + mPassword + '"';
- }
break;
case WPA2_AES:
assertNotNull("password is empty", mPassword);
- config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword);
config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
config.allowedProtocols.set(Protocol.RSN);
config.allowedPairwiseCiphers.set(PairwiseCipher.CCMP);
config.allowedGroupCiphers.set(GroupCipher.CCMP);
- config.allowedProtocols.set(Protocol.RSN);
- if (isHex(mPassword, 64)) {
- config.preSharedKey = mPassword;
- } else {
- config.preSharedKey = '"' + mPassword + '"';
- }
break;
default:
fail("Not a valid security type: " + mSecurityType);
break;
}
- Log.v(TAG, "network config: " + config.toString());
+ logv("network config: %s", config.toString());
connectToWifi(config);
// verify that connection actually works
assertTrue("no network connectivity at end of test", checkNetworkConnectivity());
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index 740ffb8..b37daa3 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -16,54 +16,38 @@
package com.android.connectivitymanagertest.functional;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo.State;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
+import android.os.SystemClock;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
+import com.android.connectivitymanagertest.WifiConfigurationHelper;
-import java.util.ArrayList;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
import java.util.List;
/**
* Test Wi-Fi connection with different configuration
* To run this tests:
- * adb shell am instrument -e class
- * com.android.connectivitymanagertest.functional.WifiConnectionTest
- * -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
+ * adb shell am instrument \
+ * -e class com.android.connectivitymanagertest.functional.WifiConnectionTest \
+ * -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner
*/
-public class WifiConnectionTest
- extends ConnectivityManagerTestBase {
- private static final String TAG = "WifiConnectionTest";
- private static final boolean DEBUG = false;
- private List<WifiConfiguration> mNetworks = new ArrayList<WifiConfiguration>();
+public class WifiConnectionTest extends ConnectivityManagerTestBase {
+ private static final String WIFI_CONFIG_FILE = "/data/wifi_configs.json";
+ private static final long PAUSE_DURATION_MS = 60 * 1000;
+
+ public WifiConnectionTest() {
+ super(WifiConnectionTest.class.getSimpleName());
+ }
@Override
public void setUp() throws Exception {
super.setUp();
- mNetworks = loadNetworkConfigurations();
- if (DEBUG) {
- printNetworkConfigurations();
- }
-
- // enable wifi and verify wpa_supplicant is started
- assertTrue("enable Wifi failed", enableWifi());
- assertTrue("wifi not connected", waitForNetworkState(
- ConnectivityManager.TYPE_WIFI, State.CONNECTED, LONG_TIMEOUT));
- WifiInfo wi = mWifiManager.getConnectionInfo();
- assertNotNull("no active wifi info", wi);
- assertTrue("failed to ping wpa_supplicant ", mWifiManager.pingSupplicant());
- }
-
- private void printNetworkConfigurations() {
- log("==== print network configurations parsed from XML file ====");
- log("number of access points: " + mNetworks.size());
- for (WifiConfiguration config : mNetworks) {
- log(config.toString());
- }
+ assertTrue("Failed to enable wifi", enableWifi());
}
@Override
@@ -72,25 +56,67 @@
super.tearDown();
}
- private void log(String message) {
- Log.v(TAG, message);
- }
-
@LargeTest
public void testWifiConnections() {
- for (int i = 0; i < mNetworks.size(); i++) {
- String ssid = mNetworks.get(i).SSID;
- log("-- START Wi-Fi connection test to : " + ssid + " --");
- connectToWifi(mNetworks.get(i));
- // verify that connection actually works
- assertTrue("no network connectivity at end of test", checkNetworkConnectivity());
- log("-- END Wi-Fi connection test to " + ssid + " -- ");
- log("pausing for 1 minute");
- try {
- Thread.sleep(60 * 1000);
- } catch (InterruptedException e) {
- // ignore
+ List<WifiConfiguration> wifiConfigs = loadConfigurations();
+
+ printWifiConfigurations(wifiConfigs);
+
+ assertFalse("No configurations to test against", wifiConfigs.isEmpty());
+
+ boolean shouldPause = false;
+ for (WifiConfiguration config : wifiConfigs) {
+ if (shouldPause) {
+ logv("Pausing for %d seconds", PAUSE_DURATION_MS / 1000);
+ SystemClock.sleep(PAUSE_DURATION_MS);
}
+ logv("Start wifi connection test to: %s", config.SSID);
+ connectToWifi(config);
+
+ // verify that connection actually works
+ assertTrue("No connectivity at end of test", checkNetworkConnectivity());
+
+ // Disconnect and remove the network
+ assertTrue("Unable to remove network", disconnectAP());
+ logv("End wifi connection test to: %s", config.SSID);
+
+ shouldPause = true;
+ }
+ }
+
+ /**
+ * Load the configuration file from the root of the data partition
+ */
+ private List<WifiConfiguration> loadConfigurations() {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(new File(WIFI_CONFIG_FILE)));
+ StringBuffer jsonBuffer = new StringBuffer();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ jsonBuffer.append(line);
+ }
+ return WifiConfigurationHelper.parseJson(jsonBuffer.toString());
+ } catch (IllegalArgumentException | IOException e) {
+ throw new AssertionError("Error parsing file", e);
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Print the wifi configurations to test against.
+ */
+ private void printWifiConfigurations(List<WifiConfiguration> wifiConfigs) {
+ logv("Wifi configurations to be tested");
+ for (WifiConfiguration config : wifiConfigs) {
+ logv(config.toString());
}
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index aead65b..41f01e6 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -17,16 +17,15 @@
package com.android.connectivitymanagertest.stress;
-import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
-
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
+
+import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
+import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
import java.io.BufferedWriter;
import java.io.File;
@@ -35,9 +34,7 @@
/**
* Stress test setting up device as wifi hotspot
*/
-public class WifiApStress
- extends ConnectivityManagerTestBase {
- private final static String TAG = "WifiApStress";
+public class WifiApStress extends ConnectivityManagerTestBase {
private static String NETWORK_ID = "AndroidAPTest";
private static String PASSWD = "androidwifi";
private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
@@ -46,6 +43,10 @@
private int mLastIteration = 0;
private boolean mWifiOnlyFlag;
+ public WifiApStress() {
+ super(WifiApStress.class.getSimpleName());
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -71,7 +72,7 @@
@LargeTest
public void testWifiHotSpot() {
if (mWifiOnlyFlag) {
- Log.v(TAG, this.getName() + " is excluded for wi-fi only test");
+ logv(getName() + " is excluded for wi-fi only test");
return;
}
WifiConfiguration config = new WifiConfiguration();
@@ -95,7 +96,7 @@
}
int i;
for (i = 0; i < mTotalIterations; i++) {
- Log.v(TAG, "iteration: " + i);
+ logv("iteration: " + i);
mLastIteration = i;
// enable Wifi tethering
assertTrue("failed to enable wifi hotspot",
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 6ef4f06..fbd4669 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -19,13 +19,10 @@
import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
-import android.net.IpConfiguration.IpAssignment;
-import android.net.IpConfiguration.ProxySettings;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Environment;
@@ -37,6 +34,7 @@
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
import com.android.connectivitymanagertest.ConnectivityManagerTestBase;
+import com.android.connectivitymanagertest.WifiConfigurationHelper;
import java.io.BufferedWriter;
import java.io.File;
@@ -52,8 +50,6 @@
* -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner
*/
public class WifiStressTest extends ConnectivityManagerTestBase {
- private final static String TAG = "WifiStressTest";
-
private final static long SCREEN_OFF_TIMER = 500; //500ms
/**
* Wi-Fi idle time for default sleep policy
@@ -78,6 +74,10 @@
private BufferedWriter mOutputWriter = null;
private boolean mWifiOnlyFlag;
+ public WifiStressTest() {
+ super(WifiStressTest.class.getSimpleName());
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -89,14 +89,14 @@
mScanIterations = mRunner.getScanIterations();
mWifiSleepTime = mRunner.getSleepTime();
mWifiOnlyFlag = mRunner.isWifiOnly();
- log(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s),"
+ logv(String.format("mReconnectIterations(%d), mSsid(%s), mPassword(%s),"
+ "mScanIterations(%d), mWifiSleepTime(%d)", mReconnectIterations, mSsid,
mPassword, mScanIterations, mWifiSleepTime));
mOutputWriter = new BufferedWriter(new FileWriter(new File(
Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
turnScreenOn();
if (!mWifiManager.isWifiEnabled()) {
- log("Enable wi-fi before stress tests.");
+ logv("Enable wi-fi before stress tests.");
if (!enableWifi()) {
tearDown();
fail("enable wifi failed.");
@@ -107,7 +107,7 @@
@Override
protected void tearDown() throws Exception {
- log("tearDown()");
+ logv("tearDown()");
if (mOutputWriter != null) {
mOutputWriter.close();
}
@@ -115,23 +115,19 @@
}
private void writeOutput(String s) {
- log("write message: " + s);
+ logv("write message: " + s);
if (mOutputWriter == null) {
- log("no writer attached to file " + OUTPUT_FILE);
+ logv("no writer attached to file " + OUTPUT_FILE);
return;
}
try {
mOutputWriter.write(s + "\n");
mOutputWriter.flush();
} catch (IOException e) {
- log("failed to write output.");
+ logv("failed to write output.");
}
}
- public void log(String message) {
- Log.v(TAG, message);
- }
-
private void sleep(long sometime, String errorMsg) {
try {
Thread.sleep(sometime);
@@ -149,7 +145,7 @@
long scanTimeSum = 0, i, averageScanTime = -1;
int ssidAppearInScanResultsCount = 0; // count times of given ssid appear in scan results.
for (i = 1; i <= mScanIterations; i++) {
- log("testWifiScanning: iteration: " + i);
+ logv("testWifiScanning: iteration: " + i);
averageScanTime = scanTimeSum / i;
writeOutput(String.format("iteration %d out of %d", i, mScanIterations));
writeOutput(String.format("average scanning time is %d", averageScanTime));
@@ -173,9 +169,9 @@
if (scanResultLocal == null || scanResultLocal.isEmpty()) {
fail("Scan results are empty ");
}
- log("size of scan result list: " + scanResultLocal.size());
+ logv("size of scan result list: " + scanResultLocal.size());
for (ScanResult sr : scanResultLocal) {
- log(String.format("scan result: " + sr.toString()));
+ logv(String.format("scan result: " + sr.toString()));
if (mSsid.equals(sr.SSID)) {
ssidAppearInScanResultsCount += 1;
break;
@@ -208,21 +204,12 @@
Settings.Global.putLong(mRunner.getContext().getContentResolver(),
Settings.Global.WIFI_IDLE_MS, WIFI_IDLE_MS);
- // Connect to a Wi-Fi network
- WifiConfiguration config = new WifiConfiguration();
- config.SSID = mSsid;
- if (mPassword != null) {
- config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
- if (isHex(mPassword, 64)) {
- config.preSharedKey = mPassword;
- } else {
- config.preSharedKey = '"' + mPassword + '"';
- }
+ WifiConfiguration config;
+ if (mPassword == null) {
+ config = WifiConfigurationHelper.createOpenConfig(mSsid);
} else {
- config.allowedKeyManagement.set(KeyMgmt.NONE);
+ config = WifiConfigurationHelper.createPskConfig(mSsid, mPassword);
}
- config.setIpAssignment(IpAssignment.DHCP);
- config.setProxySettings(ProxySettings.NONE);
assertTrue("Failed to connect to Wi-Fi network: " + mSsid,
connectToWifiWithConfiguration(config));
@@ -240,7 +227,7 @@
// 5. Wake up the device, verify Wi-Fi is enabled and connected.
writeOutput(String.format("iteration %d out of %d",
i, mReconnectIterations));
- log("iteration: " + i);
+ logv("iteration: " + i);
turnScreenOff();
// Use clock time since boot for intervals.
long start = SystemClock.uptimeMillis();
@@ -271,7 +258,7 @@
if (mWifiOnlyFlag) {
NetworkInfo ni = mCm.getActiveNetworkInfo();
if (ni != null) {
- Log.e(TAG, "has active network while in wifi sleep: " + ni.toString());
+ Log.e(mLogTag, "has active network while in wifi sleep: " + ni.toString());
fail("active network detected");
}
} else {
@@ -292,7 +279,7 @@
long connectionTime = SystemClock.uptimeMillis() - startTime;
sum += connectionTime;
avgReconnectTime = sum / i;
- log("average reconnection time is: " + avgReconnectTime);
+ logv("average reconnection time is: " + avgReconnectTime);
assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null));
}
diff --git a/docs/html/guide/topics/ui/accessibility/services.jd b/docs/html/guide/topics/ui/accessibility/services.jd
index c868080..d69af9f 100644
--- a/docs/html/guide/topics/ui/accessibility/services.jd
+++ b/docs/html/guide/topics/ui/accessibility/services.jd
@@ -71,24 +71,30 @@
<h3 id="service-declaration">Accessibility service declaration</h3>
-<p>In order to be treated as an accessibility service, your application must include the
+<p>In order to be treated as an accessibility service, you must include a
{@code service} element (rather than the {@code activity} element) within the {@code application}
-element in its manifest. In addition, within the {@code service} element, you must also include an
+element in your manifest. In addition, within the {@code service} element, you must also include an
accessibility service intent filter. For compatiblity with Android 4.1 and higher, the manifest
must also request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission
as shown in the following sample:</p>
<pre>
-<application>
- <service android:name=".MyAccessibilityService"
- android:label="@string/accessibility_service_label"
- android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
- <intent-filter>
- <action android:name="android.accessibilityservice.AccessibilityService" />
- </intent-filter>
- </service>
- <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
-</application>
+<manifest>
+ ...
+ <uses-permission ... />
+ ...
+ <application>
+ ...
+ <service android:name=".MyAccessibilityService"
+ android:label="@string/accessibility_service_label"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService" />
+ </intent-filter>
+ </service>
+ <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
+ </application>
+</manifest>
</pre>
<p>These declarations are required for all accessibility services deployed on Android 1.6 (API Level
diff --git a/docs/html/wear/images/partners/sony.png b/docs/html/wear/images/partners/sony.png
new file mode 100644
index 0000000..3e9483e
--- /dev/null
+++ b/docs/html/wear/images/partners/sony.png
Binary files differ
diff --git a/docs/html/wear/index.jd b/docs/html/wear/index.jd
index 5dd7690..c9a5cff 100644
--- a/docs/html/wear/index.jd
+++ b/docs/html/wear/index.jd
@@ -228,6 +228,10 @@
<div class="col-4">
<img src="/wear/images/partners/samsung.png" alt="Samsung">
</div>
+ <div class="col-4">
+ <img src="/wear/images/partners/sony.png" alt="Sony"
+ style="margin-left:57px;margin-top:17px;">
+ </div>
</div>
</div> <!-- end .wrap -->
</div>
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
index 4948a02..6e1402c 100644
--- a/packages/PrintSpooler/Android.mk
+++ b/packages/PrintSpooler/Android.mk
@@ -26,3 +26,5 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview
include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/packages/PrintSpooler/jni/Android.mk b/packages/PrintSpooler/jni/Android.mk
new file mode 100644
index 0000000..fbf56be
--- /dev/null
+++ b/packages/PrintSpooler/jni/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ com_android_printspooler_util_BitmapSerializeUtils.cpp \
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE)
+
+LOCAL_SHARED_LIBRARIES := \
+ libnativehelper
+
+LOCAL_LDLIBS := -lm -llog -ljnigraphics
+
+LOCAL_MODULE := libprintspooler_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
new file mode 100644
index 0000000..57281c8
--- /dev/null
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BitmapSerializeUtils"
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+#include <android/bitmap.h>
+#include <android/log.h>
+
+namespace android {
+
+#define RGBA_8888_COLOR_DEPTH 4
+
+static bool writeAllBytes(const int fd, void* buffer, const size_t byteCount) {
+ char* writeBuffer = static_cast<char*>(buffer);
+ size_t remainingBytes = byteCount;
+ while (remainingBytes > 0) {
+ ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
+ if (writtenByteCount == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+ "Error writing to buffer: %d", errno);
+ return false;
+ }
+ remainingBytes -= writtenByteCount;
+ writeBuffer += writtenByteCount;
+ }
+ return true;
+}
+
+static bool readAllBytes(const int fd, void* buffer, const size_t byteCount) {
+ char* readBuffer = static_cast<char*>(buffer);
+ size_t remainingBytes = byteCount;
+ while (remainingBytes > 0) {
+ ssize_t readByteCount = read(fd, readBuffer, remainingBytes);
+ if (readByteCount == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+ "Error reading from buffer: %d", errno);
+ return false;
+ }
+ remainingBytes -= readByteCount;
+ readBuffer += readByteCount;
+ }
+ return true;
+}
+
+static void throwException(JNIEnv* env, const char* className, const char* message) {
+ jclass exceptionClass = env->FindClass(className);
+ env->ThrowNew(exceptionClass, message);
+}
+
+static void throwIllegalStateException(JNIEnv* env, char *message) {
+ const char* className = "java/lang/IllegalStateException";
+ throwException(env, className, message);
+}
+
+static void throwIllegalArgumentException(JNIEnv* env, char* message) {
+ const char* className = "java/lang/IllegalArgumentException";
+ throwException(env, className, message);
+}
+
+static void readBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) {
+ // Read the info.
+ AndroidBitmapInfo readInfo;
+ bool read = readAllBytes(fd, (void*) &readInfo, sizeof(AndroidBitmapInfo));
+ if (!read) {
+ throwIllegalStateException(env, (char*) "Cannot read bitmap info");
+ return;
+ }
+
+ // Get the info of the target bitmap.
+ AndroidBitmapInfo targetInfo;
+ int result = AndroidBitmap_getInfo(env, jbitmap, &targetInfo);
+ if (result < 0) {
+ throwIllegalStateException(env, (char*) "Cannot get bitmap info");
+ return;
+ }
+
+ // Enforce we can reuse the bitmap.
+ if (readInfo.width != targetInfo.width || readInfo.height != targetInfo.height
+ || readInfo.stride != targetInfo.stride || readInfo.format != targetInfo.format
+ || readInfo.flags != targetInfo.flags) {
+ throwIllegalArgumentException(env, (char*) "Cannot reuse bitmap");
+ return;
+ }
+
+ // Lock the pixels.
+ void* pixels;
+ result = AndroidBitmap_lockPixels(env, jbitmap, &pixels);
+ if (result < 0) {
+ throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels");
+ return;
+ }
+
+ // Read the pixels.
+ size_t byteCount = readInfo.stride * readInfo.height;
+ read = readAllBytes(fd, (void*) pixels, byteCount);
+ if (!read) {
+ throwIllegalStateException(env, (char*) "Cannot read bitmap pixels");
+ return;
+ }
+
+ // Unlock the pixels.
+ result = AndroidBitmap_unlockPixels(env, jbitmap);
+ if (result < 0) {
+ throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels");
+ }
+}
+
+static void writeBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) {
+ // Get the info.
+ AndroidBitmapInfo info;
+ int result = AndroidBitmap_getInfo(env, jbitmap, &info);
+ if (result < 0) {
+ throwIllegalStateException(env, (char*) "Cannot get bitmap info");
+ return;
+ }
+
+ // Write the info.
+ bool written = writeAllBytes(fd, (void*) &info, sizeof(AndroidBitmapInfo));
+ if (!written) {
+ throwIllegalStateException(env, (char*) "Cannot write bitmap info");
+ return;
+ }
+
+ // Lock the pixels.
+ void* pixels;
+ result = AndroidBitmap_lockPixels(env, jbitmap, &pixels);
+ if (result < 0) {
+ throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels");
+ return;
+ }
+
+ // Write the pixels.
+ size_t byteCount = info.stride * info.height;
+ written = writeAllBytes(fd, (void*) pixels, byteCount);
+ if (!written) {
+ throwIllegalStateException(env, (char*) "Cannot write bitmap pixels");
+ return;
+ }
+
+ // Unlock the pixels.
+ result = AndroidBitmap_unlockPixels(env, jbitmap);
+ if (result < 0) {
+ throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels");
+ }
+}
+
+static JNINativeMethod sMethods[] = {
+ {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels},
+ {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels},
+};
+
+int register_com_android_printspooler_util_BitmapSerializeUtils(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "com/android/printspooler/util/BitmapSerializeUtils",
+ sMethods, NELEM(sMethods));
+}
+
+}
+
+jint JNI_OnLoad(JavaVM* jvm, void*) {
+ JNIEnv *env = NULL;
+ if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6)) {
+ return JNI_ERR;
+ }
+
+ if (android::register_com_android_printspooler_util_BitmapSerializeUtils(env) == -1) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+}
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index 761d58a..30b96292 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -33,7 +33,7 @@
<Spinner
android:id="@+id/destination_spinner"
- android:layout_width="wrap_content"
+ android:layout_width="@dimen/preview_destination_spinner_width"
android:layout_height="wrap_content"
android:layout_marginTop="4dip"
android:dropDownWidth="wrap_content"
diff --git a/packages/PrintSpooler/res/values-sw600dp-land/constants.xml b/packages/PrintSpooler/res/values-sw600dp-land/constants.xml
index f60d8e4..f7f8a18 100644
--- a/packages/PrintSpooler/res/values-sw600dp-land/constants.xml
+++ b/packages/PrintSpooler/res/values-sw600dp-land/constants.xml
@@ -17,6 +17,9 @@
<resources>
<integer name="print_option_column_count">6</integer>
+
<integer name="preview_page_per_row_count">4</integer>
+ <dimen name="preview_destination_spinner_width">256dip</dimen>
+
</resources>
diff --git a/packages/PrintSpooler/res/values/constants.xml b/packages/PrintSpooler/res/values/constants.xml
index b4e4777..357d3e1 100644
--- a/packages/PrintSpooler/res/values/constants.xml
+++ b/packages/PrintSpooler/res/values/constants.xml
@@ -45,4 +45,6 @@
<dimen name="preview_page_footer_height">32dip</dimen>
<dimen name="preview_page_min_width">128dip</dimen>
+ <dimen name="preview_destination_spinner_width">192dip</dimen>
+
</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index cd2ccbd..a581e8a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -22,15 +22,15 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Color;
-import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.PrintAttributes;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Margins;
import android.print.PrintDocumentInfo;
import android.util.ArrayMap;
import android.util.Log;
@@ -38,10 +38,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.printspooler.renderer.IPdfRenderer;
import com.android.printspooler.renderer.PdfRendererService;
+import com.android.printspooler.util.BitmapSerializeUtils;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
-import java.io.FileDescriptor;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -354,13 +354,14 @@
public static final class RenderSpec {
final int bitmapWidth;
final int bitmapHeight;
- final PrintAttributes printAttributes;
+ final PrintAttributes printAttributes = new PrintAttributes.Builder().build();
public RenderSpec(int bitmapWidth, int bitmapHeight,
- PrintAttributes printAttributes) {
+ MediaSize mediaSize, Margins minMargins) {
this.bitmapWidth = bitmapWidth;
this.bitmapHeight = bitmapHeight;
- this.printAttributes = printAttributes;
+ printAttributes.setMediaSize(mediaSize);
+ printAttributes.setMinMargins(minMargins);
}
@Override
@@ -451,6 +452,8 @@
@GuardedBy("mLock")
private IPdfRenderer mRenderer;
+ private boolean mBoundToService;
+
public AsyncRenderer(Context context, OnMalformedPdfFileListener malformedPdfFileListener) {
mContext = context;
mOnMalformedPdfFileListener = malformedPdfFileListener;
@@ -463,6 +466,7 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
+ mBoundToService = true;
synchronized (mLock) {
mRenderer = IPdfRenderer.Stub.asInterface(service);
mLock.notifyAll();
@@ -505,6 +509,10 @@
} catch (RemoteException re) {
Log.e(LOG_TAG, "Cannot open PDF document");
return MALFORMED_PDF_FILE_ERROR;
+ } finally {
+ // Close the fd as we passed it to another process
+ // which took ownership.
+ IoUtils.closeQuietly(source);
}
}
}
@@ -559,7 +567,10 @@
@Override
public void onPostExecute(Void result) {
- mContext.unbindService(AsyncRenderer.this);
+ if (mBoundToService) {
+ mBoundToService = false;
+ mContext.unbindService(AsyncRenderer.this);
+ }
mPageContentCache.invalidate();
mPageContentCache.clear();
}
@@ -804,9 +815,7 @@
// ownership, so close our copy for the write to complete.
destination.close();
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inBitmap = bitmap;
- BitmapFactory.decodeFileDescriptor(source.getFileDescriptor(), null, options);
+ BitmapSerializeUtils.readBitmapPixels(bitmap, source);
} catch (IOException|RemoteException e) {
Log.e(LOG_TAG, "Error rendering page:" + mPageIndex, e);
} finally {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index d1aa33b..09e8b39 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -55,7 +55,7 @@
public final class RemotePrintDocument {
private static final String LOG_TAG = "RemotePrintDocument";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final int STATE_INITIAL = 0;
private static final int STATE_STARTED = 1;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
index a4c6932..4d02c01 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
@@ -20,6 +20,7 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.pdf.PdfRenderer;
@@ -32,8 +33,7 @@
import android.util.Log;
import android.view.View;
import libcore.io.IoUtils;
-
-import java.io.FileOutputStream;
+import com.android.printspooler.util.BitmapSerializeUtils;
import java.io.IOException;
/**
@@ -76,7 +76,6 @@
@Override
public void renderPage(int pageIndex, int bitmapWidth, int bitmapHeight,
PrintAttributes attributes, ParcelFileDescriptor destination) {
- FileOutputStream out = null;
synchronized (mLock) {
try {
throwIfNotOpened();
@@ -136,10 +135,8 @@
page.close();
- out = new FileOutputStream(destination.getFileDescriptor());
- bitmap.compress(Bitmap.CompressFormat.PNG, 0, out);
+ BitmapSerializeUtils.writeBitmapPixels(bitmap, destination);
} finally {
- IoUtils.closeQuietly(out);
IoUtils.closeQuietly(destination);
}
}
@@ -171,11 +168,13 @@
private Bitmap getBitmapForSize(int width, int height) {
if (mBitmap != null) {
if (mBitmap.getWidth() == width && mBitmap.getHeight() == height) {
+ mBitmap.eraseColor(Color.WHITE);
return mBitmap;
}
mBitmap.recycle();
}
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ mBitmap.eraseColor(Color.WHITE);
return mBitmap;
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
index ddf637e..2b5b41b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
@@ -24,6 +24,7 @@
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Margins;
import android.print.PrintDocumentInfo;
+import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -51,7 +52,7 @@
private final MyHandler mHandler;
private final PageAdapter mPageAdapter;
- private final StaggeredGridLayoutManager mLayoutManger;
+ private final GridLayoutManager mLayoutManger;
private final PrintOptionsLayout mPrintOptionsLayout;
private final RecyclerView mRecyclerView;
@@ -73,7 +74,7 @@
final int columnCount = mActivity.getResources().getInteger(
R.integer.preview_page_per_row_count);
- mLayoutManger = new StaggeredGridLayoutManager(columnCount, OrientationHelper.VERTICAL);
+ mLayoutManger = new GridLayoutManager(mActivity, columnCount);
mRecyclerView = (RecyclerView) activity.findViewById(R.id.preview_content);
mRecyclerView.setLayoutManager(mLayoutManger);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java
new file mode 100644
index 0000000..a1845f6
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/BitmapSerializeUtils.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.util;
+
+import android.graphics.Bitmap;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Helper for serialization of bitmaps in the very specific
+ * use case of having the same bitmap on both ends and just
+ * marshaling the pixels from one side to the other.
+ */
+public final class BitmapSerializeUtils {
+
+ static {
+ System.loadLibrary("printspooler_jni");
+ }
+
+ private BitmapSerializeUtils() {
+ /* do nothing */
+ }
+
+ /**
+ * Reads a bitmap pixels from a file descriptor.
+ *
+ * @param bitmap A bitmap whose pixels to populate.
+ * @param source The source file descriptor.
+ */
+ public static void readBitmapPixels(Bitmap bitmap, ParcelFileDescriptor source) {
+ nativeReadBitmapPixels(bitmap, source.getFd());
+ }
+
+ /**
+ * Writes a bitmap pixels to a file descriptor.
+ *
+ * @param bitmap The bitmap.
+ * @param destination The destination file descriptor.
+ */
+ public static void writeBitmapPixels(Bitmap bitmap, ParcelFileDescriptor destination) {
+ nativeWriteBitmapPixels(bitmap, destination.getFd());
+ }
+
+ private static native void nativeReadBitmapPixels(Bitmap bitmap, int fd);
+
+ private static native void nativeWriteBitmapPixels(Bitmap bitmap, int fd);
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
index 76ff167..23a01bd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PageContentView.java
@@ -20,7 +20,6 @@
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
-import android.print.PrintAttributes;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Margins;
import android.util.AttributeSet;
@@ -39,14 +38,18 @@
public class PageContentView extends View
implements PageContentRepository.OnPageContentAvailableCallback {
- private final PrintAttributes mAttributes = new PrintAttributes.Builder().build();
-
private final ColorDrawable mEmptyState;
private PageContentProvider mProvider;
+ private MediaSize mMediaSize;
+
+ private Margins mMinMargins;
+
private boolean mContentRequested;
+ private boolean mNeedsLayout;
+
public PageContentView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -68,14 +71,14 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
+ mNeedsLayout = false;
requestPageContentIfNeeded();
}
@Override
public void onPageContentAvailable(BitmapDrawable content) {
- if (getBackground() != content) {
- setBackground(content);
- }
+ assert (getBackground() != content);
+ setBackground(content);
}
public PageContentProvider getPageContentProvider() {
@@ -83,18 +86,23 @@
}
public void init(PageContentProvider provider, MediaSize mediaSize, Margins minMargins) {
- if (mProvider == null ? provider == null : mProvider.equals(provider)
- && ((mAttributes.getMediaSize() == null)
- ? mediaSize == null : mAttributes.getMediaSize().equals(mediaSize))
- && ((mAttributes.getMinMargins() == null)
- ? minMargins == null : mAttributes.getMinMargins().equals(minMargins))) {
+ final boolean providerChanged = (mProvider == null)
+ ? provider != null : !mProvider.equals(provider);
+ final boolean mediaSizeChanged = (mMediaSize == null)
+ ? mediaSize != null : !mMediaSize.equals(mediaSize);
+ final boolean marginsChanged = (mMinMargins == null)
+ ? minMargins != null : !mMinMargins.equals(minMargins);
+
+ if (!providerChanged && !mediaSizeChanged && !marginsChanged) {
return;
}
mProvider = provider;
- mAttributes.setMediaSize(mediaSize);
- mAttributes.setMinMargins(minMargins);
+ mMediaSize = mediaSize;
+ mMinMargins = minMargins;
+
mContentRequested = false;
+ mNeedsLayout = mNeedsLayout || mediaSizeChanged || marginsChanged;
// If there is no provider we want immediately to switch to
// the empty state, so pages with no content appear blank.
@@ -106,9 +114,11 @@
}
private void requestPageContentIfNeeded() {
- if (getWidth() > 0 && getHeight() > 0 && !mContentRequested && mProvider != null) {
+ if (getWidth() > 0 && getHeight() > 0 && !mContentRequested
+ && mProvider != null && !mNeedsLayout) {
mContentRequested = true;
- mProvider.getPageContent(new RenderSpec(getWidth(), getHeight(), mAttributes), this);
+ mProvider.getPageContent(new RenderSpec(getWidth(), getHeight(),
+ mMediaSize, mMinMargins), this);
}
}
}
diff --git a/packages/SystemUI/res/drawable/ic_info.xml b/packages/SystemUI/res/drawable/ic_info.xml
new file mode 100644
index 0000000..65e7bf5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_info.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM13.000000,17.000000l-2.000000,0.000000l0.000000,-6.000000l2.000000,0.000000L13.000000,17.000000zM13.000000,9.000000l-2.000000,0.000000L11.000000,7.000000l2.000000,0.000000L13.000000,9.000000z"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index ac8af1b..d52c274 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -77,13 +77,23 @@
</LinearLayout>
<ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
+ android:id="@+id/notification_inspect_app_provided_settings"
+ android:layout_width="52dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:gravity="center"
+ android:src="@drawable/ic_settings"
+ android:visibility="gone"
+ />
+
+ <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
android:id="@+id/notification_inspect_item"
android:layout_width="52dp"
android:layout_height="match_parent"
android:layout_weight="0"
android:gravity="center"
android:contentDescription="@string/status_bar_notification_inspect_item_title"
- android:src="@drawable/ic_settings"
+ android:src="@drawable/ic_info"
/>
</LinearLayout>
</com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b488c56..c7a91af 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -522,9 +522,13 @@
<!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_clear_all">Clear all notifications.</string>
- <!-- Title shown in notification popup for inspecting the responsible
- application [CHAR LIMIT=30] -->
- <string name="status_bar_notification_inspect_item_title">Settings</string>
+ <!-- Content description of button in notification inspector for system settings relating to
+ notifications from this application [CHAR LIMIT=NONE] -->
+ <string name="status_bar_notification_inspect_item_title">Notification settings</string>
+
+ <!-- Content description of button in notification inspetor for application-provided settings
+ for its own notifications [CHAR LIMIT=NONE] -->
+ <string name="status_bar_notification_app_settings_title"><xliff:g id="app_name" example="Calendar">%s</xliff:g> settings</string>
<!-- Description of the button in the phone-style notification panel that controls auto-rotation, when auto-rotation is on. [CHAR LIMIT=NONE] -->
<string name="accessibility_rotation_lock_off">Screen will rotate automatically.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index dcd89ee..2c1d70d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -34,13 +34,11 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
@@ -96,6 +94,7 @@
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -177,7 +176,7 @@
// public mode, private notifications, etc
private boolean mLockscreenPublicMode = false;
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
- private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance();
+ private NotificationColorUtil mNotificationColorUtil;
private UserManager mUserManager;
@@ -435,6 +434,8 @@
mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
+ mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
+
mNotificationData = new NotificationData(this);
mDreamManager = IDreamManager.Stub.asInterface(
@@ -717,11 +718,23 @@
entry.expandedBig.findViewById(com.android.internal.R.id.media_actions) != null;
}
+ // The gear button in the guts that links to the app's own notification settings
+ private void startAppOwnNotificationSettingsActivity(Intent intent,
+ final int notificationId, final String notificationTag, final int appUid) {
+ intent.putExtra("notification_id", notificationId);
+ intent.putExtra("notification_tag", notificationTag);
+ startNotificationGutsIntent(intent, appUid);
+ }
+
+ // The (i) button in the guts that links to the system notification settings for that app
private void startAppNotificationSettingsActivity(String packageName, final int appUid) {
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+ startNotificationGutsIntent(intent, appUid);
+ }
+ private void startNotificationGutsIntent(final Intent intent, final int appUid) {
final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
dismissKeyguardThenExecute(new OnDismissAction() {
@Override
@@ -1128,7 +1141,7 @@
entry.notification.getUser().getIdentifier());
int maxHeight = mRowMaxHeight;
- StatusBarNotification sbn = entry.notification;
+ final StatusBarNotification sbn = entry.notification;
RemoteViews contentView = sbn.getNotification().contentView;
RemoteViews bigContentView = sbn.getNotification().bigContentView;
@@ -1197,6 +1210,8 @@
((DateTimeView) row.findViewById(R.id.timestamp)).setTime(entry.notification.getPostTime());
((TextView) row.findViewById(R.id.pkgname)).setText(appname);
final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+ final View appSettingsButton
+ = guts.findViewById(R.id.notification_inspect_app_provided_settings);
if (appUid >= 0) {
final int appUidF = appUid;
settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -1204,8 +1219,33 @@
startAppNotificationSettingsActivity(pkg, appUidF);
}
});
+
+ final Intent appSettingsQueryIntent
+ = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
+ .setPackage(pkg);
+ List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
+ if (infos.size() > 0) {
+ appSettingsButton.setVisibility(View.VISIBLE);
+ appSettingsButton.setContentDescription(
+ mContext.getResources().getString(
+ R.string.status_bar_notification_app_settings_title,
+ appname
+ ));
+ final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
+ .setClassName(pkg, infos.get(0).activityInfo.name);
+ appSettingsButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
+ sbn.getId(),
+ sbn.getTag(),
+ appUidF);
+ }
+ });
+ }
} else {
settingsButton.setVisibility(View.GONE);
+ appSettingsButton.setVisibility(View.GONE);
}
workAroundBadLayerDrawableOpacity(row);
@@ -1307,7 +1347,7 @@
Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
icon.setImageDrawable(iconDrawable);
- if (mNotificationColorUtil.isGrayscale(iconDrawable)) {
+ if (mNotificationColorUtil.isGrayscaleIcon(iconDrawable)) {
icon.setBackgroundResource(
com.android.internal.R.drawable.notification_icon_legacy_bg);
int padding = mContext.getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
index c75bd28..c4c9dac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
@@ -36,7 +36,7 @@
private TextView mMoreText;
private int mTintColor;
private int mIconSize;
- private NotificationColorUtil mNotificationColorUtil = new NotificationColorUtil();
+ private NotificationColorUtil mNotificationColorUtil;
public NotificationOverflowIconsView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -45,6 +45,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mNotificationColorUtil = NotificationColorUtil.getInstance(getContext());
mTintColor = getResources().getColor(R.color.keyguard_overflow_content_color);
mIconSize = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 3e7a7e4..083aa9b 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -8395,10 +8395,15 @@
Slog.i(TAG, "Auto restore => " + doAutoRestore);
- synchronized (this) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
- mAutoRestore = doAutoRestore;
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_AUTO_RESTORE, doAutoRestore ? 1 : 0);
+ mAutoRestore = doAutoRestore;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
}
@@ -8467,10 +8472,15 @@
synchronized (mTransports) {
String prevTransport = null;
if (mTransports.get(transport) != null) {
- prevTransport = mCurrentTransport;
- mCurrentTransport = transport;
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.BACKUP_TRANSPORT, transport);
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ prevTransport = mCurrentTransport;
+ mCurrentTransport = transport;
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.BACKUP_TRANSPORT, transport);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
Slog.v(TAG, "selectBackupTransport() set " + mCurrentTransport
+ " returning " + prevTransport);
} else {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 93c0f07..9314cf8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -856,8 +856,11 @@
device.onDeviceRemoved();
// There is no explicit event for device removal unlike capability register event
// used for device addition . Hence we remove the device on hotplug event.
- invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE);
- updateSafeMhlInput();
+ HdmiDeviceInfo deviceInfo = device.getInfo();
+ if (deviceInfo != null) {
+ invokeDeviceEventListeners(deviceInfo, DEVICE_EVENT_REMOVE_DEVICE);
+ updateSafeMhlInput();
+ }
} else {
Slog.w(TAG, "No device to remove:[portId=" + portId);
}
@@ -1082,7 +1085,7 @@
// the connected mobile device, start routing control to switch ports.
// callback is handled by MHL action.
device.turnOn(callback);
- tv.doManualPortSwitching(device.getInfo().getPortId(), null);
+ tv.doManualPortSwitching(device.getPortId(), null);
return;
}
tv.deviceSelect(deviceId, callback);
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 37bedf3..4a8e318 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -538,14 +538,17 @@
pw.println("");
}
printedLabel = false;
- for (long keySetId : pkg.keySetData.getSigningKeySets()) {
- if (!printedLabel) {
- pw.print(" Signing KeySets: ");
- printedLabel = true;
- } else {
- pw.print(", ");
+ final long[] signingKeySets = pkg.keySetData.getSigningKeySets();
+ if (signingKeySets != null) {
+ for (long keySetId : signingKeySets) {
+ if (!printedLabel) {
+ pw.print(" Signing KeySets: ");
+ printedLabel = true;
+ } else {
+ pw.print(", ");
+ }
+ pw.print(Long.toString(keySetId));
}
- pw.print(Long.toString(keySetId));
}
if (printedLabel) {
pw.println("");
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 350c27e..34da1c9 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -221,18 +221,39 @@
private final Handler mHandler;
+ /**
+ * Create a PhoneStateListener for the Phone with the default subscription.
+ * This class requires Looper.myLooper() not return null. To supply your
+ * own non-null looper use PhoneStateListener(Looper looper) below.
+ */
public PhoneStateListener() {
this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper());
}
/**
+ * Create a PhoneStateListener for the Phone with the default subscription
+ * using a particular non-null Looper.
+ * @hide
+ */
+ public PhoneStateListener(Looper looper) {
+ this(SubscriptionManager.DEFAULT_SUB_ID, looper);
+ }
+
+ /**
+ * Create a PhoneStateListener for the Phone using the specified subscription.
+ * This class requires Looper.myLooper() not return null. To supply your
+ * own non-null Looper use PhoneStateListener(long subId, Looper looper) below.
* @hide
*/
public PhoneStateListener(long subId) {
this(subId, Looper.myLooper());
}
- /** @hide */
+ /**
+ * Create a PhoneStateListener for the Phone using the specified subscription
+ * and non-null Looper.
+ * @hide
+ */
public PhoneStateListener(long subId, Looper looper) {
if (DBG) log("ctor: subId=" + subId + " looper=" + looper);
mSubId = subId;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index f83f164..2bb2404 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1,18 +1,18 @@
/*
-* Copyright (C) 2011-2014 MediaTek Inc.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package android.telephony;
@@ -30,7 +30,10 @@
import java.util.List;
/**
- *@hide
+ * SubscriptionManager is the application interface to SubscriptionController
+ * and provides information about the current Telephony Subscriptions.
+ *
+ * @hide
*/
public class SubscriptionManager implements BaseColumns {
private static final String LOG_TAG = "SUB";
@@ -38,123 +41,167 @@
private static final boolean VDBG = false;
// An invalid phone identifier
+ /** @hide */
public static final int INVALID_PHONE_ID = -1000;
// Indicates the caller wants the default phone id.
+ /** @hide */
public static final int DEFAULT_PHONE_ID = Integer.MAX_VALUE;
// An invalid slot identifier
+ /** @hide */
public static final int INVALID_SLOT_ID = -1000;
// Indicates the caller wants the default slot id.
+ /** @hide */
public static final int DEFAULT_SLOT_ID = Integer.MAX_VALUE;
// An invalid subscription identifier
+ /** @hide */
public static final long INVALID_SUB_ID = -1000;
// Indicates the user should be asked which sub to use.
+ /** @hide */
public static final long ASK_USER_SUB_ID = -1001;
// Indicates the caller wants the default sub id.
+ /** @hide */
public static final long DEFAULT_SUB_ID = Long.MAX_VALUE;
+ /** @hide */
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+ /** @hide */
public static final int DEFAULT_INT_VALUE = -100;
+ /** @hide */
public static final String DEFAULT_STRING_VALUE = "N/A";
+ /** @hide */
public static final int EXTRA_VALUE_NEW_SIM = 1;
+
+ /** @hide */
public static final int EXTRA_VALUE_REMOVE_SIM = 2;
+ /** @hide */
public static final int EXTRA_VALUE_REPOSITION_SIM = 3;
+ /** @hide */
public static final int EXTRA_VALUE_NOCHANGE = 4;
+ /** @hide */
public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus";
+ /** @hide */
public static final String INTENT_KEY_SIM_COUNT = "simCount";
+ /** @hide */
public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot";
+ /** @hide */
public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus";
/**
* The ICC ID of a SIM.
* <P>Type: TEXT (String)</P>
*/
+ /** @hide */
public static final String ICC_ID = "icc_id";
/**
* <P>Type: INTEGER (int)</P>
*/
+ /** @hide */
public static final String SIM_ID = "sim_id";
-
+ /** @hide */
public static final int SIM_NOT_INSERTED = -1;
/**
* The display name of a SIM.
* <P>Type: TEXT (String)</P>
*/
+ /** @hide */
public static final String DISPLAY_NAME = "display_name";
+ /** @hide */
public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
/**
* The display name source of a SIM.
* <P>Type: INT (int)</P>
*/
+ /** @hide */
public static final String NAME_SOURCE = "name_source";
+ /** @hide */
public static final int NAME_SOURCE_UNDEFINDED = -1;
+ /** @hide */
public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
+ /** @hide */
public static final int NAME_SOURCE_SIM_SOURCE = 1;
+ /** @hide */
public static final int NAME_SOURCE_USER_INPUT = 2;
/**
* The color of a SIM.
* <P>Type: INTEGER (int)</P>
*/
+ /** @hide */
public static final String COLOR = "color";
+ /** @hide */
public static final int COLOR_1 = 0;
+ /** @hide */
public static final int COLOR_2 = 1;
+ /** @hide */
public static final int COLOR_3 = 2;
+ /** @hide */
public static final int COLOR_4 = 3;
+ /** @hide */
public static final int COLOR_DEFAULT = COLOR_1;
/**
* The phone number of a SIM.
* <P>Type: TEXT (String)</P>
*/
+ /** @hide */
public static final String NUMBER = "number";
/**
* The number display format of a SIM.
* <P>Type: INTEGER (int)</P>
*/
+ /** @hide */
public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+ /** @hide */
public static final int DISPLAY_NUMBER_NONE = 0;
+ /** @hide */
public static final int DISPLAY_NUMBER_FIRST = 1;
+ /** @hide */
public static final int DISPLAY_NUMBER_LAST = 2;
+ /** @hide */
public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
/**
* Permission for data roaming of a SIM.
* <P>Type: INTEGER (int)</P>
*/
+ /** @hide */
public static final String DATA_ROAMING = "data_roaming";
+ /** @hide */
public static final int DATA_ROAMING_ENABLE = 1;
+ /** @hide */
public static final int DATA_ROAMING_DISABLE = 0;
+ /** @hide */
public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
private static final int RES_TYPE_BACKGROUND_DARK = 0;
@@ -166,12 +213,13 @@
/**
* Broadcast Action: The user has changed one of the default subs related to
* data, phone calls, or sms</p>
- *
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SUB_DEFAULT_CHANGED_ACTION =
"android.intent.action.SUB_DEFAULT_CHANGED";
+ /** @hide */
public SubscriptionManager() {
if (DBG) logd("SubscriptionManager created");
}
@@ -180,6 +228,7 @@
* Get the SubInfoRecord according to an index
* @param subId The unique SubInfoRecord index in database
* @return SubInfoRecord, maybe null
+ * @hide
*/
public static SubInfoRecord getSubInfoUsingSubId(long subId) {
if (!isValidSubId(subId)) {
@@ -206,6 +255,7 @@
* Get the SubInfoRecord according to an IccId
* @param iccId the IccId of SIM card
* @return SubInfoRecord, maybe null
+ * @hide
*/
public static List<SubInfoRecord> getSubInfoUsingIccId(String iccId) {
if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId);
@@ -232,6 +282,7 @@
* Get the SubInfoRecord according to slotId
* @param slotId the slot which the SIM is inserted
* @return SubInfoRecord, maybe null
+ * @hide
*/
public static List<SubInfoRecord> getSubInfoUsingSlotId(int slotId) {
// FIXME: Consider never returning null
@@ -257,6 +308,7 @@
/**
* Get all the SubInfoRecord(s) in subinfo database
* @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+ * @hide
*/
public static List<SubInfoRecord> getAllSubInfoList() {
if (VDBG) logd("[getAllSubInfoList]+");
@@ -278,6 +330,7 @@
/**
* Get the SubInfoRecord(s) of the currently inserted SIM(s)
* @return Array list of currently inserted SubInfoRecord(s)
+ * @hide
*/
public static List<SubInfoRecord> getActiveSubInfoList() {
List<SubInfoRecord> result = null;
@@ -297,6 +350,7 @@
/**
* Get the SUB count of all SUB(s) in subinfo database
* @return all SIM count in database, include what was inserted before
+ * @hide
*/
public static int getAllSubInfoCount() {
if (VDBG) logd("[getAllSubInfoCount]+");
@@ -318,6 +372,7 @@
/**
* Get the count of active SUB(s)
* @return active SIM count
+ * @hide
*/
public static int getActiveSubInfoCount() {
int result = 0;
@@ -339,6 +394,7 @@
* @param iccId the IccId of the SIM card
* @param slotId the slot which the SIM is inserted
* @return the URL of the newly created row or the updated row
+ * @hide
*/
public static Uri addSubInfoRecord(String iccId, int slotId) {
if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
@@ -369,6 +425,7 @@
* @param color the color of the SIM
* @param subId the unique SubInfoRecord index in database
* @return the number of records updated
+ * @hide
*/
public static int setColor(int color, long subId) {
if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId);
@@ -398,6 +455,7 @@
* @param displayName the display name of SIM card
* @param subId the unique SubInfoRecord index in database
* @return the number of records updated
+ * @hide
*/
public static int setDisplayName(String displayName, long subId) {
return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
@@ -410,6 +468,7 @@
* @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
* 2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
* @return the number of records updated or -1 if invalid subId
+ * @hide
*/
public static int setDisplayName(String displayName, long subId, long nameSource) {
if (VDBG) {
@@ -441,6 +500,7 @@
* @param number the phone number of the SIM
* @param subId the unique SubInfoRecord index in database
* @return the number of records updated
+ * @hide
*/
public static int setDisplayNumber(String number, long subId) {
if (number == null || !isValidSubId(subId)) {
@@ -468,6 +528,7 @@
* @param format the display format of phone number
* @param subId the unique SubInfoRecord index in database
* @return the number of records updated
+ * @hide
*/
public static int setDisplayNumberFormat(int format, long subId) {
if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId);
@@ -496,6 +557,7 @@
* @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
* @param subId the unique SubInfoRecord index in database
* @return the number of records updated
+ * @hide
*/
public static int setDataRoaming(int roaming, long subId) {
if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
@@ -518,6 +580,7 @@
return result;
}
+ /** @hide */
public static int getSlotId(long subId) {
if (!isValidSubId(subId)) {
logd("[getSlotId]- fail");
@@ -538,6 +601,7 @@
}
+ /** @hide */
public static long[] getSubId(int slotId) {
if (!isValidSlotId(slotId)) {
logd("[getSubId]- fail");
@@ -558,6 +622,7 @@
return subId;
}
+ /** @hide */
public static int getPhoneId(long subId) {
if (!isValidSubId(subId)) {
logd("[getPhoneId]- fail");
@@ -613,6 +678,7 @@
* @return the "system" defaultSubId on a voice capable device this
* will be getDefaultVoiceSubId() and on a data only device it will be
* getDefaultDataSubId().
+ * @hide
*/
public static long getDefaultSubId() {
long subId = INVALID_SUB_ID;
@@ -630,6 +696,7 @@
return subId;
}
+ /** @hide */
public static long getDefaultVoiceSubId() {
long subId = INVALID_SUB_ID;
@@ -646,6 +713,7 @@
return subId;
}
+ /** @hide */
public static void setDefaultVoiceSubId(long subId) {
if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
try {
@@ -658,14 +726,17 @@
}
}
+ /** @hide */
public static SubInfoRecord getDefaultVoiceSubInfo() {
return getSubInfoUsingSubId(getDefaultVoiceSubId());
}
+ /** @hide */
public static int getDefaultVoicePhoneId() {
return getPhoneId(getDefaultVoiceSubId());
}
+ /** @hide */
public static long getDefaultSmsSubId() {
long subId = INVALID_SUB_ID;
@@ -682,6 +753,7 @@
return subId;
}
+ /** @hide */
public static void setDefaultSmsSubId(long subId) {
if (VDBG) logd("setDefaultSmsSubId sub id = " + subId);
try {
@@ -694,14 +766,17 @@
}
}
+ /** @hide */
public static SubInfoRecord getDefaultSmsSubInfo() {
return getSubInfoUsingSubId(getDefaultSmsSubId());
}
+ /** @hide */
public static int getDefaultSmsPhoneId() {
return getPhoneId(getDefaultSmsSubId());
}
+ /** @hide */
public static long getDefaultDataSubId() {
long subId = INVALID_SUB_ID;
@@ -718,6 +793,7 @@
return subId;
}
+ /** @hide */
public static void setDefaultDataSubId(long subId) {
if (VDBG) logd("setDataSubscription sub id = " + subId);
try {
@@ -730,14 +806,17 @@
}
}
+ /** @hide */
public static SubInfoRecord getDefaultDataSubInfo() {
return getSubInfoUsingSubId(getDefaultDataSubId());
}
+ /** @hide */
public static int getDefaultDataPhoneId() {
return getPhoneId(getDefaultDataSubId());
}
+ /** @hide */
public static void clearSubInfo() {
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -752,6 +831,7 @@
}
//FIXME this is vulnerable to race conditions
+ /** @hide */
public static boolean allDefaultsSelected() {
if (getDefaultDataSubId() == INVALID_SUB_ID) {
return false;
@@ -768,6 +848,7 @@
/**
* If a default is set to subscription which is not active, this will reset that default back to
* INVALID_SUB_ID.
+ * @hide
*/
public static void clearDefaultsForInactiveSubIds() {
if (VDBG) logd("clearDefaultsForInactiveSubIds");
@@ -781,19 +862,23 @@
}
}
+ /** @hide */
public static boolean isValidSubId(long subId) {
return subId > INVALID_SUB_ID ;
}
+ /** @hide */
public static boolean isValidSlotId(int slotId) {
return slotId > INVALID_SLOT_ID && slotId < TelephonyManager.getDefault().getSimCount();
}
+ /** @hide */
public static boolean isValidPhoneId(int phoneId) {
return phoneId > INVALID_PHONE_ID
&& phoneId < TelephonyManager.getDefault().getPhoneCount();
}
+ /** @hide */
public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
long[] subIds = SubscriptionManager.getSubId(phoneId);
if (subIds != null && subIds.length > 0) {
@@ -803,6 +888,7 @@
}
}
+ /** @hide */
public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, long subId) {
if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
@@ -815,6 +901,7 @@
/**
* @return the list of subId's that are active,
* is never null but the length maybe 0.
+ * @hide
*/
public static long[] getActiveSubIdList() {
long[] subId = null;