diff options
Diffstat (limited to 'core/java/android')
30 files changed, 713 insertions, 355 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) + ". "); } |
