summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl8
-rw-r--r--core/java/android/content/pm/PackageManager.java12
-rw-r--r--core/java/android/net/CaptivePortalTracker.java133
-rw-r--r--core/java/android/net/ConnectivityManager.java89
-rw-r--r--core/java/android/net/IConnectivityManager.aidl5
-rw-r--r--core/java/android/net/MobileDataStateTracker.java94
-rw-r--r--core/java/android/net/NetworkInfo.java7
-rw-r--r--core/java/android/nfc/cardemulation/ApduServiceInfo.java20
-rw-r--r--core/java/android/nfc/cardemulation/CardEmulationManager.java101
-rw-r--r--core/java/android/nfc/cardemulation/HostApduService.java2
-rw-r--r--core/java/android/print/IPrintManager.aidl4
-rw-r--r--core/java/android/print/PrintDocumentAdapter.java18
-rw-r--r--core/java/android/print/PrintDocumentInfo.java30
-rw-r--r--core/java/android/print/PrintFileDocumentAdapter.java10
-rw-r--r--core/java/android/print/PrintJobInfo.java62
-rw-r--r--core/java/android/print/PrintManager.java13
-rw-r--r--core/java/android/print/PrinterDiscoverySession.java35
-rw-r--r--core/java/android/print/pdf/PrintedPdfDocument.java5
-rw-r--r--core/java/android/printservice/IPrintService.aidl4
-rw-r--r--core/java/android/printservice/PrintDocument.java11
-rw-r--r--core/java/android/printservice/PrintJob.java71
-rw-r--r--core/java/android/printservice/PrintService.java44
-rw-r--r--core/java/android/printservice/PrinterDiscoverySession.java100
-rw-r--r--core/java/android/provider/AlarmClock.java9
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/util/LayoutDirection.java8
-rw-r--r--core/java/android/webkit/WebView.java28
-rw-r--r--core/java/android/webkit/WebViewClassic.java7
-rw-r--r--core/java/android/webkit/WebViewProvider.java8
-rw-r--r--core/java/android/widget/GridLayout.java124
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java228
31 files changed, 843 insertions, 453 deletions
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index eba69b6..2b0c896 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -216,6 +216,12 @@ interface IPackageManager {
void resetPreferredActivities(int userId);
+ ResolveInfo getLastChosenActivity(in Intent intent,
+ String resolvedType, int flags);
+
+ void setLastChosenActivity(in Intent intent, String resolvedType, int flags,
+ in IntentFilter filter, int match, in ComponentName activity);
+
void addPreferredActivity(in IntentFilter filter, int match,
in ComponentName[] set, in ComponentName activity, int userId);
@@ -226,7 +232,7 @@ interface IPackageManager {
int getPreferredActivities(out List<IntentFilter> outFilters,
out List<ComponentName> outActivities, String packageName);
-
+
/**
* As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 81f860e..d58b14c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -957,12 +957,24 @@ public abstract class PackageManager {
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports host-
* based NFC card emulation.
+ *
+ * TODO remove when depending apps have moved to new constant.
+ * @hide
+ * @deprecated
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports host-
+ * based NFC card emulation.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device includes an accelerometer.
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
index 74c2c59..01977cd 100644
--- a/core/java/android/net/CaptivePortalTracker.java
+++ b/core/java/android/net/CaptivePortalTracker.java
@@ -16,22 +16,16 @@
package android.net;
-import android.app.Activity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
-import android.os.UserHandle;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -46,7 +40,6 @@ import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.TelephonyManager;
-import android.text.TextUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -60,8 +53,6 @@ import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;
-import com.android.internal.R;
-
/**
* This class allows captive portal detection on a network.
* @hide
@@ -71,7 +62,6 @@ public class CaptivePortalTracker extends StateMachine {
private static final String TAG = "CaptivePortalTracker";
private static final String DEFAULT_SERVER = "clients3.google.com";
- private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
private static final int SOCKET_TIMEOUT_MS = 10000;
@@ -93,7 +83,6 @@ public class CaptivePortalTracker extends StateMachine {
private String mServer;
private String mUrl;
- private boolean mNotificationShown = false;
private boolean mIsCaptivePortalCheckEnabled = false;
private IConnectivityManager mConnService;
private TelephonyManager mTelephonyManager;
@@ -192,12 +181,12 @@ public class CaptivePortalTracker extends StateMachine {
private class DefaultState extends State {
@Override
public void enter() {
- if (DBG) log(getName() + "\n");
+ setNotificationOff();
}
@Override
public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
+ if (DBG) log(getName() + message.toString());
switch (message.what) {
case CMD_DETECT_PORTAL:
NetworkInfo info = (NetworkInfo) message.obj;
@@ -219,23 +208,24 @@ public class CaptivePortalTracker extends StateMachine {
private class NoActiveNetworkState extends State {
@Override
public void enter() {
- if (DBG) log(getName() + "\n");
mNetworkInfo = null;
- /* Clear any previous notification */
- setNotificationVisible(false);
}
@Override
public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
+ if (DBG) log(getName() + message.toString());
InetAddress server;
NetworkInfo info;
switch (message.what) {
case CMD_CONNECTIVITY_CHANGE:
info = (NetworkInfo) message.obj;
- if (info.isConnected() && isActiveNetwork(info)) {
- mNetworkInfo = info;
- transitionTo(mDelayedCaptiveCheckState);
+ if (info.getType() == ConnectivityManager.TYPE_WIFI) {
+ if (info.isConnected() && isActiveNetwork(info)) {
+ mNetworkInfo = info;
+ transitionTo(mDelayedCaptiveCheckState);
+ }
+ } else {
+ log(getName() + " not a wifi connectivity change, ignore");
}
break;
default:
@@ -248,7 +238,7 @@ public class CaptivePortalTracker extends StateMachine {
private class ActiveNetworkState extends State {
@Override
public void enter() {
- if (DBG) log(getName() + "\n");
+ setNotificationOff();
}
@Override
@@ -281,7 +271,6 @@ public class CaptivePortalTracker extends StateMachine {
private class DelayedCaptiveCheckState extends State {
@Override
public void enter() {
- if (DBG) log(getName() + "\n");
Message message = obtainMessage(CMD_DELAYED_CAPTIVE_CHECK, ++mDelayedCheckToken, 0);
if (mDeviceProvisioned) {
sendMessageDelayed(message, DELAYED_CHECK_INTERVAL_MS);
@@ -292,7 +281,7 @@ public class CaptivePortalTracker extends StateMachine {
@Override
public boolean processMessage(Message message) {
- if (DBG) log(getName() + message.toString() + "\n");
+ if (DBG) log(getName() + message.toString());
switch (message.what) {
case CMD_DELAYED_CAPTIVE_CHECK:
if (message.arg1 == mDelayedCheckToken) {
@@ -308,7 +297,12 @@ public class CaptivePortalTracker extends StateMachine {
if (captive) {
// Setup Wizard will assist the user in connecting to a captive
// portal, so make the notification visible unless during setup
- setNotificationVisible(true);
+ try {
+ mConnService.setProvisioningNotificationVisible(true,
+ mNetworkInfo.getType(), mNetworkInfo.getExtraInfo(), mUrl);
+ } catch(RemoteException e) {
+ e.printStackTrace();
+ }
}
} else {
Intent intent = new Intent(
@@ -366,6 +360,15 @@ public class CaptivePortalTracker extends StateMachine {
return false;
}
+ private void setNotificationOff() {
+ try {
+ mConnService.setProvisioningNotificationVisible(false, ConnectivityManager.TYPE_NONE,
+ null, null);
+ } catch (RemoteException e) {
+ log("setNotificationOff: " + e);
+ }
+ }
+
/**
* Do a URL fetch on a known server to see if we get the data we expect.
* Measure the response time and broadcast that.
@@ -394,17 +397,14 @@ public class CaptivePortalTracker extends StateMachine {
long responseTimestamp = SystemClock.elapsedRealtime();
// we got a valid response, but not from the real google
- boolean isCaptivePortal = urlConnection.getResponseCode() != 204;
+ int rspCode = urlConnection.getResponseCode();
+ boolean isCaptivePortal = rspCode != 204;
sendNetworkConditionsBroadcast(true /* response received */, isCaptivePortal,
requestTimestamp, responseTimestamp);
+
+ if (DBG) log("isCaptivePortal: ret=" + isCaptivePortal + " rspCode=" + rspCode);
return isCaptivePortal;
- } catch (SocketTimeoutException e) {
- if (DBG) log("Probably a portal: exception " + e);
- if (requestTimestamp != -1) {
- sendFailedCaptivePortalCheckBroadcast(requestTimestamp);
- } // else something went wrong with setting up the urlConnection
- return true;
} catch (IOException e) {
if (DBG) log("Probably not a portal: exception " + e);
if (requestTimestamp != -1) {
@@ -435,77 +435,6 @@ public class CaptivePortalTracker extends StateMachine {
return null;
}
- private void setNotificationVisible(boolean visible) {
- // if it should be hidden and it is already hidden, then noop
- if (!visible && !mNotificationShown) {
- if (DBG) log("setNotivicationVisible: false and not shown, so noop");
- return;
- }
-
- Resources r = Resources.getSystem();
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
-
- if (visible) {
- CharSequence title;
- CharSequence details;
- int icon;
- String url = null;
- switch (mNetworkInfo.getType()) {
- case ConnectivityManager.TYPE_WIFI:
- title = r.getString(R.string.wifi_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed,
- mNetworkInfo.getExtraInfo());
- icon = R.drawable.stat_notify_wifi_in_range;
- url = mUrl;
- break;
- case ConnectivityManager.TYPE_MOBILE:
- title = r.getString(R.string.network_available_sign_in, 0);
- // TODO: Change this to pull from NetworkInfo once a printable
- // name has been added to it
- details = mTelephonyManager.getNetworkOperatorName();
- icon = R.drawable.stat_notify_rssi_in_range;
- try {
- url = mConnService.getMobileProvisioningUrl();
- if (TextUtils.isEmpty(url)) {
- url = mConnService.getMobileRedirectedProvisioningUrl();
- }
- } catch(RemoteException e) {
- e.printStackTrace();
- }
- if (TextUtils.isEmpty(url)) {
- url = mUrl;
- }
- break;
- default:
- title = r.getString(R.string.network_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed,
- mNetworkInfo.getExtraInfo());
- icon = R.drawable.stat_notify_rssi_in_range;
- url = mUrl;
- break;
- }
-
- Notification notification = new Notification();
- notification.when = 0;
- notification.icon = icon;
- notification.flags = Notification.FLAG_AUTO_CANCEL;
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
- Intent.FLAG_ACTIVITY_NEW_TASK);
- notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
- notification.tickerText = title;
- notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
-
- if (DBG) log("setNotivicationVisible: make visible");
- notificationManager.notify(NOTIFICATION_ID, 1, notification);
- } else {
- if (DBG) log("setNotivicationVisible: cancel notification");
- notificationManager.cancel(NOTIFICATION_ID, 1);
- }
- mNotificationShown = visible;
- }
-
private void sendFailedCaptivePortalCheckBroadcast(long requestTimestampMs) {
sendNetworkConditionsBroadcast(false /* response received */, false /* ignored */,
requestTimestampMs, 0 /* ignored */);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index f6a3a4a..3874369 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -624,6 +624,29 @@ public class ConnectivityManager {
}
/**
+ * Returns details about the Provisioning or currently active default data network. When
+ * connected, this network is the default route for outgoing connections.
+ * You should always check {@link NetworkInfo#isConnected()} before initiating
+ * network traffic. This may return {@code null} when there is no default
+ * network.
+ *
+ * @return a {@link NetworkInfo} object for the current default network
+ * or {@code null} if no network default network is currently active
+ *
+ * <p>This method requires the call to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * {@hide}
+ */
+ public NetworkInfo getProvisioningOrActiveNetworkInfo() {
+ try {
+ return mService.getProvisioningOrActiveNetworkInfo();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Returns the IP information for the current default network.
*
* @return a {@link LinkProperties} object describing the IP info
@@ -1357,63 +1380,19 @@ public class ConnectivityManager {
}
/**
- * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE)
- */
-
- /**
- * No connection was possible to the network.
- * {@hide}
- */
- public static final int CMP_RESULT_CODE_NO_CONNECTION = 0;
-
- /**
- * A connection was made to the internet, all is well.
- * {@hide}
- */
- public static final int CMP_RESULT_CODE_CONNECTABLE = 1;
-
- /**
- * A connection was made but there was a redirection, we appear to be in walled garden.
- * This is an indication of a warm sim on a mobile network.
- * {@hide}
- */
- public static final int CMP_RESULT_CODE_REDIRECTED = 2;
-
- /**
- * A connection was made but no dns server was available to resolve a name to address.
- * This is an indication of a warm sim on a mobile network.
+ * Check mobile provisioning.
*
- * {@hide}
- */
- public static final int CMP_RESULT_CODE_NO_DNS = 3;
-
- /**
- * A connection was made but could not open a TCP connection.
- * This is an indication of a warm sim on a mobile network.
- * {@hide}
- */
- public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4;
-
- /**
- * Check mobile provisioning. The resultCode passed to
- * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above.
- * This may take a minute or more to complete.
- *
- * @param sendNotificaiton, when true a notification will be sent to user.
* @param suggestedTimeOutMs, timeout in milliseconds
- * @param resultReceiver needs to be supplied to receive the result
*
* @return time out that will be used, maybe less that suggestedTimeOutMs
* -1 if an error.
*
* {@hide}
*/
- public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs,
- ResultReceiver resultReceiver) {
+ public int checkMobileProvisioning(int suggestedTimeOutMs) {
int timeOutMs = -1;
try {
- timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs,
- resultReceiver);
+ timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs);
} catch (RemoteException e) {
}
return timeOutMs;
@@ -1481,4 +1460,20 @@ public class ConnectivityManager {
return null;
}
}
+
+ /**
+ * Set sign in error notification to visible or in visible
+ *
+ * @param visible
+ * @param networkType
+ *
+ * {@hide}
+ */
+ public void setProvisioningNotificationVisible(boolean visible, int networkType,
+ String extraInfo, String url) {
+ try {
+ mService.setProvisioningNotificationVisible(visible, networkType, extraInfo, url);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index bf2dade..c07e900 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -50,6 +50,8 @@ interface IConnectivityManager
NetworkInfo getNetworkInfo(int networkType);
NetworkInfo[] getAllNetworkInfo();
+ NetworkInfo getProvisioningOrActiveNetworkInfo();
+
boolean isNetworkSupported(int networkType);
LinkProperties getActiveLinkProperties();
@@ -141,7 +143,7 @@ interface IConnectivityManager
int findConnectionTypeForIface(in String iface);
- int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver);
+ int checkMobileProvisioning(int suggestedTimeOutMs);
String getMobileProvisioningUrl();
@@ -153,4 +155,5 @@ interface IConnectivityManager
LinkInfo[] getAllLinkInfo();
+ void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index faa13b0..125d5c1 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -61,8 +61,12 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
private ITelephony mPhoneService;
private String mApnType;
+ private NetworkInfo mNetworkInfo;
private boolean mTeardownRequested = false;
private Handler mTarget;
+ private Context mContext;
+ private LinkProperties mLinkProperties;
+ private LinkCapabilities mLinkCapabilities;
private boolean mPrivateDnsRouteSet = false;
private boolean mDefaultRouteSet = false;
@@ -106,6 +110,7 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
IntentFilter filter = new IntentFilter();
filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+ filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN);
filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
mContext.registerReceiver(new MobileDataStateReceiver(), filter);
@@ -184,10 +189,41 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
public void releaseWakeLock() {
}
+ private void updateLinkProperitesAndCapatilities(Intent intent) {
+ mLinkProperties = intent.getParcelableExtra(
+ PhoneConstants.DATA_LINK_PROPERTIES_KEY);
+ if (mLinkProperties == null) {
+ loge("CONNECTED event did not supply link properties.");
+ mLinkProperties = new LinkProperties();
+ }
+ mLinkCapabilities = intent.getParcelableExtra(
+ PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
+ if (mLinkCapabilities == null) {
+ loge("CONNECTED event did not supply link capabilities.");
+ mLinkCapabilities = new LinkCapabilities();
+ }
+ }
+
private class MobileDataStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(TelephonyIntents.
+ ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) {
+ String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
+ String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
+ if (!TextUtils.equals(mApnType, apnType)) {
+ return;
+ }
+ if (DBG) {
+ log("Broadcast received: " + intent.getAction() + " apnType=" + apnType
+ + " apnName=" + apnName);
+ }
+
+ // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING
+ mMobileDataState = PhoneConstants.DataState.CONNECTING;
+ updateLinkProperitesAndCapatilities(intent);
+ setDetailedState(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, "", apnName);
+ } else if (intent.getAction().equals(TelephonyIntents.
ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
if (VDBG) {
@@ -249,18 +285,7 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
setDetailedState(DetailedState.SUSPENDED, reason, apnName);
break;
case CONNECTED:
- mLinkProperties = intent.getParcelableExtra(
- PhoneConstants.DATA_LINK_PROPERTIES_KEY);
- if (mLinkProperties == null) {
- loge("CONNECTED event did not supply link properties.");
- mLinkProperties = new LinkProperties();
- }
- mLinkCapabilities = intent.getParcelableExtra(
- PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
- if (mLinkCapabilities == null) {
- loge("CONNECTED event did not supply link capabilities.");
- mLinkCapabilities = new LinkCapabilities();
- }
+ updateLinkProperitesAndCapatilities(intent);
setDetailedState(DetailedState.CONNECTED, reason, apnName);
break;
}
@@ -319,8 +344,8 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY);
String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
if (DBG) {
- log("Received " + intent.getAction() +
- " broadcast" + (reason == null ? "" : "(" + reason + ")"));
+ log("Broadcast received: " + intent.getAction() +
+ " reason=" + reason == null ? "null" : reason);
}
setDetailedState(DetailedState.FAILED, reason, apnName);
} else {
@@ -412,6 +437,13 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED);
}
+ /**
+ * @return true if this is ready to operate
+ */
+ public boolean isReady() {
+ return mDataConnectionTrackerAc != null;
+ }
+
@Override
public void captivePortalCheckComplete() {
// not implemented
@@ -574,6 +606,40 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
}
}
+ /**
+ * Inform DCT mobile provisioning has started, it ends when provisioning completes.
+ */
+ public void enableMobileProvisioning(String url) {
+ if (DBG) log("enableMobileProvisioning(url=" + url + ")");
+ final AsyncChannel channel = mDataConnectionTrackerAc;
+ if (channel != null) {
+ Message msg = Message.obtain();
+ msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING;
+ msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url));
+ channel.sendMessage(msg);
+ }
+ }
+
+ /**
+ * Return if this network is the provisioning network. Valid only if connected.
+ * @param met
+ */
+ public boolean isProvisioningNetwork() {
+ boolean retVal;
+ try {
+ Message msg = Message.obtain();
+ msg.what = DctConstants.CMD_IS_PROVISIONING_APN;
+ msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType));
+ Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg);
+ retVal = result.arg1 == DctConstants.ENABLED;
+ } catch (NullPointerException e) {
+ loge("isProvisioningNetwork: X " + e);
+ retVal = false;
+ }
+ if (DBG) log("isProvisioningNetwork: retVal=" + retVal);
+ return retVal;
+ }
+
@Override
public void addStackedLink(LinkProperties link) {
mLinkProperties.addStackedLink(link);
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 689dae5..dabc73a 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -84,6 +84,12 @@ public class NetworkInfo implements Parcelable {
VERIFYING_POOR_LINK,
/** Checking if network is a captive portal */
CAPTIVE_PORTAL_CHECK,
+ /**
+ * Network is connected to provisioning network
+ * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK
+ * @hide
+ */
+ CONNECTED_TO_PROVISIONING_NETWORK
}
/**
@@ -108,6 +114,7 @@ public class NetworkInfo implements Parcelable {
stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
+ stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED);
}
private int mNetworkType;
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 3f7e3ef..b83911a 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -75,16 +75,22 @@ public final class ApduServiceInfo implements Parcelable {
final HashMap<String, AidGroup> mCategoryToGroup;
/**
+ * Whether this service should only be started when the device is unlocked.
+ */
+ final boolean mRequiresDeviceUnlock;
+
+ /**
* @hide
*/
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
- ArrayList<AidGroup> aidGroups) {
+ ArrayList<AidGroup> aidGroups, boolean requiresUnlock) {
this.mService = info;
this.mDescription = description;
this.mAidGroups = aidGroups;
this.mAids = new ArrayList<String>();
this.mCategoryToGroup = new HashMap<String, AidGroup>();
this.mOnHost = onHost;
+ this.mRequiresDeviceUnlock = requiresUnlock;
for (AidGroup aidGroup : aidGroups) {
this.mCategoryToGroup.put(aidGroup.category, aidGroup);
this.mAids.addAll(aidGroup.aids);
@@ -132,12 +138,16 @@ public final class ApduServiceInfo implements Parcelable {
mService = info;
mDescription = sa.getString(
com.android.internal.R.styleable.HostApduService_description);
+ mRequiresDeviceUnlock = sa.getBoolean(
+ com.android.internal.R.styleable.HostApduService_requireDeviceUnlock,
+ false);
} else {
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.OffHostApduService);
mService = info;
mDescription = sa.getString(
com.android.internal.R.styleable.OffHostApduService_description);
+ mRequiresDeviceUnlock = false;
}
mAidGroups = new ArrayList<AidGroup>();
@@ -226,6 +236,10 @@ public final class ApduServiceInfo implements Parcelable {
return mOnHost;
}
+ public boolean requiresUnlock() {
+ return mRequiresDeviceUnlock;
+ }
+
public CharSequence loadLabel(PackageManager pm) {
return mService.loadLabel(pm);
}
@@ -287,6 +301,7 @@ public final class ApduServiceInfo implements Parcelable {
if (mAidGroups.size() > 0) {
dest.writeTypedList(mAidGroups);
}
+ dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
};
public static final Parcelable.Creator<ApduServiceInfo> CREATOR =
@@ -301,7 +316,8 @@ public final class ApduServiceInfo implements Parcelable {
if (numGroups > 0) {
source.readTypedList(aidGroups, AidGroup.CREATOR);
}
- return new ApduServiceInfo(info, onHost, description, aidGroups);
+ boolean requiresUnlock = (source.readInt() != 0) ? true : false;
+ return new ApduServiceInfo(info, onHost, description, aidGroups, requiresUnlock);
}
@Override
diff --git a/core/java/android/nfc/cardemulation/CardEmulationManager.java b/core/java/android/nfc/cardemulation/CardEmulationManager.java
index 537fded..9d60c73 100644
--- a/core/java/android/nfc/cardemulation/CardEmulationManager.java
+++ b/core/java/android/nfc/cardemulation/CardEmulationManager.java
@@ -27,6 +27,7 @@ import android.nfc.INfcCardEmulation;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Log;
import java.util.HashMap;
@@ -78,19 +79,68 @@ public final class CardEmulationManager {
*/
public static final String CATEGORY_OTHER = "other";
- static boolean sIsInitialized = false;
- static HashMap<Context, CardEmulationManager> sCardEmuManagers = new HashMap();
- static INfcCardEmulation sService;
+ /**
+ * Return value for {@link #getSelectionModeForCategory(String)}.
+ *
+ * <p>In this mode, the user has set a default service for this
+ * AID category. If a remote reader selects any of the AIDs
+ * that the default service has registered in this category,
+ * that service will automatically be bound to to handle
+ * the transaction.
+ *
+ * <p>There are still cases where a service that is
+ * not the default for a category can selected:
+ * <p>
+ * If a remote reader selects an AID in this category
+ * that is not handled by the default service, and there is a set
+ * of other services {S} that do handle this AID, the
+ * user is asked if he wants to use any of the services in
+ * {S} instead.
+ * <p>
+ * As a special case, if the size of {S} is one, containing a single service X,
+ * and all AIDs X has registered in this category are not
+ * registered by any other service, then X will be
+ * selected automatically without asking the user.
+ * <p>Example:
+ * <ul>
+ * <li>Service A registers AIDs "1", "2" and "3" in the category
+ * <li>Service B registers AIDs "3" and "4" in the category
+ * <li>Service C registers AIDs "5" and "6" in the category
+ * </ul>
+ * In this case, the following will happen when service A
+ * is the default:
+ * <ul>
+ * <li>Reader selects AID "1", "2" or "3": service A is invoked automatically
+ * <li>Reader selects AID "4": the user is asked to confirm he
+ * wants to use service B, because its AIDs overlap with service A.
+ * <li>Reader selects AID "5" or "6": service C is invoked automatically,
+ * because all AIDs it has asked for are only registered by C,
+ * and there is no overlap.
+ * </ul>
+ *
+ */
+ public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
/**
- * @hide
+ * Return value for {@link #getSelectionModeForCategory(String)}.
+ *
+ * <p>In this mode, whenever an AID of this category is selected,
+ * the user is asked which service he wants to use to handle
+ * the transaction, even if there is only one matching service.
*/
- public static final String PAYMENT_MODE_AUTO = "auto";
+ public static final int SELECTION_MODE_ALWAYS_ASK = 1;
/**
- * @hide
+ * Return value for {@link #getSelectionModeForCategory(String)}.
+ *
+ * <p>In this mode, the user will only be asked to select a service
+ * if the selected AID has been registered by multiple applications.
*/
- public static final String PAYMENT_MODE_MANUAL = "manual";
+ public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
+
+ static boolean sIsInitialized = false;
+ static HashMap<Context, CardEmulationManager> sCardEmuManagers = new HashMap();
+ static INfcCardEmulation sService;
final Context mContext;
@@ -113,7 +163,7 @@ public final class CardEmulationManager {
throw new UnsupportedOperationException();
}
try {
- if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HCE)) {
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
Log.e(TAG, "This device does not support card emulation");
throw new UnsupportedOperationException();
}
@@ -137,6 +187,10 @@ public final class CardEmulationManager {
* Allows an application to query whether a service is currently
* the default service to handle a card emulation category.
*
+ * <p>Note that if {@link #getSelectionModeForCategory(String)}
+ * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always
+ * return false.
+ *
* @param service The ComponentName of the service
* @param category The category
* @return whether service is currently the default service for the category.
@@ -147,6 +201,10 @@ public final class CardEmulationManager {
} catch (RemoteException e) {
// Try one more time
recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
try {
return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service,
category);
@@ -186,6 +244,33 @@ public final class CardEmulationManager {
}
/**
+ * Returns the application selection mode for the passed in category.
+ * Valid return values are:
+ * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
+ * application for this category, which will be preferred.
+ * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
+ * every time what app he would like to use in this category.
+ * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
+ * to pick a service if there is a conflict.
+ * @param category The category, for example {@link #CATEGORY_PAYMENT}
+ * @return
+ */
+ public int getSelectionModeForCategory(String category) {
+ if (CATEGORY_PAYMENT.equals(category)) {
+ String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
+ if (defaultComponent != null) {
+ return SELECTION_MODE_PREFER_DEFAULT;
+ } else {
+ return SELECTION_MODE_ALWAYS_ASK;
+ }
+ } else {
+ // All other categories are in "only ask if conflict" mode
+ return SELECTION_MODE_ASK_IF_CONFLICT;
+ }
+ }
+
+ /**
* @hide
*/
public boolean setDefaultServiceForCategory(ComponentName service, String category) {
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
index cdc4adb..ae94b2f 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -4,13 +4,11 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.content.Intent;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
-import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 3bfd9a1..fb6bb2e 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -41,7 +41,9 @@ interface IPrintManager {
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
in List<PrinterId> priorityList, int userId);
void stopPrinterDiscovery(in IPrinterDiscoveryObserver observer, int userId);
- void requestPrinterUpdate(in PrinterId printerId, int userId);
+ void validatePrinters(in List<PrinterId> printerIds, int userId);
+ void startPrinterStateTracking(in PrinterId printerId, int userId);
+ void stopPrinterStateTracking(in PrinterId printerId, int userId);
void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer,
int userId);
}
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index 8a64e85..33b4aad 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -18,8 +18,8 @@ package android.print;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
-import java.io.FileDescriptor;
import java.util.List;
/**
@@ -41,7 +41,7 @@ import java.util.List;
* <li>
* After every call to {@link #onLayout(PrintAttributes, PrintAttributes,
* CancellationSignal, LayoutResultCallback, Bundle)}, you may get a call to
- * {@link #onWrite(PageRange[], FileDescriptor, CancellationSignal, WriteResultCallback)}
+ * {@link #onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal, WriteResultCallback)}
* asking you to write a PDF file with the content for specific pages.
* </li>
* <li>
@@ -64,7 +64,7 @@ import java.util.List;
* PrintAttributes, CancellationSignal, LayoutResultCallback, Bundle)} on
* the UI thread (assuming onStart initializes resources needed for layout).
* This will ensure that the UI does not change while you are laying out the
- * printed content. Then you can handle {@link #onWrite(PageRange[], FileDescriptor,
+ * printed content. Then you can handle {@link #onWrite(PageRange[], ParcelFileDescriptor,
* CancellationSignal, WriteResultCallback)} and {@link #onFinish()} on another
* thread. This will ensure that the UI is frozen for the minimal amount of
* time. Also this assumes that you will generate the printed content in
@@ -150,10 +150,10 @@ public abstract class PrintDocumentAdapter {
* from of a PDF file to the given file descriptor. This method is invoked
* on the main thread.
*<p>
- * After you are done writing, you should <strong>not</strong> close the
- * file descriptor, rather you must invoke: {@link WriteResultCallback
- * #onWriteFinished(List)}, if writing completed successfully; or {@link
- * WriteResultCallback#onWriteFailed(CharSequence)}, if an error occurred.
+ * After you are done writing, you should close the file descriptor and
+ * invoke {@link WriteResultCallback #onWriteFinished(List)}, if writing
+ * completed successfully; or {@link WriteResultCallback#onWriteFailed(
+ * CharSequence)}, if an error occurred.
* </p>
* <p>
* <strong>Note:</strong> If the printed content is large, it is a good
@@ -171,7 +171,7 @@ public abstract class PrintDocumentAdapter {
* @see WriteResultCallback
* @see CancellationSignal
*/
- public abstract void onWrite(PageRange[] pages, FileDescriptor destination,
+ public abstract void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
CancellationSignal cancellationSignal, WriteResultCallback callback);
/**
@@ -185,7 +185,7 @@ public abstract class PrintDocumentAdapter {
/**
* Base class for implementing a callback for the result of {@link
- * PrintDocumentAdapter#onWrite(PageRange[], FileDescriptor, CancellationSignal,
+ * PrintDocumentAdapter#onWrite(PageRange[], ParcelFileDescriptor, CancellationSignal,
* WriteResultCallback)}.
*/
public static abstract class WriteResultCallback {
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index b32961b..f2b91ae 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -60,6 +60,7 @@ public final class PrintDocumentInfo implements Parcelable {
private int mColorMode;
private Margins mMargins;
private MediaSize mMediaSize;
+ private long mDataSize;
/**
* Creates a new instance.
@@ -82,6 +83,7 @@ public final class PrintDocumentInfo implements Parcelable {
mColorMode = prototype.mColorMode;
mMargins = prototype.mMargins;
mMediaSize = prototype.mMediaSize;
+ mDataSize = prototype.mDataSize;
}
/**
@@ -98,6 +100,7 @@ public final class PrintDocumentInfo implements Parcelable {
mColorMode = parcel.readInt();
mMargins = Margins.createFromParcel(parcel);
mMediaSize = MediaSize.createFromParcel(parcel);
+ mDataSize = parcel.readLong();
}
/**
@@ -188,6 +191,26 @@ public final class PrintDocumentInfo implements Parcelable {
return mMediaSize;
}
+ /**
+ * Gets the document data size in bytes.
+ *
+ * @return The data size.
+ */
+ public long getDataSize() {
+ return mDataSize;
+ }
+
+ /**
+ * Sets the document data size in bytes.
+ *
+ * @param dataSize The data size.
+ *
+ * @hide
+ */
+ public void setDataSize(long dataSize) {
+ mDataSize = dataSize;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -203,6 +226,7 @@ public final class PrintDocumentInfo implements Parcelable {
parcel.writeInt(mColorMode);
mMargins.writeToParcel(parcel);
mMediaSize.writeToParcel(parcel);
+ parcel.writeLong(mDataSize);
}
@Override
@@ -217,6 +241,8 @@ public final class PrintDocumentInfo implements Parcelable {
result = prime * result + mColorMode;
result = prime * result + (mMargins != null ? mMargins.hashCode() : 0);
result = prime * result + (mMediaSize != null ? mMediaSize.hashCode() : 0);
+ result = prime * result + (int) mDataSize;
+ result = prime * result + (int) mDataSize >> 32;
return result;
}
@@ -264,6 +290,9 @@ public final class PrintDocumentInfo implements Parcelable {
} else if (!mMediaSize.equals(other.mMediaSize)) {
return false;
}
+ if (mDataSize != other.mDataSize) {
+ return false;
+ }
return true;
}
@@ -279,6 +308,7 @@ public final class PrintDocumentInfo implements Parcelable {
builder.append(", colorMode=").append(PrintAttributes.colorModeToString(mColorMode));
builder.append(", margins=").append(mMargins);
builder.append(", mediaSize=").append(mMediaSize);
+ builder.append(", size=").append(mDataSize);
builder.append("}");
return builder.toString();
}
diff --git a/core/java/android/print/PrintFileDocumentAdapter.java b/core/java/android/print/PrintFileDocumentAdapter.java
index dbc8b6f..b905396 100644
--- a/core/java/android/print/PrintFileDocumentAdapter.java
+++ b/core/java/android/print/PrintFileDocumentAdapter.java
@@ -21,6 +21,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
+import android.os.ParcelFileDescriptor;
import android.util.Log;
import com.android.internal.R;
@@ -28,7 +29,6 @@ import com.android.internal.R;
import libcore.io.IoUtils;
import java.io.File;
-import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -81,7 +81,7 @@ public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
}
@Override
- public void onWrite(PageRange[] pages, FileDescriptor destination,
+ public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
CancellationSignal cancellationSignal, WriteResultCallback callback) {
mWriteFileAsyncTask = new WriteFileAsyncTask(destination, cancellationSignal, callback);
mWriteFileAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
@@ -90,13 +90,13 @@ public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
private final class WriteFileAsyncTask extends AsyncTask<Void, Void, Void> {
- private final FileDescriptor mDestination;
+ private final ParcelFileDescriptor mDestination;
private final WriteResultCallback mResultCallback;
private final CancellationSignal mCancellationSignal;
- public WriteFileAsyncTask(FileDescriptor destination,
+ public WriteFileAsyncTask(ParcelFileDescriptor destination,
CancellationSignal cancellationSignal, WriteResultCallback callback) {
mDestination = destination;
mResultCallback = callback;
@@ -112,7 +112,7 @@ public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
@Override
protected Void doInBackground(Void... params) {
InputStream in = null;
- OutputStream out = new FileOutputStream(mDestination);
+ OutputStream out = new FileOutputStream(mDestination.getFileDescriptor());
final byte[] buffer = new byte[8192];
try {
in = new FileInputStream(mFile);
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 602f3c1..b919ad6 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -44,6 +44,13 @@ public final class PrintJobInfo implements Parcelable {
public static final int STATE_ANY_VISIBLE_TO_CLIENTS = -2;
/**
+ * Constant for matching any active print job state.
+ *
+ * @hide
+ */
+ public static final int STATE_ANY_ACTIVE = -3;
+
+ /**
* Print job state: The print job is being created but not yet
* ready to be printed.
* <p>
@@ -55,7 +62,7 @@ public final class PrintJobInfo implements Parcelable {
public static final int STATE_CREATED = 1;
/**
- * Print job status: The print jobs is created, it is ready
+ * Print job state: The print jobs is created, it is ready
* to be printed and should be processed.
* <p>
* Next valid states: {@link #STATE_STARTED}, {@link #STATE_FAILED},
@@ -65,40 +72,49 @@ public final class PrintJobInfo implements Parcelable {
public static final int STATE_QUEUED = 2;
/**
- * Print job status: The print job is being printed.
+ * Print job state: The print job is being printed.
* <p>
* Next valid states: {@link #STATE_COMPLETED}, {@link #STATE_FAILED},
- * {@link #STATE_CANCELED}
+ * {@link #STATE_CANCELED}, {@link #STATE_BLOCKED}
* </p>
*/
public static final int STATE_STARTED = 3;
/**
- * Print job status: The print job was successfully printed.
+ * Print job state: The print job is blocked.
+ * <p>
+ * Next valid states: {@link #STATE_FAILED}, {@link #STATE_CANCELED},
+ * {@link #STATE_STARTED}
+ * </p>
+ */
+ public static final int STATE_BLOCKED = 4;
+
+ /**
+ * Print job state: The print job was successfully printed.
* This is a terminal state.
* <p>
* Next valid states: None
* </p>
*/
- public static final int STATE_COMPLETED = 4;
+ public static final int STATE_COMPLETED = 5;
/**
- * Print job status: The print job was printing but printing failed.
+ * Print job state: The print job was printing but printing failed.
* This is a terminal state.
* <p>
* Next valid states: None
* </p>
*/
- public static final int STATE_FAILED = 5;
+ public static final int STATE_FAILED = 6;
/**
- * Print job status: The print job was canceled.
+ * Print job state: The print job was canceled.
* This is a terminal state.
* <p>
* Next valid states: None
* </p>
*/
- public static final int STATE_CANCELED = 6;
+ public static final int STATE_CANCELED = 7;
/** The unique print job id. */
private int mId;
@@ -127,8 +143,8 @@ public final class PrintJobInfo implements Parcelable {
/** How many copies to print. */
private int mCopies;
- /** Failure reason if this job failed. */
- private String mFailureReason;
+ /** Reason for the print job being in its current state. */
+ private String mStateReason;
/** The pages to print */
private PageRange[] mPageRanges;
@@ -155,7 +171,7 @@ public final class PrintJobInfo implements Parcelable {
mUserId = other.mUserId;
mTag = other.mTag;
mCopies = other.mCopies;
- mFailureReason = other.mFailureReason;
+ mStateReason = other.mStateReason;
mPageRanges = other.mPageRanges;
mAttributes = other.mAttributes;
mDocumentInfo = other.mDocumentInfo;
@@ -171,7 +187,7 @@ public final class PrintJobInfo implements Parcelable {
mUserId = parcel.readInt();
mTag = parcel.readString();
mCopies = parcel.readInt();
- mFailureReason = parcel.readString();
+ mStateReason = parcel.readString();
if (parcel.readInt() == 1) {
Parcelable[] parcelables = parcel.readParcelableArray(null);
mPageRanges = new PageRange[parcelables.length];
@@ -377,25 +393,27 @@ public final class PrintJobInfo implements Parcelable {
}
/**
- * The failure reason if this print job failed.
+ * Gets the reason for the print job being in the current state.
*
- * @return The failure reason.
+ * @return The reason, or null if there is no reason or the
+ * reason is unknown.
*
* @hide
*/
- public String getFailureReason() {
- return mFailureReason;
+ public String getStateReason() {
+ return mStateReason;
}
/**
- * The failure reason if this print job failed.
+ * Sets the reason for the print job being in the current state.
*
- * @param failureReason The failure reason.
+ * @param stateReason The reason, or null if there is no reason
+ * or the reason is unknown.
*
* @hide
*/
- public void setFailureReason(String failureReason) {
- mFailureReason = failureReason;
+ public void setStateReason(String stateReason) {
+ mStateReason = stateReason;
}
/**
@@ -476,7 +494,7 @@ public final class PrintJobInfo implements Parcelable {
parcel.writeInt(mUserId);
parcel.writeString(mTag);
parcel.writeInt(mCopies);
- parcel.writeString(mFailureReason);
+ parcel.writeString(mStateReason);
if (mPageRanges != null) {
parcel.writeInt(1);
parcel.writeParcelableArray(mPageRanges, flags);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index d3e35c3..6e32c05 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -36,7 +36,6 @@ import com.android.internal.os.SomeArgs;
import libcore.io.IoUtils;
import java.io.File;
-import java.io.FileDescriptor;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
@@ -163,7 +162,7 @@ public final class PrintManager {
* @param pdfFile The PDF file to print.
* @param documentInfo Information about the printed document.
* @param attributes The default print job attributes.
- * @return The created print job.
+ * @return The created print job on success or null on failure.
*
* @see PrintJob
*/
@@ -181,7 +180,7 @@ public final class PrintManager {
* @param printJobName A name for the new print job.
* @param documentAdapter An adapter that emits the document to print.
* @param attributes The default print job attributes.
- * @return The created print job.
+ * @return The created print job on success or null on failure.
*
* @see PrintJob
*/
@@ -279,7 +278,7 @@ public final class PrintManager {
}
SomeArgs args = SomeArgs.obtain();
args.arg1 = pages;
- args.arg2 = fd.getFileDescriptor();
+ args.arg2 = fd;
args.arg3 = callback;
args.argi1 = sequence;
mHandler.removeMessages(MyHandler.MSG_WRITE);
@@ -342,7 +341,7 @@ public final class PrintManager {
case MSG_WRITE: {
SomeArgs args = (SomeArgs) message.obj;
PageRange[] pages = (PageRange[]) args.arg1;
- FileDescriptor fd = (FileDescriptor) args.arg2;
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args.arg2;
IWriteResultCallback callback = (IWriteResultCallback) args.arg3;
final int sequence = args.argi1;
args.recycle();
@@ -428,12 +427,12 @@ public final class PrintManager {
}
private final class MyWriteResultCallback extends WriteResultCallback {
- private FileDescriptor mFd;
+ private ParcelFileDescriptor mFd;
private int mSequence;
private IWriteResultCallback mCallback;
public MyWriteResultCallback(IWriteResultCallback callback,
- FileDescriptor fd, int sequence) {
+ ParcelFileDescriptor fd, int sequence) {
mFd = fd;
mSequence = sequence;
mCallback = callback;
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index 8fbdd9c..46f0bef 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -74,6 +74,7 @@ public final class PrinterDiscoverySession {
public final void startPrinterDisovery(List<PrinterId> priorityList) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring start printers dsicovery - session destroyed");
+ return;
}
if (!mIsPrinterDiscoveryStarted) {
mIsPrinterDiscoveryStarted = true;
@@ -88,6 +89,7 @@ public final class PrinterDiscoverySession {
public final void stopPrinterDiscovery() {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
+ return;
}
if (mIsPrinterDiscoveryStarted) {
mIsPrinterDiscoveryStarted = false;
@@ -99,14 +101,39 @@ public final class PrinterDiscoverySession {
}
}
- public final void requestPrinterUpdate(PrinterId printerId) {
+ public final void startPrinterStateTracking(PrinterId printerId) {
+ if (isDestroyed()) {
+ Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
+ return;
+ }
+ try {
+ mPrintManager.startPrinterStateTracking(printerId, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error starting printer state tracking", re);
+ }
+ }
+
+ public final void stopPrinterStateTracking(PrinterId printerId) {
if (isDestroyed()) {
- Log.w(LOG_TAG, "Ignoring reqeust printer update - session destroyed");
+ Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
+ return;
+ }
+ try {
+ mPrintManager.stopPrinterStateTracking(printerId, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error stoping printer state tracking", re);
+ }
+ }
+
+ public final void validatePrinters(List<PrinterId> printerIds) {
+ if (isDestroyed()) {
+ Log.w(LOG_TAG, "Ignoring validate printers - session destroyed");
+ return;
}
try {
- mPrintManager.requestPrinterUpdate(printerId, mUserId);
+ mPrintManager.validatePrinters(printerIds, mUserId);
} catch (RemoteException re) {
- Log.e(LOG_TAG, "Error requesting printer update", re);
+ Log.e(LOG_TAG, "Error validating printers", re);
}
}
diff --git a/core/java/android/print/pdf/PrintedPdfDocument.java b/core/java/android/print/pdf/PrintedPdfDocument.java
index a3be38b..bee17ef 100644
--- a/core/java/android/print/pdf/PrintedPdfDocument.java
+++ b/core/java/android/print/pdf/PrintedPdfDocument.java
@@ -111,7 +111,10 @@ public final class PrintedPdfDocument {
* @see #finishPage(Page)
*/
public Page startPage(int pageNumber) {
- PageInfo pageInfo = new PageInfo.Builder(mPageSize, 0).create();
+ PageInfo pageInfo = new PageInfo
+ .Builder(mPageSize, 0)
+ .setContentSize(mContentSize)
+ .create();
Page page = mDocument.startPage(pageInfo);
return page;
}
diff --git a/core/java/android/printservice/IPrintService.aidl b/core/java/android/printservice/IPrintService.aidl
index 2cee1d8..ee36619 100644
--- a/core/java/android/printservice/IPrintService.aidl
+++ b/core/java/android/printservice/IPrintService.aidl
@@ -33,6 +33,8 @@ oneway interface IPrintService {
void createPrinterDiscoverySession();
void startPrinterDiscovery(in List<PrinterId> priorityList);
void stopPrinterDiscovery();
- void requestPrinterUpdate(in PrinterId printerId);
+ void validatePrinters(in List<PrinterId> printerIds);
+ void startPrinterStateTracking(in PrinterId printerId);
+ void stopPrinterStateTracking(in PrinterId printerId);
void destroyPrinterDiscoverySession();
}
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
index 7437dc5..8292cfb 100644
--- a/core/java/android/printservice/PrintDocument.java
+++ b/core/java/android/printservice/PrintDocument.java
@@ -21,12 +21,15 @@ import android.os.RemoteException;
import android.print.PrintDocumentInfo;
import android.util.Log;
-import java.io.FileDescriptor;
import java.io.IOException;
/**
* This class represents a printed document from the perspective of a print
* service. It exposes APIs to query the document and obtain its data.
+ * <p>
+ * <strong>Note: </strong> All methods of this class must be executed on the
+ * main application thread.
+ * </p>
*/
public final class PrintDocument {
@@ -51,6 +54,7 @@ public final class PrintDocument {
* @return The document info.
*/
public PrintDocumentInfo getInfo() {
+ PrintService.throwIfNotCalledOnMainThread();
return mInfo;
}
@@ -64,7 +68,8 @@ public final class PrintDocument {
*
* @return A file descriptor for reading the data.
*/
- public FileDescriptor getData() {
+ public ParcelFileDescriptor getData() {
+ PrintService.throwIfNotCalledOnMainThread();
ParcelFileDescriptor source = null;
ParcelFileDescriptor sink = null;
try {
@@ -72,7 +77,7 @@ public final class PrintDocument {
source = fds[0];
sink = fds[1];
mPrintServiceClient.writePrintJobData(sink, mPrintJobId);
- return source.getFileDescriptor();
+ return source;
} catch (IOException ioe) {
Log.e(LOG_TAG, "Error calling getting print job data!", ioe);
} catch (RemoteException re) {
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index d2fbef2..8bae9d6 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -18,6 +18,7 @@ package android.printservice;
import android.os.RemoteException;
import android.print.PrintJobInfo;
+import android.text.TextUtils;
import android.util.Log;
/**
@@ -123,6 +124,21 @@ public final class PrintJob {
}
/**
+ * Gets whether this print job is blocked. Such a print job is halted
+ * due to an abnormal condition and can be started or canceled or failed.
+ *
+ * @return Whether the print job is blocked.
+ *
+ * @see #start()
+ * @see #cancel()
+ * @see #fail(CharSequence)
+ */
+ public boolean isBlocked() {
+ PrintService.throwIfNotCalledOnMainThread();
+ return getInfo().getState() == PrintJobInfo.STATE_BLOCKED;
+ }
+
+ /**
* Gets whether this print job is completed. Such a print job
* is successfully printed. This is a final state.
*
@@ -163,21 +179,49 @@ public final class PrintJob {
/**
* Starts the print job. You should call this method if {@link
- * #isQueued()} returns true and you started printing.
+ * #isQueued()} or {@link #isBlocked()} returns true and you started
+ * resumed printing.
*
- * @return Whether the job as started.
+ * @return Whether the job was started.
*
* @see #isQueued()
+ * @see #isBlocked()
*/
public boolean start() {
PrintService.throwIfNotCalledOnMainThread();
- if (isQueued()) {
+ final int state = getInfo().getState();
+ if (state == PrintJobInfo.STATE_QUEUED
+ || state == PrintJobInfo.STATE_BLOCKED) {
return setState(PrintJobInfo.STATE_STARTED, null);
}
return false;
}
/**
+ * Blocks the print job. You should call this method if {@link
+ * #isStarted()} or {@link #isBlocked()} returns true and you need
+ * to block the print job. For example, the user has to add some
+ * paper to continue printing. To resume the print job call {@link
+ * #start()}.
+ *
+ * @return Whether the job was blocked.
+ *
+ * @see #isStarted()
+ * @see #isBlocked()
+ */
+ public boolean block(String reason) {
+ PrintService.throwIfNotCalledOnMainThread();
+ PrintJobInfo info = getInfo();
+ final int state = info.getState();
+ if (state == PrintJobInfo.STATE_STARTED
+ || (state == PrintJobInfo.STATE_BLOCKED
+ && !TextUtils.equals(info.getStateReason(), reason))) {
+ return setState(PrintJobInfo.STATE_BLOCKED, reason);
+ }
+ return false;
+ }
+
+ /**
* Completes the print job. You should call this method if {@link
* #isStarted()} returns true and you are done printing.
*
@@ -195,8 +239,8 @@ public final class PrintJob {
/**
* Fails the print job. You should call this method if {@link
- * #isQueued()} or {@link #isStarted()} returns true you failed
- * while printing.
+ * #isQueued()} or {@link #isStarted()} or {@link #isBlocked()}
+ * returns true you failed while printing.
*
* @param error The human readable, short, and translated reason
* for the failure.
@@ -204,10 +248,11 @@ public final class PrintJob {
*
* @see #isQueued()
* @see #isStarted()
+ * @see #isBlocked()
*/
public boolean fail(String error) {
PrintService.throwIfNotCalledOnMainThread();
- if (isQueued() || isStarted()) {
+ if (!isInImmutableState()) {
return setState(PrintJobInfo.STATE_FAILED, error);
}
return false;
@@ -215,18 +260,19 @@ public final class PrintJob {
/**
* Cancels the print job. You should call this method if {@link
- * #isQueued()} or {@link #isStarted()} returns true and you canceled
- * the print job as a response to a call to {@link
- * PrintService#onRequestCancelPrintJob(PrintJob)}.
+ * #isQueued()} or {@link #isStarted() or #isBlocked()} returns
+ * true and you canceled the print job as a response to a call to
+ * {@link PrintService#onRequestCancelPrintJob(PrintJob)}.
*
* @return Whether the job is canceled.
*
* @see #isStarted()
* @see #isQueued()
+ * @see #isBlocked()
*/
public boolean cancel() {
PrintService.throwIfNotCalledOnMainThread();
- if (isQueued() || isStarted()) {
+ if (!isInImmutableState()) {
return setState(PrintJobInfo.STATE_CANCELED, null);
}
return false;
@@ -277,7 +323,8 @@ public final class PrintJob {
private boolean isInImmutableState() {
final int state = mCachedInfo.getState();
return state == PrintJobInfo.STATE_COMPLETED
- || state == PrintJobInfo.STATE_CANCELED;
+ || state == PrintJobInfo.STATE_CANCELED
+ || state == PrintJobInfo.STATE_FAILED;
}
private boolean setState(int state, String error) {
@@ -287,7 +334,7 @@ public final class PrintJob {
// we may not be able to re-fetch it later if the job gets
// removed from the spooler as a result of the state change.
mCachedInfo.setState(state);
- mCachedInfo.setFailureReason(error);
+ mCachedInfo.setStateReason(error);
return true;
}
} catch (RemoteException re) {
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index f6c0a9a..96552af 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -314,8 +314,20 @@ public abstract class PrintService extends Service {
}
@Override
- public void requestPrinterUpdate(PrinterId printerId) {
- mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_PRINTER_UPDATE,
+ public void validatePrinters(List<PrinterId> printerIds) {
+ mHandler.obtainMessage(ServiceHandler.MSG_VALIDATE_PRINTERS,
+ printerIds).sendToTarget();
+ }
+
+ @Override
+ public void startPrinterStateTracking(PrinterId printerId) {
+ mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_STATE_TRACKING,
+ printerId).sendToTarget();
+ }
+
+ @Override
+ public void stopPrinterStateTracking(PrinterId printerId) {
+ mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
printerId).sendToTarget();
}
@@ -344,10 +356,12 @@ public abstract class PrintService extends Service {
public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
public static final int MSG_START_PRINTER_DISCOVERY = 3;
public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
- public static final int MSG_REQUEST_PRINTER_UPDATE = 5;
- public static final int MSG_ON_PRINTJOB_QUEUED = 6;
- public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 7;
- public static final int MSG_SET_CLEINT = 8;
+ public static final int MSG_VALIDATE_PRINTERS = 5;
+ public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
+ public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
+ public static final int MSG_ON_PRINTJOB_QUEUED = 8;
+ public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
+ public static final int MSG_SET_CLEINT = 10;
public ServiceHandler(Looper looper) {
super(looper, null, true);
@@ -391,10 +405,24 @@ public abstract class PrintService extends Service {
}
} break;
- case MSG_REQUEST_PRINTER_UPDATE: {
+ case MSG_VALIDATE_PRINTERS: {
+ if (mDiscoverySession != null) {
+ List<PrinterId> printerIds = (List<PrinterId>) message.obj;
+ mDiscoverySession.validatePrinters(printerIds);
+ }
+ } break;
+
+ case MSG_START_PRINTER_STATE_TRACKING: {
+ if (mDiscoverySession != null) {
+ PrinterId printerId = (PrinterId) message.obj;
+ mDiscoverySession.startPrinterStateTracking(printerId);
+ }
+ } break;
+
+ case MSG_STOP_PRINTER_STATE_TRACKING: {
if (mDiscoverySession != null) {
PrinterId printerId = (PrinterId) message.obj;
- mDiscoverySession.requestPrinterUpdate(printerId);
+ mDiscoverySession.stopPrinterStateTracking(printerId);
}
} break;
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 8b959a6..1f86ecc 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -53,15 +53,23 @@ import java.util.List;
* session. Printers are <strong>not</strong> persisted across sessions.
* </p>
* <p>
- * The system will make a call to
- * {@link PrinterDiscoverySession#onRequestPrinterUpdate(PrinterId)} if you
- * need to update a given printer. It is possible that you add a printer without
+ * The system will make a call to {@link #onValidatePrinters(List)} if you
+ * need to update some printers. It is possible that you add a printer without
* specifying its capabilities. This enables you to avoid querying all discovered
* printers for their capabilities, rather querying the capabilities of a printer
* only if necessary. For example, the system will request that you update a printer
- * if it gets selected by the user. If you did not report the printer capabilities
- * when adding it, you must do so after the system requests a printer update.
- * Otherwise, the printer will be ignored.
+ * if it gets selected by the user. When validating printers you do not need to
+ * provide the printers' capabilities but may do so.
+ * </p>
+ * <p>
+ * If the system is interested in being constantly updated for the state of a
+ * printer you will receive a call to {@link #onStartPrinterStateTracking(PrinterId)}
+ * after which you will have to do a best effort to keep the system updated for
+ * changes in the printer state and capabilities. You also <strong>must</strong>
+ * update the printer capabilities if you did not provide them when adding it, or
+ * the printer will be ignored. When the system is no longer interested in getting
+ * updates for a printer you will receive a call to {@link #onStopPrinterStateTracking(
+ * PrinterId)}.
* </p>
* <p>
* <strong>Note: </strong> All callbacks in this class are executed on the main
@@ -115,7 +123,7 @@ public abstract class PrinterDiscoverySession {
* the printer that was added but not removed.
* <p>
* <strong>Note: </strong> Calls to this method after the session is
- * destroyed, i.e. after the {@link #onDestroy()} callback, will be ignored.
+ * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
* </p>
*
* @return The printers.
@@ -139,7 +147,7 @@ public abstract class PrinterDiscoverySession {
* times during the life of this session. Duplicates will be ignored.
* <p>
* <strong>Note: </strong> Calls to this method after the session is
- * destroyed, i.e. after the {@link #onDestroy()} callback, will be ignored.
+ * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
* </p>
*
* @param printers The printers to add.
@@ -218,7 +226,7 @@ public abstract class PrinterDiscoverySession {
* call this method multiple times during the lifetime of this session.
* <p>
* <strong>Note: </strong> Calls to this method after the session is
- * destroyed, i.e. after the {@link #onDestroy()} callback, will be ignored.
+ * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
* </p>
*
* @param printerIds The ids of the removed printers.
@@ -293,7 +301,7 @@ public abstract class PrinterDiscoverySession {
* during the lifetime of this session.
* <p>
* <strong>Note: </strong> Calls to this method after the session is
- * destroyed, i.e. after the {@link #onDestroy()} callback, will be ignored.
+ * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
* </p>
*
* @param printers The printers to update.
@@ -441,7 +449,9 @@ public abstract class PrinterDiscoverySession {
* <p>
* <strong>Note: </strong>You are also given a list of printers whose availability
* has to be checked first. For example, these printers could be the user's favorite
- * ones, therefore they have to be verified first.
+ * ones, therefore they have to be verified first. You do <strong>not need</strong>
+ * to provide the capabilities of the printers, rather verify whether they exist
+ * similarly to {@link #onValidatePrinters(List)}.
* </p>
*
* @param priorityList The list of printers to validate first. Never null.
@@ -463,9 +473,28 @@ public abstract class PrinterDiscoverySession {
public abstract void onStopPrinterDiscovery();
/**
- * Requests that you update a printer. You are responsible for updating
- * the printer by also reporting its capabilities via calling {@link
- * #updatePrinters(List)}.
+ * Callback asking you to validate that the given printers are valid, that
+ * is they exist. You are responsible for checking whether these printers
+ * exist and for the ones that do exist notify the system via calling
+ * {@link #updatePrinters(List)}.
+ * <p>
+ * <strong>Note: </strong> You are <strong>not required</strong> to provide
+ * the printer capabilities when updating the printers that do exist.
+ * <p>
+ *
+ * @param printerIds The printers to validate.
+ *
+ * @see #updatePrinters(List)
+ * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+ * PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
+ */
+ public abstract void onValidatePrinters(List<PrinterId> printerIds);
+
+ /**
+ * Callback asking you to start tracking the state of a printer. Tracking
+ * the state means that you should do a best effort to observe the state
+ * of this printer and notify the system if that state changes via calling
+ * {@link #updatePrinters(List)}.
* <p>
* <strong>Note: </strong> A printer can be initially added without its
* capabilities to avoid polling printers that the user will not select.
@@ -473,18 +502,33 @@ public abstract class PrinterDiscoverySession {
* printer <strong>including</strong> its capabilities. Otherwise, the
* printer will be ignored.
* <p>
- * A scenario when you may be requested to update a printer is if the user
- * selects it and the system has to present print options UI based on the
- * printer's capabilities.
+ * <p>
+ * A scenario when you may be requested to track a printer's state is if
+ * the user selects that printer and the system has to present print
+ * options UI based on the printer's capabilities. In this case the user
+ * should be promptly informed if, for example, the printer becomes
+ * unavailable.
* </p>
*
- * @param printerId The printer id.
+ * @param printerId The printer to start tracking.
*
+ * @see #onStopPrinterStateTracking(PrinterId)
* @see #updatePrinters(List)
* @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
*/
- public abstract void onRequestPrinterUpdate(PrinterId printerId);
+ public abstract void onStartPrinterStateTracking(PrinterId printerId);
+
+ /**
+ * Callback asking you to stop tracking the state of a printer. The passed
+ * in printer id is the one for which you received a call to {@link
+ * #onStartPrinterStateTracking(PrinterId)}.
+ *
+ * @param printerId The printer to stop tracking.
+ *
+ * @see #onStartPrinterStateTracking(PrinterId)
+ */
+ public abstract void onStopPrinterStateTracking(PrinterId printerId);
/**
* Notifies you that the session is destroyed. After this callback is invoked
@@ -538,9 +582,21 @@ public abstract class PrinterDiscoverySession {
}
}
- void requestPrinterUpdate(PrinterId printerId) {
- if (!mIsDestroyed) {
- onRequestPrinterUpdate(printerId);
+ void validatePrinters(List<PrinterId> printerIds) {
+ if (!mIsDestroyed && mObserver != null) {
+ onValidatePrinters(printerIds);
+ }
+ }
+
+ void startPrinterStateTracking(PrinterId printerId) {
+ if (!mIsDestroyed && mObserver != null) {
+ onStartPrinterStateTracking(printerId);
+ }
+ }
+
+ void stopPrinterStateTracking(PrinterId printerId) {
+ if (!mIsDestroyed && mObserver != null) {
+ onStopPrinterStateTracking(printerId);
}
}
diff --git a/core/java/android/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java
index 5e56e934..724d76d 100644
--- a/core/java/android/provider/AlarmClock.java
+++ b/core/java/android/provider/AlarmClock.java
@@ -90,6 +90,15 @@ public final class AlarmClock {
public static final String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
/**
+ * Activity Action: Show the alarms.
+ * <p>
+ * This action opens the alarms page.
+ * </p>
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
+
+ /**
* Bundle extra: Weekdays for repeating alarm.
* <p>
* Used by {@link #ACTION_SET_ALARM}.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 24dbf0e..802bedf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4285,12 +4285,6 @@ public final class Settings {
public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
/**
- * Whether to automatically invoke NFC payment app or manually select on tap.
- * @hide
- */
- public static final String NFC_PAYMENT_MODE = "nfc_payment_mode";
-
- /**
* Name of a package that the current user has explicitly allowed to see all of that
* user's notifications.
*
diff --git a/core/java/android/util/LayoutDirection.java b/core/java/android/util/LayoutDirection.java
index e37d2f2..20af20b 100644
--- a/core/java/android/util/LayoutDirection.java
+++ b/core/java/android/util/LayoutDirection.java
@@ -17,11 +17,15 @@
package android.util;
/**
- * An interface for defining layout directions. A layout direction can be left-to-right (LTR)
+ * A class for defining layout directions. A layout direction can be left-to-right (LTR)
* or right-to-left (RTL). It can also be inherited (from a parent) or deduced from the default
* language script of a locale.
*/
-public interface LayoutDirection {
+public final class LayoutDirection {
+
+ // No instantiation
+ private LayoutDirection() {}
+
/**
* Horizontal layout direction is from Left to Right.
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 1b57d50..eded438 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -31,7 +31,9 @@ import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.StrictMode;
+import android.print.PrintAttributes;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
@@ -49,7 +51,6 @@ import android.widget.AbsoluteLayout;
import java.io.BufferedWriter;
import java.io.File;
-import java.io.OutputStream;
import java.util.Map;
/**
@@ -498,6 +499,8 @@ public class WebView extends AbsoluteLayout
ensureProviderCreated();
mProvider.init(javaScriptInterfaces, privateBrowsing);
+ // Post condition of creating a webview is the CookieSyncManager instance exists.
+ CookieSyncManager.createInstance(getContext());
}
/**
@@ -1040,7 +1043,9 @@ public class WebView extends AbsoluteLayout
* Exports the contents of this Webview as PDF. Only supported for API levels
* {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE} and above.
*
- * @param out The stream to export the PDF contents to. Cannot be null.
+ * TODO(sgurun) the parameter list is stale. Fix it before unhiding.
+ *
+ * @param fd The FileDescriptor to export the PDF contents to. Cannot be null.
* @param width The page width. Should be larger than 0.
* @param height The page height. Should be larger than 0.
* @param resultCallback A callback to be invoked when the PDF content is exported.
@@ -1049,21 +1054,26 @@ public class WebView extends AbsoluteLayout
* be null.
*
* The PDF conversion is done asynchronously and the PDF output is written to the provided
- * outputstream. The caller should not close the outputstream until the resultCallback is
- * called, indicating PDF conversion is complete. Webview cannot be drawn during the pdf
- * export so the application is recommended to take it offscreen, or putting in a layer
- * with an overlaid progress UI / spinner.
+ * file descriptor. The caller should not close the file descriptor until the resultCallback
+ * is called, indicating PDF conversion is complete. Webview will never close the file
+ * descriptor.
+ * Limitations: Webview cannot be drawn during the PDF export so the application is
+ * recommended to take it offscreen, or putting in a layer with an overlaid progress
+ * UI / spinner.
*
* If the caller cancels the task using the cancellationSignal, the cancellation will be
* acked using the resultCallback signal.
*
+ * Throws an exception if an IO error occurs accessing the file descriptor.
+ *
* TODO(sgurun) margins, explain the units, make it public.
* @hide
*/
- public void exportToPdf(OutputStream out, int width, int height,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal) {
+ public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes,
+ ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
+ throws java.io.IOException {
checkThread();
- mProvider.exportToPdf(out, width, height, resultCallback, cancellationSignal);
+ mProvider.exportToPdf(fd, attributes, resultCallback, cancellationSignal);
}
/**
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index db98d30..b1a7878 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -62,6 +62,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
+import android.print.PrintAttributes;
import android.security.KeyChain;
import android.text.Editable;
import android.text.InputType;
@@ -2896,11 +2897,11 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
* See {@link WebView#exportToPdf()}
*/
@Override
- public void exportToPdf(java.io.OutputStream out, int width, int height,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal) {
+ public void exportToPdf(android.os.ParcelFileDescriptor fd, PrintAttributes attributes,
+ ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
+ throws java.io.IOException {
// K-only API not implemented in WebViewClassic.
throw new IllegalStateException("This API not supported on Android 4.3 and earlier");
-
}
/**
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 8fe6edf..d625d8a 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -27,6 +27,8 @@ import android.net.http.SslCertificate;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.print.PrintAttributes;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -41,7 +43,6 @@ import android.webkit.WebView.PictureListener;
import java.io.BufferedWriter;
import java.io.File;
-import java.io.OutputStream;
import java.util.Map;
/**
@@ -148,8 +149,9 @@ public interface WebViewProvider {
public Picture capturePicture();
- public void exportToPdf(OutputStream out, int width, int height,
- ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal);
+ public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes,
+ ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
+ throws java.io.IOException;
public float getScale();
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 109fcfe..54cc3f4 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -251,14 +251,14 @@ public class GridLayout extends ViewGroup {
// Instance variables
- final Axis horizontalAxis = new Axis(true);
- final Axis verticalAxis = new Axis(false);
- int orientation = DEFAULT_ORIENTATION;
- boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
- int alignmentMode = DEFAULT_ALIGNMENT_MODE;
- int defaultGap;
- int lastLayoutParamsHashCode = UNINITIALIZED_HASH;
- Printer printer = LOG_PRINTER;
+ final Axis mHorizontalAxis = new Axis(true);
+ final Axis mVerticalAxis = new Axis(false);
+ int mOrientation = DEFAULT_ORIENTATION;
+ boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
+ int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
+ int mDefaultGap;
+ int mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
+ Printer mPrinter = LOG_PRINTER;
// Constructors
@@ -267,7 +267,7 @@ public class GridLayout extends ViewGroup {
*/
public GridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- defaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
+ mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
try {
setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
@@ -309,7 +309,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_orientation
*/
public int getOrientation() {
- return orientation;
+ return mOrientation;
}
/**
@@ -349,8 +349,8 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_orientation
*/
public void setOrientation(int orientation) {
- if (this.orientation != orientation) {
- this.orientation = orientation;
+ if (this.mOrientation != orientation) {
+ this.mOrientation = orientation;
invalidateStructure();
requestLayout();
}
@@ -369,7 +369,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_rowCount
*/
public int getRowCount() {
- return verticalAxis.getCount();
+ return mVerticalAxis.getCount();
}
/**
@@ -384,7 +384,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_rowCount
*/
public void setRowCount(int rowCount) {
- verticalAxis.setCount(rowCount);
+ mVerticalAxis.setCount(rowCount);
invalidateStructure();
requestLayout();
}
@@ -402,7 +402,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_columnCount
*/
public int getColumnCount() {
- return horizontalAxis.getCount();
+ return mHorizontalAxis.getCount();
}
/**
@@ -417,7 +417,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_columnCount
*/
public void setColumnCount(int columnCount) {
- horizontalAxis.setCount(columnCount);
+ mHorizontalAxis.setCount(columnCount);
invalidateStructure();
requestLayout();
}
@@ -433,7 +433,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_useDefaultMargins
*/
public boolean getUseDefaultMargins() {
- return useDefaultMargins;
+ return mUseDefaultMargins;
}
/**
@@ -463,7 +463,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_useDefaultMargins
*/
public void setUseDefaultMargins(boolean useDefaultMargins) {
- this.useDefaultMargins = useDefaultMargins;
+ this.mUseDefaultMargins = useDefaultMargins;
requestLayout();
}
@@ -480,7 +480,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_alignmentMode
*/
public int getAlignmentMode() {
- return alignmentMode;
+ return mAlignmentMode;
}
/**
@@ -499,7 +499,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_alignmentMode
*/
public void setAlignmentMode(int alignmentMode) {
- this.alignmentMode = alignmentMode;
+ this.mAlignmentMode = alignmentMode;
requestLayout();
}
@@ -514,7 +514,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_rowOrderPreserved
*/
public boolean isRowOrderPreserved() {
- return verticalAxis.isOrderPreserved();
+ return mVerticalAxis.isOrderPreserved();
}
/**
@@ -534,7 +534,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_rowOrderPreserved
*/
public void setRowOrderPreserved(boolean rowOrderPreserved) {
- verticalAxis.setOrderPreserved(rowOrderPreserved);
+ mVerticalAxis.setOrderPreserved(rowOrderPreserved);
invalidateStructure();
requestLayout();
}
@@ -550,7 +550,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_columnOrderPreserved
*/
public boolean isColumnOrderPreserved() {
- return horizontalAxis.isOrderPreserved();
+ return mHorizontalAxis.isOrderPreserved();
}
/**
@@ -570,7 +570,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_columnOrderPreserved
*/
public void setColumnOrderPreserved(boolean columnOrderPreserved) {
- horizontalAxis.setOrderPreserved(columnOrderPreserved);
+ mHorizontalAxis.setOrderPreserved(columnOrderPreserved);
invalidateStructure();
requestLayout();
}
@@ -581,9 +581,11 @@ public class GridLayout extends ViewGroup {
* @see #setPrinter(android.util.Printer)
*
* @return the printer associated with this view
+ *
+ * @hide
*/
public Printer getPrinter() {
- return printer;
+ return mPrinter;
}
/**
@@ -593,9 +595,11 @@ public class GridLayout extends ViewGroup {
* @param printer the printer associated with this layout
*
* @see #getPrinter()
+ *
+ * @hide
*/
public void setPrinter(Printer printer) {
- this.printer = (printer == null) ? NO_PRINTER : printer;
+ this.mPrinter = (printer == null) ? NO_PRINTER : printer;
}
// Static utility methods
@@ -643,7 +647,7 @@ public class GridLayout extends ViewGroup {
if (c.getClass() == Space.class) {
return 0;
}
- return defaultGap / 2;
+ return mDefaultGap / 2;
}
private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
@@ -651,11 +655,11 @@ public class GridLayout extends ViewGroup {
}
private int getDefaultMargin(View c, LayoutParams p, boolean horizontal, boolean leading) {
- if (!useDefaultMargins) {
+ if (!mUseDefaultMargins) {
return 0;
}
Spec spec = horizontal ? p.columnSpec : p.rowSpec;
- Axis axis = horizontal ? horizontalAxis : verticalAxis;
+ Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
Interval span = spec.span;
boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading;
boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount());
@@ -672,10 +676,10 @@ public class GridLayout extends ViewGroup {
}
private int getMargin(View view, boolean horizontal, boolean leading) {
- if (alignmentMode == ALIGN_MARGINS) {
+ if (mAlignmentMode == ALIGN_MARGINS) {
return getMargin1(view, horizontal, leading);
} else {
- Axis axis = horizontal ? horizontalAxis : verticalAxis;
+ Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
LayoutParams lp = getLayoutParams(view);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
@@ -722,8 +726,8 @@ public class GridLayout extends ViewGroup {
// install default indices for cells that don't define them
private void validateLayoutParams() {
- final boolean horizontal = (orientation == HORIZONTAL);
- final Axis axis = horizontal ? horizontalAxis : verticalAxis;
+ final boolean horizontal = (mOrientation == HORIZONTAL);
+ final Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0;
int major = 0;
@@ -779,9 +783,9 @@ public class GridLayout extends ViewGroup {
}
private void invalidateStructure() {
- lastLayoutParamsHashCode = UNINITIALIZED_HASH;
- horizontalAxis.invalidateStructure();
- verticalAxis.invalidateStructure();
+ mLastLayoutParamsHashCode = UNINITIALIZED_HASH;
+ mHorizontalAxis.invalidateStructure();
+ mVerticalAxis.invalidateStructure();
// This can end up being done twice. Better twice than not at all.
invalidateValues();
}
@@ -789,9 +793,9 @@ public class GridLayout extends ViewGroup {
private void invalidateValues() {
// Need null check because requestLayout() is called in View's initializer,
// before we are set up.
- if (horizontalAxis != null && verticalAxis != null) {
- horizontalAxis.invalidateValues();
- verticalAxis.invalidateValues();
+ if (mHorizontalAxis != null && mVerticalAxis != null) {
+ mHorizontalAxis.invalidateValues();
+ mVerticalAxis.invalidateValues();
}
}
@@ -822,7 +826,7 @@ public class GridLayout extends ViewGroup {
if (span.min != UNDEFINED && span.min < 0) {
handleInvalidParams(groupName + " indices must be positive");
}
- Axis axis = horizontal ? horizontalAxis : verticalAxis;
+ Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
int count = axis.definedCount;
if (count != UNDEFINED) {
if (span.max > count) {
@@ -908,7 +912,7 @@ public class GridLayout extends ViewGroup {
int right = getWidth() - getPaddingRight() - insets.right;
int bottom = getHeight() - getPaddingBottom() - insets.bottom;
- int[] xs = horizontalAxis.locations;
+ int[] xs = mHorizontalAxis.locations;
if (xs != null) {
for (int i = 0, length = xs.length; i < length; i++) {
int x = left + xs[i];
@@ -916,7 +920,7 @@ public class GridLayout extends ViewGroup {
}
}
- int[] ys = verticalAxis.locations;
+ int[] ys = mVerticalAxis.locations;
if (ys != null) {
for (int i = 0, length = ys.length; i < length; i++) {
int y = top + ys[i];
@@ -973,11 +977,11 @@ public class GridLayout extends ViewGroup {
}
private void consistencyCheck() {
- if (lastLayoutParamsHashCode == UNINITIALIZED_HASH) {
+ if (mLastLayoutParamsHashCode == UNINITIALIZED_HASH) {
validateLayoutParams();
- lastLayoutParamsHashCode = computeLayoutParamsHashCode();
- } else if (lastLayoutParamsHashCode != computeLayoutParamsHashCode()) {
- printer.println("The fields of some layout parameters were modified in between "
+ mLastLayoutParamsHashCode = computeLayoutParamsHashCode();
+ } else if (mLastLayoutParamsHashCode != computeLayoutParamsHashCode()) {
+ mPrinter.println("The fields of some layout parameters were modified in between "
+ "layout operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
invalidateStructure();
consistencyCheck();
@@ -1005,11 +1009,11 @@ public class GridLayout extends ViewGroup {
if (firstPass) {
measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
} else {
- boolean horizontal = (orientation == HORIZONTAL);
+ boolean horizontal = (mOrientation == HORIZONTAL);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
if (spec.alignment == FILL) {
Interval span = spec.span;
- Axis axis = horizontal ? horizontalAxis : verticalAxis;
+ Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
int[] locations = axis.getLocations();
int cellSize = locations[span.max] - locations[span.min];
int viewSize = cellSize - getTotalMargin(c, horizontal);
@@ -1048,14 +1052,14 @@ public class GridLayout extends ViewGroup {
int heightSansPadding;
// Use the orientation property to decide which axis should be laid out first.
- if (orientation == HORIZONTAL) {
- widthSansPadding = horizontalAxis.getMeasure(widthSpecSansPadding);
+ if (mOrientation == HORIZONTAL) {
+ widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
- heightSansPadding = verticalAxis.getMeasure(heightSpecSansPadding);
+ heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
} else {
- heightSansPadding = verticalAxis.getMeasure(heightSpecSansPadding);
+ heightSansPadding = mVerticalAxis.getMeasure(heightSpecSansPadding);
measureChildrenWithMargins(widthSpecSansPadding, heightSpecSansPadding, false);
- widthSansPadding = horizontalAxis.getMeasure(widthSpecSansPadding);
+ widthSansPadding = mHorizontalAxis.getMeasure(widthSpecSansPadding);
}
int measuredWidth = Math.max(widthSansPadding + hPadding, getSuggestedMinimumWidth());
@@ -1114,11 +1118,11 @@ public class GridLayout extends ViewGroup {
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
- horizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
- verticalAxis.layout(targetHeight - paddingTop - paddingBottom);
+ mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
+ mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
- int[] hLocations = horizontalAxis.getLocations();
- int[] vLocations = verticalAxis.getLocations();
+ int[] hLocations = mHorizontalAxis.getLocations();
+ int[] vLocations = mVerticalAxis.getLocations();
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
@@ -1145,8 +1149,8 @@ public class GridLayout extends ViewGroup {
Alignment hAlign = getAlignment(columnSpec.alignment, true);
Alignment vAlign = getAlignment(rowSpec.alignment, false);
- Bounds boundsX = horizontalAxis.getGroupBounds().getValue(i);
- Bounds boundsY = verticalAxis.getGroupBounds().getValue(i);
+ Bounds boundsX = mHorizontalAxis.getGroupBounds().getValue(i);
+ Bounds boundsY = mVerticalAxis.getGroupBounds().getValue(i);
// Gravity offsets: the location of the alignment group relative to its cell group.
int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true));
@@ -1571,7 +1575,7 @@ public class GridLayout extends ViewGroup {
removed.add(arc);
}
}
- printer.println(axisName + " constraints: " + arcsToString(culprits) +
+ mPrinter.println(axisName + " constraints: " + arcsToString(culprits) +
" are inconsistent; permanently removing: " + arcsToString(removed) + ". ");
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index aa94728..ab81a37 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -22,11 +22,13 @@ import com.android.internal.content.PackageMonitor;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.LabeledIntent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -45,7 +47,6 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
-import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
@@ -71,13 +72,13 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
private PackageManager mPm;
private boolean mAlwaysUseOption;
private boolean mShowExtended;
- private GridView mGrid;
+ private ListView mListView;
private Button mAlwaysButton;
private Button mOnceButton;
private int mIconDpi;
private int mIconSize;
private int mMaxColumns;
- private int mLastSelected = GridView.INVALID_POSITION;
+ private int mLastSelected = ListView.INVALID_POSITION;
private boolean mRegistered;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -139,17 +140,15 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
finish();
return;
} else if (count > 1) {
- ap.mView = getLayoutInflater().inflate(R.layout.resolver_grid, null);
- mGrid = (GridView) ap.mView.findViewById(R.id.resolver_grid);
- mGrid.setAdapter(mAdapter);
- mGrid.setOnItemClickListener(this);
- mGrid.setOnItemLongClickListener(new ItemLongClickListener());
+ ap.mView = getLayoutInflater().inflate(R.layout.resolver_list, null);
+ mListView = (ListView) ap.mView.findViewById(R.id.resolver_list);
+ mListView.setAdapter(mAdapter);
+ mListView.setOnItemClickListener(this);
+ mListView.setOnItemLongClickListener(new ItemLongClickListener());
if (alwaysUseOption) {
- mGrid.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
-
- resizeGrid();
} else if (count == 1) {
startActivity(mAdapter.intentForPosition(0));
mPackageMonitor.unregister();
@@ -172,11 +171,11 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
mAlwaysUseOption = false;
}
}
- }
-
- void resizeGrid() {
- final int itemCount = mAdapter.getCount();
- mGrid.setNumColumns(Math.min(itemCount, mMaxColumns));
+ final int initialHighlight = mAdapter.getInitialHighlight();
+ if (initialHighlight >= 0) {
+ mListView.setItemChecked(initialHighlight, true);
+ onItemClick(null, null, initialHighlight, 0); // Other entries are not used
+ }
}
Drawable getIcon(Resources res, int resId) {
@@ -247,26 +246,26 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (mAlwaysUseOption) {
- final int checkedPos = mGrid.getCheckedItemPosition();
- final boolean enabled = checkedPos != GridView.INVALID_POSITION;
+ final int checkedPos = mListView.getCheckedItemPosition();
+ final boolean enabled = checkedPos != ListView.INVALID_POSITION;
mLastSelected = checkedPos;
mAlwaysButton.setEnabled(enabled);
mOnceButton.setEnabled(enabled);
if (enabled) {
- mGrid.setSelection(checkedPos);
+ mListView.setSelection(checkedPos);
}
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final int checkedPos = mGrid.getCheckedItemPosition();
- final boolean hasValidSelection = checkedPos != GridView.INVALID_POSITION;
+ final int checkedPos = mListView.getCheckedItemPosition();
+ final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
mAlwaysButton.setEnabled(hasValidSelection);
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
- mGrid.smoothScrollToPosition(checkedPos);
+ mListView.smoothScrollToPosition(checkedPos);
}
mLastSelected = checkedPos;
} else {
@@ -276,7 +275,7 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
public void onButtonClick(View v) {
final int id = v.getId();
- startSelected(mGrid.getCheckedItemPosition(), id == R.id.button_always);
+ startSelected(mListView.getCheckedItemPosition(), id == R.id.button_always);
dismiss();
}
@@ -288,94 +287,103 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
}
protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
- if (alwaysCheck) {
- // Build a reasonable intent filter, based on what matched.
- IntentFilter filter = new IntentFilter();
+ // Build a reasonable intent filter, based on what matched.
+ IntentFilter filter = new IntentFilter();
- if (intent.getAction() != null) {
- filter.addAction(intent.getAction());
- }
- Set<String> categories = intent.getCategories();
- if (categories != null) {
- for (String cat : categories) {
- filter.addCategory(cat);
- }
+ if (intent.getAction() != null) {
+ filter.addAction(intent.getAction());
+ }
+ Set<String> categories = intent.getCategories();
+ if (categories != null) {
+ for (String cat : categories) {
+ filter.addCategory(cat);
}
- filter.addCategory(Intent.CATEGORY_DEFAULT);
-
- int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
- Uri data = intent.getData();
- if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
- String mimeType = intent.resolveType(this);
- if (mimeType != null) {
- try {
- filter.addDataType(mimeType);
- } catch (IntentFilter.MalformedMimeTypeException e) {
- Log.w("ResolverActivity", e);
- filter = null;
- }
+ }
+ filter.addCategory(Intent.CATEGORY_DEFAULT);
+
+ int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
+ Uri data = intent.getData();
+ if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
+ String mimeType = intent.resolveType(this);
+ if (mimeType != null) {
+ try {
+ filter.addDataType(mimeType);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ Log.w("ResolverActivity", e);
+ filter = null;
}
}
- if (data != null && data.getScheme() != null) {
- // We need the data specification if there was no type,
- // OR if the scheme is not one of our magical "file:"
- // or "content:" schemes (see IntentFilter for the reason).
- if (cat != IntentFilter.MATCH_CATEGORY_TYPE
- || (!"file".equals(data.getScheme())
- && !"content".equals(data.getScheme()))) {
- filter.addDataScheme(data.getScheme());
-
- // Look through the resolved filter to determine which part
- // of it matched the original Intent.
- Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
- if (pIt != null) {
- String ssp = data.getSchemeSpecificPart();
- while (ssp != null && pIt.hasNext()) {
- PatternMatcher p = pIt.next();
- if (p.match(ssp)) {
- filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
- break;
- }
+ }
+ if (data != null && data.getScheme() != null) {
+ // We need the data specification if there was no type,
+ // OR if the scheme is not one of our magical "file:"
+ // or "content:" schemes (see IntentFilter for the reason).
+ if (cat != IntentFilter.MATCH_CATEGORY_TYPE
+ || (!"file".equals(data.getScheme())
+ && !"content".equals(data.getScheme()))) {
+ filter.addDataScheme(data.getScheme());
+
+ // Look through the resolved filter to determine which part
+ // of it matched the original Intent.
+ Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
+ if (pIt != null) {
+ String ssp = data.getSchemeSpecificPart();
+ while (ssp != null && pIt.hasNext()) {
+ PatternMatcher p = pIt.next();
+ if (p.match(ssp)) {
+ filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
+ break;
}
}
- Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
- if (aIt != null) {
- while (aIt.hasNext()) {
- IntentFilter.AuthorityEntry a = aIt.next();
- if (a.match(data) >= 0) {
- int port = a.getPort();
- filter.addDataAuthority(a.getHost(),
- port >= 0 ? Integer.toString(port) : null);
- break;
- }
+ }
+ Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
+ if (aIt != null) {
+ while (aIt.hasNext()) {
+ IntentFilter.AuthorityEntry a = aIt.next();
+ if (a.match(data) >= 0) {
+ int port = a.getPort();
+ filter.addDataAuthority(a.getHost(),
+ port >= 0 ? Integer.toString(port) : null);
+ break;
}
}
- pIt = ri.filter.pathsIterator();
- if (pIt != null) {
- String path = data.getPath();
- while (path != null && pIt.hasNext()) {
- PatternMatcher p = pIt.next();
- if (p.match(path)) {
- filter.addDataPath(p.getPath(), p.getType());
- break;
- }
+ }
+ pIt = ri.filter.pathsIterator();
+ if (pIt != null) {
+ String path = data.getPath();
+ while (path != null && pIt.hasNext()) {
+ PatternMatcher p = pIt.next();
+ if (p.match(path)) {
+ filter.addDataPath(p.getPath(), p.getType());
+ break;
}
}
}
}
+ }
- if (filter != null) {
- final int N = mAdapter.mList.size();
- ComponentName[] set = new ComponentName[N];
- int bestMatch = 0;
- for (int i=0; i<N; i++) {
- ResolveInfo r = mAdapter.mList.get(i).ri;
- set[i] = new ComponentName(r.activityInfo.packageName,
- r.activityInfo.name);
- if (r.match > bestMatch) bestMatch = r.match;
- }
+ if (filter != null) {
+ final int N = mAdapter.mList.size();
+ ComponentName[] set = new ComponentName[N];
+ int bestMatch = 0;
+ for (int i=0; i<N; i++) {
+ ResolveInfo r = mAdapter.mList.get(i).ri;
+ set[i] = new ComponentName(r.activityInfo.packageName,
+ r.activityInfo.name);
+ if (r.match > bestMatch) bestMatch = r.match;
+ }
+ if (alwaysCheck) {
getPackageManager().addPreferredActivity(filter, bestMatch, set,
intent.getComponent());
+ } else {
+ try {
+ AppGlobals.getPackageManager().setLastChosenActivity(intent,
+ intent.resolveTypeIfNeeded(getContentResolver()),
+ PackageManager.MATCH_DEFAULT_ONLY,
+ filter, bestMatch, intent.getComponent());
+ } catch (RemoteException re) {
+ Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
+ }
}
}
@@ -410,11 +418,13 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
private final class ResolveListAdapter extends BaseAdapter {
private final Intent[] mInitialIntents;
private final List<ResolveInfo> mBaseResolveList;
+ private ResolveInfo mLastChosen;
private final Intent mIntent;
private final int mLaunchedFromUid;
private final LayoutInflater mInflater;
private List<DisplayResolveInfo> mList;
+ private int mInitialHighlight = -1;
public ResolveListAdapter(Context context, Intent intent,
Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid) {
@@ -436,14 +446,24 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
if (newItemCount == 0) {
// We no longer have any items... just finish the activity.
finish();
- } else if (newItemCount != oldItemCount) {
- resizeGrid();
}
}
+ public int getInitialHighlight() {
+ return mInitialHighlight;
+ }
+
private void rebuildList() {
List<ResolveInfo> currentResolveList;
+ try {
+ mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity(
+ mIntent, mIntent.resolveTypeIfNeeded(getContentResolver()),
+ PackageManager.MATCH_DEFAULT_ONLY);
+ } catch (RemoteException re) {
+ Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
+ }
+
mList.clear();
if (mBaseResolveList != null) {
currentResolveList = mBaseResolveList;
@@ -556,6 +576,12 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
// Process labels from start to i
int num = end - start+1;
if (num == 1) {
+ if (mLastChosen != null
+ && mLastChosen.activityInfo.packageName.equals(
+ ro.activityInfo.packageName)
+ && mLastChosen.activityInfo.name.equals(ro.activityInfo.name)) {
+ mInitialHighlight = mList.size();
+ }
// No duplicate labels. Use label for entry at start
mList.add(new DisplayResolveInfo(ro, roLabel, null, null));
} else {
@@ -585,6 +611,12 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
}
for (int k = start; k <= end; k++) {
ResolveInfo add = rList.get(k);
+ if (mLastChosen != null
+ && mLastChosen.activityInfo.packageName.equals(
+ add.activityInfo.packageName)
+ && mLastChosen.activityInfo.name.equals(add.activityInfo.name)) {
+ mInitialHighlight = mList.size();
+ }
if (usePkg) {
// Use application name for all entries from start to end-1
mList.add(new DisplayResolveInfo(add, roLabel,