diff options
263 files changed, 3618 insertions, 1352 deletions
diff --git a/api/current.txt b/api/current.txt index 0418cd9..8d71796 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25,6 +25,7 @@ package android { field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE"; field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"; field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE"; + field public static final java.lang.String BIND_PRINT_SPOOLER_SERVICE = "android.permission.BIND_PRINT_SPOOLER_SERVICE"; field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS"; field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE"; field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE"; @@ -867,6 +868,7 @@ package android { field public static final int reqKeyboardType = 16843304; // 0x1010228 field public static final int reqNavigation = 16843306; // 0x101022a field public static final int reqTouchScreen = 16843303; // 0x1010227 + field public static final int requireDeviceUnlock = 16843754; // 0x10103ea field public static final int required = 16843406; // 0x101028e field public static final int requiredAccountType = 16843734; // 0x10103d6 field public static final int requiredForAllUsers = 16843728; // 0x10103d0 @@ -7328,7 +7330,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_LOCATION_NETWORK = "android.hardware.location.network"; field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone"; field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc"; - field public static final java.lang.String FEATURE_NFC_HCE = "android.hardware.nfc.hce"; + field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce"; field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape"; field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait"; field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer"; @@ -15260,6 +15262,7 @@ package android.nfc.cardemulation { public final class CardEmulationManager { method public static synchronized android.nfc.cardemulation.CardEmulationManager getInstance(android.nfc.NfcAdapter); + method public int getSelectionModeForCategory(java.lang.String); method public boolean isDefaultServiceForAid(android.content.ComponentName, java.lang.String); method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String); field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.ACTION_CHANGE_DEFAULT"; @@ -15267,6 +15270,9 @@ package android.nfc.cardemulation { field public static final java.lang.String CATEGORY_PAYMENT = "payment"; field public static final java.lang.String EXTRA_CATEGORY = "category"; field public static final java.lang.String EXTRA_SERVICE_COMPONENT = "component"; + field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1 + field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2 + field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0 } public abstract class HostApduService extends android.app.Service { @@ -19142,7 +19148,7 @@ package android.print { method public void onFinish(); method public abstract void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle); method public void onStart(); - method public abstract void onWrite(android.print.PageRange[], java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback); + method public abstract void onWrite(android.print.PageRange[], android.os.ParcelFileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback); field public static final java.lang.String METADATA_KEY_PRINT_PREVIEW = "KEY_METADATA_PRINT_PREVIEW"; } @@ -19162,6 +19168,7 @@ package android.print { method public int describeContents(); method public int getColorMode(); method public int getContentType(); + method public long getDataSize(); method public int getFittingMode(); method public android.print.PrintAttributes.Margins getMargins(); method public android.print.PrintAttributes.MediaSize getMediaSize(); @@ -19193,7 +19200,7 @@ package android.print { public class PrintFileDocumentAdapter extends android.print.PrintDocumentAdapter { ctor public PrintFileDocumentAdapter(android.content.Context, java.io.File, android.print.PrintDocumentInfo); method public void onLayout(android.print.PrintAttributes, android.print.PrintAttributes, android.os.CancellationSignal, android.print.PrintDocumentAdapter.LayoutResultCallback, android.os.Bundle); - method public void onWrite(android.print.PageRange[], java.io.FileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback); + method public void onWrite(android.print.PageRange[], android.os.ParcelFileDescriptor, android.os.CancellationSignal, android.print.PrintDocumentAdapter.WriteResultCallback); } public final class PrintJob { @@ -19215,9 +19222,10 @@ package android.print { method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int PRINT_JOB_ID_UNDEFINED = -1; // 0xffffffff - field public static final int STATE_CANCELED = 6; // 0x6 - field public static final int STATE_COMPLETED = 4; // 0x4 - field public static final int STATE_FAILED = 5; // 0x5 + field public static final int STATE_BLOCKED = 4; // 0x4 + field public static final int STATE_CANCELED = 7; // 0x7 + field public static final int STATE_COMPLETED = 5; // 0x5 + field public static final int STATE_FAILED = 6; // 0x6 field public static final int STATE_QUEUED = 2; // 0x2 field public static final int STATE_STARTED = 3; // 0x3 } @@ -19335,17 +19343,19 @@ package android.print.pdf { package android.printservice { public final class PrintDocument { - method public java.io.FileDescriptor getData(); + method public android.os.ParcelFileDescriptor getData(); method public android.print.PrintDocumentInfo getInfo(); } public final class PrintJob { + method public boolean block(java.lang.String); method public boolean cancel(); method public boolean complete(); method public boolean fail(java.lang.String); method public android.printservice.PrintDocument getDocument(); method public int getId(); method public android.print.PrintJobInfo getInfo(); + method public boolean isBlocked(); method public boolean isCancelled(); method public boolean isCompleted(); method public boolean isFailed(); @@ -19377,9 +19387,11 @@ package android.printservice { method public final boolean isDestroyed(); method public final boolean isPrinterDiscoveryStarted(); method public abstract void onDestroy(); - method public abstract void onRequestPrinterUpdate(android.print.PrinterId); method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>); + method public abstract void onStartPrinterStateTracking(android.print.PrinterId); method public abstract void onStopPrinterDiscovery(); + method public abstract void onStopPrinterStateTracking(android.print.PrinterId); + method public abstract void onValidatePrinters(java.util.List<android.print.PrinterId>); method public final void removePrinters(java.util.List<android.print.PrinterId>); method public final void updatePrinters(java.util.List<android.print.PrinterInfo>); } @@ -19392,6 +19404,7 @@ package android.provider { ctor public AlarmClock(); field public static final java.lang.String ACTION_SET_ALARM = "android.intent.action.SET_ALARM"; field public static final java.lang.String ACTION_SET_TIMER = "android.intent.action.SET_TIMER"; + field public static final java.lang.String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS"; field public static final java.lang.String EXTRA_DAYS = "android.intent.extra.alarm.DAYS"; field public static final java.lang.String EXTRA_HOUR = "android.intent.extra.alarm.HOUR"; field public static final java.lang.String EXTRA_LENGTH = "android.intent.extra.alarm.LENGTH"; @@ -21708,6 +21721,7 @@ package android.renderscript { method public deprecated synchronized void resize(int); method public void setFromFieldPacker(int, android.renderscript.FieldPacker); method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker); + method public void setOnBufferAvailableListener(android.renderscript.Allocation.OnBufferAvailableListener); method public void setSurface(android.view.Surface); method public void syncAll(int); field public static final int USAGE_GRAPHICS_CONSTANTS = 8; // 0x8 @@ -21728,6 +21742,10 @@ package android.renderscript { enum_constant public static final android.renderscript.Allocation.MipmapControl MIPMAP_ON_SYNC_TO_TEXTURE; } + public static abstract interface Allocation.OnBufferAvailableListener { + method public abstract void onBufferAvailable(android.renderscript.Allocation); + } + public class AllocationAdapter extends android.renderscript.Allocation { method public static android.renderscript.AllocationAdapter create1D(android.renderscript.RenderScript, android.renderscript.Allocation); method public static android.renderscript.AllocationAdapter create2D(android.renderscript.RenderScript, android.renderscript.Allocation); @@ -22377,7 +22395,7 @@ package android.renderscript { } public final class ScriptIntrinsicColorMatrix extends android.renderscript.ScriptIntrinsic { - method public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript, android.renderscript.Element); + method public static deprecated android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript, android.renderscript.Element); method public static android.renderscript.ScriptIntrinsicColorMatrix create(android.renderscript.RenderScript); method public void forEach(android.renderscript.Allocation, android.renderscript.Allocation); method public android.renderscript.Script.KernelID getKernelID(); @@ -22411,9 +22429,9 @@ package android.renderscript { public final class ScriptIntrinsicHistogram extends android.renderscript.ScriptIntrinsic { method public static android.renderscript.ScriptIntrinsicHistogram create(android.renderscript.RenderScript, android.renderscript.Element); method public void forEach(android.renderscript.Allocation); - method public void forEach_dot(android.renderscript.Allocation); + method public void forEach_Dot(android.renderscript.Allocation); method public android.renderscript.Script.FieldID getFieldID_Input(); - method public android.renderscript.Script.KernelID getKernelID_seperate(); + method public android.renderscript.Script.KernelID getKernelID_Separate(); method public void setDotCoefficients(float, float, float, float); method public void setOutput(android.renderscript.Allocation); } @@ -25730,7 +25748,7 @@ package android.util { method public android.util.JsonWriter value(java.lang.Number) throws java.io.IOException; } - public abstract interface LayoutDirection { + public final class LayoutDirection { field public static final int INHERIT = 2; // 0x2 field public static final int LOCALE = 3; // 0x3 field public static final int LTR = 0; // 0x0 @@ -31147,7 +31165,6 @@ package android.widget { method public int getAlignmentMode(); method public int getColumnCount(); method public int getOrientation(); - method public android.util.Printer getPrinter(); method public int getRowCount(); method public boolean getUseDefaultMargins(); method public boolean isColumnOrderPreserved(); @@ -31157,7 +31174,6 @@ package android.widget { method public void setColumnCount(int); method public void setColumnOrderPreserved(boolean); method public void setOrientation(int); - method public void setPrinter(android.util.Printer); method public void setRowCount(int); method public void setRowOrderPreserved(boolean); method public void setUseDefaultMargins(boolean); 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, diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index fd9fbae..eea9ee1 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -5,6 +5,7 @@ #include "GraphicsJNI.h"
#include "SkDither.h"
#include "SkUnPreMultiply.h"
+#include "SkStream.h"
#include <binder/Parcel.h>
#include "android_os_Parcel.h"
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index c433874..16beb02 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -202,7 +202,7 @@ private: // since we "may" create a purgeable imageref, we require the stream be ref'able // i.e. dynamically allocated, since its lifetime may exceed the current stack // frame. -static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, +static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options, bool allowPurgeable, bool forcePurgeable = false) { int sampleSize = 1; @@ -459,26 +459,17 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA jobject padding, jobject options) { jobject bitmap = NULL; - SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 0); + SkAutoTUnref<SkStreamRewindable> stream(GetRewindableStream(env, is, storage)); - if (stream) { + if (stream.get()) { // for now we don't allow purgeable with java inputstreams + // FIXME: GetRewindableStream may have made a copy, in which case + // purgeable should be allowed. bitmap = doDecode(env, stream, padding, options, false, false); - stream->unref(); } return bitmap; } -static ssize_t getFDSize(int fd) { - off64_t curr = ::lseek64(fd, 0, SEEK_CUR); - if (curr < 0) { - return 0; - } - size_t size = ::lseek(fd, 0, SEEK_END); - ::lseek64(fd, curr, SEEK_SET); - return size; -} - static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor, jobject padding, jobject bitmapFactoryOptions) { @@ -512,44 +503,16 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD); } -/* make a deep copy of the asset, and return it as a stream, or NULL if there - was an error. - */ -static SkStream* copyAssetToStream(Asset* asset) { - // if we could "ref/reopen" the asset, we may not need to copy it here - off64_t size = asset->seek(0, SEEK_SET); - if ((off64_t)-1 == size) { - SkDebugf("---- copyAsset: asset rewind failed\n"); - return NULL; - } - - size = asset->getLength(); - if (size <= 0) { - SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size); - return NULL; - } - - SkStream* stream = new SkMemoryStream(size); - void* data = const_cast<void*>(stream->getMemoryBase()); - off64_t len = asset->read(data, size); - if (len != size) { - SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len); - delete stream; - stream = NULL; - } - return stream; -} - static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jint native_asset, jobject padding, jobject options) { - SkStream* stream; + SkStreamRewindable* stream; Asset* asset = reinterpret_cast<Asset*>(native_asset); bool forcePurgeable = optionsPurgeable(env, options); if (forcePurgeable) { // if we could "ref/reopen" the asset, we may not need to copy it here // and we could assume optionsShareable, since assets are always RO - stream = copyAssetToStream(asset); + stream = CopyAssetToStream(asset); if (stream == NULL) { return NULL; } @@ -559,7 +522,7 @@ static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jint native_asset, stream = new AssetStreamAdaptor(asset); } SkAutoUnref aur(stream); - return doDecode(env, stream, padding, options, true, forcePurgeable); + return doDecode(env, stream, padding, options, forcePurgeable, forcePurgeable); } static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, @@ -572,7 +535,7 @@ static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, */ bool purgeable = optionsPurgeable(env, options) && !optionsJustBounds(env, options); AutoJavaByteArray ar(env, byteArray); - SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable); + SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable); SkAutoUnref aur(stream); return doDecode(env, stream, NULL, options, purgeable); } diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 8867a11..6646579 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -76,27 +76,6 @@ private: int fHeight; }; -static SkMemoryStream* buildSkMemoryStream(SkStream *stream) { - size_t bufferSize = 4096; - size_t streamLen = 0; - size_t len; - char* data = (char*)sk_malloc_throw(bufferSize); - - while ((len = stream->read(data + streamLen, - bufferSize - streamLen)) != 0) { - streamLen += len; - if (streamLen == bufferSize) { - bufferSize *= 2; - data = (char*)sk_realloc_throw(data, bufferSize); - } - } - data = (char*)sk_realloc_throw(data, streamLen); - - SkMemoryStream* streamMem = new SkMemoryStream(); - streamMem->setMemoryOwned(data, streamLen); - return streamMem; -} - static jobject createBitmapRegionDecoder(JNIEnv* env, SkStream* stream) { SkImageDecoder* decoder = SkImageDecoder::Factory(stream); int width, height; @@ -161,14 +140,12 @@ static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz, jbyteArray storage, // byte[] jboolean isShareable) { jobject brd = NULL; - SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024); + // for now we don't allow shareable with java inputstreams + SkStream* stream = CopyJavaInputStream(env, is, storage); if (stream) { - // for now we don't allow shareable with java inputstreams - SkMemoryStream* mStream = buildSkMemoryStream(stream); - brd = createBitmapRegionDecoder(env, mStream); - SkSafeUnref(mStream); // the decoder now holds a reference - stream->unref(); + brd = createBitmapRegionDecoder(env, stream); + stream->unref(); // the decoder now holds a reference } return brd; } @@ -176,14 +153,14 @@ static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz, static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz, jint native_asset, // Asset jboolean isShareable) { - SkStream* stream, *assStream; Asset* asset = reinterpret_cast<Asset*>(native_asset); - assStream = new AssetStreamAdaptor(asset); - stream = buildSkMemoryStream(assStream); - assStream->unref(); + SkAutoTUnref<SkMemoryStream> stream(CopyAssetToStream(asset)); + if (NULL == stream.get()) { + return NULL; + } - jobject brd = createBitmapRegionDecoder(env, stream); - SkSafeUnref(stream); // the decoder now holds a reference + jobject brd = createBitmapRegionDecoder(env, stream.get()); + // The decoder now holds a reference to stream. return brd; } diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp index aa4cbde..797d155 100644 --- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp +++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp @@ -1,28 +1,83 @@ #include "CreateJavaOutputStreamAdaptor.h" +#include "JNIHelp.h" +#include "SkData.h" +#include "SkRefCnt.h" +#include "SkStream.h" +#include "SkTypes.h" +#include "Utils.h" +#include <androidfw/Asset.h> #define RETURN_NULL_IF_NULL(value) \ do { if (!(value)) { SkASSERT(0); return NULL; } } while (false) +#define RETURN_ZERO_IF_NULL(value) \ + do { if (!(value)) { SkASSERT(0); return 0; } } while (false) + static jmethodID gInputStream_resetMethodID; static jmethodID gInputStream_markMethodID; -static jmethodID gInputStream_availableMethodID; +static jmethodID gInputStream_markSupportedMethodID; static jmethodID gInputStream_readMethodID; static jmethodID gInputStream_skipMethodID; +class RewindableJavaStream; + +/** + * Non-rewindable wrapper for a Java InputStream. + */ class JavaInputStreamAdaptor : public SkStream { public: JavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar) : fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) { SkASSERT(ar); - fCapacity = env->GetArrayLength(ar); + fCapacity = env->GetArrayLength(ar); SkASSERT(fCapacity > 0); - fBytesRead = 0; + fBytesRead = 0; + fIsAtEnd = false; + } + + virtual size_t read(void* buffer, size_t size) { + JNIEnv* env = fEnv; + if (NULL == buffer) { + if (0 == size) { + return 0; + } else { + /* InputStream.skip(n) can return <=0 but still not be at EOF + If we see that value, we need to call read(), which will + block if waiting for more data, or return -1 at EOF + */ + size_t amountSkipped = 0; + do { + size_t amount = this->doSkip(size - amountSkipped); + if (0 == amount) { + char tmp; + amount = this->doRead(&tmp, 1); + if (0 == amount) { + // if read returned 0, we're at EOF + fIsAtEnd = true; + break; + } + } + amountSkipped += amount; + } while (amountSkipped < size); + return amountSkipped; + } + } + return this->doRead(buffer, size); + } + + virtual bool isAtEnd() const { + return fIsAtEnd; } - virtual bool rewind() { +private: + // Does not override rewind, since a JavaInputStreamAdaptor's interface + // does not support rewinding. RewindableJavaStream, which is a friend, + // will be able to call this method to rewind. + bool doRewind() { JNIEnv* env = fEnv; fBytesRead = 0; + fIsAtEnd = false; env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID); if (env->ExceptionCheck()) { @@ -53,6 +108,7 @@ public: } if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications. + fIsAtEnd = true; break; // eof } @@ -92,58 +148,19 @@ public: return (size_t)skipped; } - size_t doSize() { - JNIEnv* env = fEnv; - jint avail = env->CallIntMethod(fJavaInputStream, - gInputStream_availableMethodID); - if (env->ExceptionCheck()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - SkDebugf("------- available threw an exception\n"); - avail = 0; - } - return avail; - } - - virtual size_t read(void* buffer, size_t size) { - JNIEnv* env = fEnv; - if (NULL == buffer) { - if (0 == size) { - return this->doSize(); - } else { - /* InputStream.skip(n) can return <=0 but still not be at EOF - If we see that value, we need to call read(), which will - block if waiting for more data, or return -1 at EOF - */ - size_t amountSkipped = 0; - do { - size_t amount = this->doSkip(size - amountSkipped); - if (0 == amount) { - char tmp; - amount = this->doRead(&tmp, 1); - if (0 == amount) { - // if read returned 0, we're at EOF - break; - } - } - amountSkipped += amount; - } while (amountSkipped < size); - return amountSkipped; - } - } - return this->doRead(buffer, size); - } - -private: JNIEnv* fEnv; jobject fJavaInputStream; // the caller owns this object jbyteArray fJavaByteArray; // the caller owns this object size_t fCapacity; size_t fBytesRead; + bool fIsAtEnd; + + // Allows access to doRewind and fBytesRead. + friend class RewindableJavaStream; }; -SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, - jbyteArray storage, int markSize) { +SkStream* WrapJavaInputStream(JNIEnv* env, jobject stream, + jbyteArray storage) { static bool gInited; if (!gInited) { @@ -154,8 +171,8 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, "reset", "()V"); gInputStream_markMethodID = env->GetMethodID(inputStream_Clazz, "mark", "(I)V"); - gInputStream_availableMethodID = env->GetMethodID(inputStream_Clazz, - "available", "()I"); + gInputStream_markSupportedMethodID = env->GetMethodID(inputStream_Clazz, + "markSupported", "()Z"); gInputStream_readMethodID = env->GetMethodID(inputStream_Clazz, "read", "([BII)I"); gInputStream_skipMethodID = env->GetMethodID(inputStream_Clazz, @@ -163,18 +180,167 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, RETURN_NULL_IF_NULL(gInputStream_resetMethodID); RETURN_NULL_IF_NULL(gInputStream_markMethodID); - RETURN_NULL_IF_NULL(gInputStream_availableMethodID); + RETURN_NULL_IF_NULL(gInputStream_markSupportedMethodID); RETURN_NULL_IF_NULL(gInputStream_readMethodID); RETURN_NULL_IF_NULL(gInputStream_skipMethodID); gInited = true; } - if (markSize) { - env->CallVoidMethod(stream, gInputStream_markMethodID, markSize); + return new JavaInputStreamAdaptor(env, stream, storage); +} + +static SkMemoryStream* adaptor_to_mem_stream(SkStream* adaptor) { + SkASSERT(adaptor != NULL); + SkDynamicMemoryWStream wStream; + const int bufferSize = 256 * 1024; // 256 KB, same as ViewStateSerializer. + uint8_t buffer[bufferSize]; + do { + size_t bytesRead = adaptor->read(buffer, bufferSize); + wStream.write(buffer, bytesRead); + } while (!adaptor->isAtEnd()); + SkAutoTUnref<SkData> data(wStream.copyToData()); + return new SkMemoryStream(data.get()); +} + +SkMemoryStream* CopyJavaInputStream(JNIEnv* env, jobject stream, + jbyteArray storage) { + SkAutoTUnref<SkStream> adaptor(WrapJavaInputStream(env, stream, storage)); + if (NULL == adaptor.get()) { + return NULL; } + return adaptor_to_mem_stream(adaptor.get()); +} - return new JavaInputStreamAdaptor(env, stream, storage); +/** + * Wrapper for a Java InputStream which is rewindable and + * has a length. + */ +class RewindableJavaStream : public SkStreamRewindable { +public: + // RewindableJavaStream takes ownership of adaptor. + RewindableJavaStream(JavaInputStreamAdaptor* adaptor, size_t length) + : fAdaptor(adaptor) + , fLength(length) { + SkASSERT(fAdaptor != NULL); + } + + virtual ~RewindableJavaStream() { + fAdaptor->unref(); + } + + virtual bool rewind() { + return fAdaptor->doRewind(); + } + + virtual size_t read(void* buffer, size_t size) { + return fAdaptor->read(buffer, size); + } + + virtual bool isAtEnd() const { + return fAdaptor->isAtEnd(); + } + + virtual size_t getLength() const { + return fLength; + } + + virtual bool hasLength() const { + return true; + } + + virtual SkStreamRewindable* duplicate() const { + // Duplicating this stream requires rewinding and + // reading, which modify this Stream (and could + // fail, leaving this one invalid). + SkASSERT(false); + return NULL; + } + +private: + JavaInputStreamAdaptor* fAdaptor; + const size_t fLength; +}; + +/** + * If jstream is a ByteArrayInputStream, return its remaining length. Otherwise + * return 0. + */ +static size_t get_length_from_byte_array_stream(JNIEnv* env, jobject jstream) { + static jclass byteArrayInputStream_Clazz; + static jfieldID countField; + static jfieldID posField; + + byteArrayInputStream_Clazz = env->FindClass("java/io/ByteArrayInputStream"); + RETURN_ZERO_IF_NULL(byteArrayInputStream_Clazz); + + countField = env->GetFieldID(byteArrayInputStream_Clazz, "count", "I"); + RETURN_ZERO_IF_NULL(byteArrayInputStream_Clazz); + posField = env->GetFieldID(byteArrayInputStream_Clazz, "pos", "I"); + RETURN_ZERO_IF_NULL(byteArrayInputStream_Clazz); + + if (env->IsInstanceOf(jstream, byteArrayInputStream_Clazz)) { + // Return the remaining length, to keep the same behavior of using the rest of the + // stream. + return env->GetIntField(jstream, countField) - env->GetIntField(jstream, posField); + } + return 0; +} + +/** + * If jstream is a class that has a length, return it. Otherwise + * return 0. + * Only checks for a set of subclasses. + */ +static size_t get_length_if_supported(JNIEnv* env, jobject jstream) { + size_t len = get_length_from_byte_array_stream(env, jstream); + if (len > 0) { + return len; + } + return 0; +} + +SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream, + jbyteArray storage) { + SkAutoTUnref<SkStream> adaptor(WrapJavaInputStream(env, stream, storage)); + if (NULL == adaptor.get()) { + return NULL; + } + + const size_t length = get_length_if_supported(env, stream); + if (length > 0 && env->CallBooleanMethod(stream, gInputStream_markSupportedMethodID)) { + // Set the readLimit for mark to the end of the stream, so it can + // be rewound regardless of how much has been read. + env->CallVoidMethod(stream, gInputStream_markMethodID, length); + // RewindableJavaStream will unref adaptor when it is destroyed. + return new RewindableJavaStream(static_cast<JavaInputStreamAdaptor*>(adaptor.detach()), + length); + } + + return adaptor_to_mem_stream(adaptor.get()); +} + +android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject jstream) { + static jclass assetInputStream_Clazz; + static jmethodID getAssetIntMethodID; + + assetInputStream_Clazz = env->FindClass("android/content/res/AssetManager$AssetInputStream"); + RETURN_NULL_IF_NULL(assetInputStream_Clazz); + + getAssetIntMethodID = env->GetMethodID(assetInputStream_Clazz, "getAssetInt", "()I"); + RETURN_NULL_IF_NULL(getAssetIntMethodID); + + if (!env->IsInstanceOf(jstream, assetInputStream_Clazz)) { + return NULL; + } + + jint jasset = env->CallIntMethod(jstream, getAssetIntMethodID); + android::Asset* a = reinterpret_cast<android::Asset*>(jasset); + if (NULL == a) { + jniThrowNullPointerException(env, "NULL native asset"); + return NULL; + } + return new android::AssetStreamAdaptor(a); } /////////////////////////////////////////////////////////////////////////////// diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h index c34c96a..5218dc5 100644 --- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h +++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h @@ -3,10 +3,70 @@ //#include <android_runtime/AndroidRuntime.h> #include "jni.h" -#include "SkStream.h" -SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, - jbyteArray storage, int markSize = 0); +namespace android { + class AssetStreamAdaptor; +} + +class SkMemoryStream; +class SkStream; +class SkStreamRewindable; +class SkWStream; + +/** + * Return an adaptor from a Java InputStream to an SkStream. + * @param env JNIEnv object. + * @param stream Pointer to Java InputStream. + * @param storage Java byte array for retrieving data from the + * Java InputStream. + * @return SkStream Simple subclass of SkStream which supports its + * basic methods like reading. Only valid until the calling + * function returns, since the Java InputStream is not managed + * by the SkStream. + */ +SkStream* WrapJavaInputStream(JNIEnv* env, jobject stream, + jbyteArray storage); + +/** + * Copy a Java InputStream. + * @param env JNIEnv object. + * @param stream Pointer to Java InputStream. + * @param storage Java byte array for retrieving data from the + * Java InputStream. + * @return SkMemoryStream The data in stream will be copied to a new + * SkMemoryStream. + * FIXME: Could return a more generic return type if ViewStateSerializer + * did not require an SkMemoryStream. + */ +SkMemoryStream* CopyJavaInputStream(JNIEnv* env, jobject stream, + jbyteArray storage); + +/** + * Get a rewindable stream from a Java InputStream. + * @param env JNIEnv object. + * @param stream Pointer to Java InputStream. + * @param storage Java byte array for retrieving data from the + * Java InputStream. + * @return SkStreamRewindable Either a wrapper around the Java + * InputStream, if possible, or a copy which is rewindable. + * Since it may be a wrapper, must not be used after the + * caller returns, like the result of WrapJavaInputStream. + */ +SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream, + jbyteArray storage); + +/** + * If the Java InputStream is an AssetInputStream, return an adaptor. + * This should not be used after the calling function returns, since + * the caller may close the asset. Returns NULL if the stream is + * not an AssetInputStream. + * @param env JNIEnv object. + * @param stream Pointer to Java InputStream. + * @return AssetStreamAdaptor representing the InputStream, or NULL. + * Must not be held onto. + */ +android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject stream); + SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream, jbyteArray storage); diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp index 4f64ff8..2eae841 100644 --- a/core/jni/android/graphics/Movie.cpp +++ b/core/jni/android/graphics/Movie.cpp @@ -1,8 +1,10 @@ +#include "ScopedLocalRef.h" #include "SkMovie.h" #include "SkStream.h" #include "GraphicsJNI.h" #include "SkTemplates.h" #include "SkUtils.h" +#include "Utils.h" #include "CreateJavaOutputStreamAdaptor.h" #include <androidfw/Asset.h> @@ -83,9 +85,14 @@ static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) { NPE_CHECK_RETURN_ZERO(env, istream); - // what is the lifetime of the array? Can the skstream hold onto it? - jbyteArray byteArray = env->NewByteArray(16*1024); - SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray); + SkStreamRewindable* strm = CheckForAssetStream(env, istream); + jbyteArray byteArray = NULL; + ScopedLocalRef<jbyteArray> scoper(env, NULL); + if (NULL == strm) { + byteArray = env->NewByteArray(16*1024); + scoper.reset(byteArray); + strm = GetRewindableStream(env, istream, byteArray); + } if (NULL == strm) { return 0; } diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp index 9c02219..dff2b18 100644 --- a/core/jni/android/graphics/Picture.cpp +++ b/core/jni/android/graphics/Picture.cpp @@ -20,6 +20,7 @@ #include "SkCanvas.h" #include "SkPicture.h" +#include "SkStream.h" #include "SkTemplates.h" #include "CreateJavaOutputStreamAdaptor.h" @@ -38,10 +39,9 @@ public: static SkPicture* deserialize(JNIEnv* env, jobject, jobject jstream, jbyteArray jstorage) { SkPicture* picture = NULL; - SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage); - if (strm) { - picture = SkPicture::CreateFromStream(strm); - delete strm; + SkAutoTUnref<SkStream> strm(WrapJavaInputStream(env, jstream, jstorage)); + if (strm.get()) { + picture = SkPicture::CreateFromStream(strm.get()); } return picture; } diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp index cf6977e..b7d1f3a 100644 --- a/core/jni/android/graphics/Utils.cpp +++ b/core/jni/android/graphics/Utils.cpp @@ -28,12 +28,28 @@ bool AssetStreamAdaptor::rewind() { return true; } +size_t AssetStreamAdaptor::getLength() const { + return fAsset->getLength(); +} + +bool AssetStreamAdaptor::isAtEnd() const { + return fAsset->getRemainingLength() == 0; +} + +SkStreamRewindable* AssetStreamAdaptor::duplicate() const { + SkASSERT(false); + // Cannot create a duplicate, since each AssetStreamAdaptor + // would be modifying the Asset. + //return new AssetStreamAdaptor(fAsset); + return NULL; +} + size_t AssetStreamAdaptor::read(void* buffer, size_t size) { ssize_t amount; if (NULL == buffer) { - if (0 == size) { // caller is asking us for our total length - return fAsset->getLength(); + if (0 == size) { + return 0; } // asset->seek returns new total offset // we want to return amount that was skipped @@ -62,6 +78,34 @@ size_t AssetStreamAdaptor::read(void* buffer, size_t size) { return amount; } +SkMemoryStream* android::CopyAssetToStream(Asset* asset) { + if (NULL == asset) { + return NULL; + } + + off64_t size = asset->seek(0, SEEK_SET); + if ((off64_t)-1 == size) { + SkDebugf("---- copyAsset: asset rewind failed\n"); + return NULL; + } + + size = asset->getLength(); + if (size <= 0) { + SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size); + return NULL; + } + + SkMemoryStream* stream = new SkMemoryStream(size); + void* data = const_cast<void*>(stream->getMemoryBase()); + off64_t len = asset->read(data, size); + if (len != size) { + SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len); + delete stream; + stream = NULL; + } + return stream; +} + jobject android::nullObjectReturn(const char msg[]) { if (msg) { SkDebugf("--- %s\n", msg); diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h index 75ceaa2..a1ac72a 100644 --- a/core/jni/android/graphics/Utils.h +++ b/core/jni/android/graphics/Utils.h @@ -26,16 +26,27 @@ namespace android { -class AssetStreamAdaptor : public SkStream { +class AssetStreamAdaptor : public SkStreamRewindable { public: AssetStreamAdaptor(Asset* a) : fAsset(a) {} virtual bool rewind(); virtual size_t read(void* buffer, size_t size); + virtual bool hasLength() const { return true; } + virtual size_t getLength() const; + virtual bool isAtEnd() const; + virtual SkStreamRewindable* duplicate() const; private: Asset* fAsset; }; +/** + * Make a deep copy of the asset, and return it as a stream, or NULL if there + * was an error. + * FIXME: If we could "ref/reopen" the asset, we may not need to copy it here. + */ + +SkMemoryStream* CopyAssetToStream(Asset*); /** Restore the file descriptor's offset in our destructor */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index faf6e63..9613df3 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -207,6 +207,7 @@ <protected-broadcast android:name="android.intent.action.DREAMING_STARTED" /> <protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" /> <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" /> + <protected-broadcast android:name="android.intent.action.DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN" /> <protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" /> <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" /> @@ -249,6 +250,9 @@ <protected-broadcast android:name="android.location.GPS_FIX_CHANGE" /> <protected-broadcast android:name="android.net.proxy.PAC_REFRESH" /> + <protected-broadcast + android:name="com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION" /> + <!-- ====================================== --> <!-- Permissions for things that cost money --> <!-- ====================================== --> @@ -1915,13 +1919,10 @@ android:description="@string/permdesc_bindNfcService" android:protectionLevel="signature" /> - <!-- Allows an application to call APIs that give it access to all print jobs - on the device. Usually an app can access only the print jobts it created. - This permission is not available to third party applications. - @hide --> - <permission android:name="android.permission.ACCESS_ALL_PRINT_JOBS" - android:label="@string/permlab_accessAllPrintJobs" - android:description="@string/permdesc_accessAllPrintJobs" + <!-- Must be required by the PrintSpooler to ensure that only the system can bind to it. --> + <permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE" + android:label="@string/permlab_bindPrintSpoolerService" + android:description="@string/permdesc_bindPrintSpoolerService" android:protectionLevel="signature" /> <!-- Must be required by a TextService (e.g. SpellCheckerService) diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml index 61cecae..28c5b74 100644 --- a/core/res/res/layout/resolve_list_item.xml +++ b/core/res/res/layout/resolve_list_item.xml @@ -18,40 +18,40 @@ */ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:gravity="center" - android:orientation="vertical" + android:orientation="horizontal" android:layout_height="wrap_content" android:layout_width="match_parent" - android:background="@android:drawable/activity_picker_bg" - android:padding="16dp"> - - <!-- Extended activity info to distinguish between duplicate activity names --> - <TextView android:id="@android:id/text2" - android:textAppearance="?android:attr/textAppearance" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center" - android:minLines="2" - android:maxLines="2" - android:paddingStart="4dip" - android:paddingEnd="4dip" /> + android:background="@android:drawable/activity_picker_bg"> <!-- Activity icon when presenting dialog Size will be filled in by ResolverActivity --> <ImageView android:id="@+id/icon" android:layout_width="0dp" android:layout_height="0dp" + android:layout_marginStart="12dp" + android:padding="4dp" android:scaleType="fitCenter" /> - <!-- Activity name --> - <TextView android:id="@android:id/text1" - android:textAppearance="?android:attr/textAppearanceSmall" - android:layout_width="wrap_content" + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:gravity="start|center_vertical" + android:orientation="vertical" android:layout_height="wrap_content" - android:gravity="center" - android:minLines="2" - android:maxLines="2" - android:paddingStart="4dip" - android:paddingEnd="4dip" /> + android:layout_width="wrap_content" + android:layout_gravity="start|center_vertical" + android:layout_marginStart="12dp"> + <!-- Activity name --> + <TextView android:id="@android:id/text1" + android:textAppearance="?android:attr/textAppearanceMedium" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="2" /> + <!-- Extended activity info to distinguish between duplicate activity names --> + <TextView android:id="@android:id/text2" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="2" + android:paddingTop="4dip" /> + </LinearLayout> </LinearLayout> diff --git a/core/res/res/layout/resolver_grid.xml b/core/res/res/layout/resolver_list.xml index d271c1a..f88ced1 100644 --- a/core/res/res/layout/resolver_grid.xml +++ b/core/res/res/layout/resolver_list.xml @@ -23,20 +23,18 @@ android:divider="?android:attr/dividerHorizontal" android:showDividers="middle" android:dividerPadding="0dip"> + <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1"> - <GridView - android:layout_gravity="center" - android:layout_width="wrap_content" + + <ListView + android:layout_width="match_parent" android:layout_height="match_parent" - android:id="@+id/resolver_grid" - android:numColumns="4" - android:columnWidth="128dp" - android:padding="16dp" - android:clipToPadding="false" - android:scrollbarStyle="outsideOverlay" /> + android:id="@+id/resolver_list" /> + </FrameLayout> + <LinearLayout android:id="@+id/button_bar" android:visibility="gone" diff --git a/core/res/res/values-mcc208-mnc26/config.xml b/core/res/res/values-mcc208-mnc26/config.xml new file mode 100644 index 0000000..31d2d0f --- /dev/null +++ b/core/res/res/values-mcc208-mnc26/config.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>20801</item> + <item>20810</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc214-mnc04/config.xml b/core/res/res/values-mcc214-mnc04/config.xml new file mode 100644 index 0000000..71301d5 --- /dev/null +++ b/core/res/res/values-mcc214-mnc04/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>21407</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc234-mnc30/config.xml b/core/res/res/values-mcc234-mnc30/config.xml new file mode 100644 index 0000000..eabdf9a --- /dev/null +++ b/core/res/res/values-mcc234-mnc30/config.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>23430</item> + <item>23431</item> + <item>23432</item> + <item>23433</item> + <item>23434</item> + <item>23486</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc234-mnc31/config.xml b/core/res/res/values-mcc234-mnc31/config.xml new file mode 100644 index 0000000..eabdf9a --- /dev/null +++ b/core/res/res/values-mcc234-mnc31/config.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>23430</item> + <item>23431</item> + <item>23432</item> + <item>23433</item> + <item>23434</item> + <item>23486</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc234-mnc32/config.xml b/core/res/res/values-mcc234-mnc32/config.xml new file mode 100644 index 0000000..eabdf9a --- /dev/null +++ b/core/res/res/values-mcc234-mnc32/config.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>23430</item> + <item>23431</item> + <item>23432</item> + <item>23433</item> + <item>23434</item> + <item>23486</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc234-mnc33/config.xml b/core/res/res/values-mcc234-mnc33/config.xml index d79d212..175f76e 100644 --- a/core/res/res/values-mcc234-mnc33/config.xml +++ b/core/res/res/values-mcc234-mnc33/config.xml @@ -35,4 +35,14 @@ "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type" note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> <string translatable="false" name="config_tether_apndata">Consumer Broadband,consumerbroadband,,,,,,,,,234,33,,DUN</string> + + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>23430</item> + <item>23431</item> + <item>23432</item> + <item>23433</item> + <item>23434</item> + <item>23486</item> + </string-array> </resources> diff --git a/core/res/res/values-mcc234-mnc34/config.xml b/core/res/res/values-mcc234-mnc34/config.xml new file mode 100644 index 0000000..eabdf9a --- /dev/null +++ b/core/res/res/values-mcc234-mnc34/config.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>23430</item> + <item>23431</item> + <item>23432</item> + <item>23433</item> + <item>23434</item> + <item>23486</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc234-mnc86/config.xml b/core/res/res/values-mcc234-mnc86/config.xml new file mode 100644 index 0000000..eabdf9a --- /dev/null +++ b/core/res/res/values-mcc234-mnc86/config.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>23430</item> + <item>23431</item> + <item>23432</item> + <item>23433</item> + <item>23434</item> + <item>23486</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml new file mode 100644 index 0000000..706570c --- /dev/null +++ b/core/res/res/values-mcc302-mnc610/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>302</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml new file mode 100644 index 0000000..706570c --- /dev/null +++ b/core/res/res/values-mcc302-mnc640/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>302</item> + </string-array> +</resources> diff --git a/core/res/res/values-mcc302-mnc780/config.xml b/core/res/res/values-mcc302-mnc780/config.xml index 42d4956..b03d14e 100644 --- a/core/res/res/values-mcc302-mnc780/config.xml +++ b/core/res/res/values-mcc302-mnc780/config.xml @@ -37,4 +37,8 @@ note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> <string translatable="false" name="config_tether_apndata">SaskTel Tethering,inet.stm.sk.ca,,,,,,,,,302,780,,DUN</string> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>302</item> + </string-array> </resources> diff --git a/core/res/res/values-mcc425-mnc07/config.xml b/core/res/res/values-mcc425-mnc07/config.xml index 890420e..51a9934 100644 --- a/core/res/res/values-mcc425-mnc07/config.xml +++ b/core/res/res/values-mcc425-mnc07/config.xml @@ -37,4 +37,8 @@ note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> <string translatable="false" name="config_tether_apndata">PC HOT mobile,pc.hotm,,,,,,,,,425,07,,DUN</string> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>42503</item> + </string-array> </resources> diff --git a/core/res/res/values-mcc425-mnc08/config.xml b/core/res/res/values-mcc425-mnc08/config.xml new file mode 100644 index 0000000..8470b86 --- /dev/null +++ b/core/res/res/values-mcc425-mnc08/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Don't use roaming icon for considered operators --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + <item>42502</item> + </string-array> +</resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 50ea08b..5444cb1 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2602,6 +2602,9 @@ <!-- Short description of the functionality the service implements. This attribute is mandatory.--> <attr name="description" /> + <!-- Whether the device must be unlocked before routing data to this service. + The default is false.--> + <attr name="requireDeviceUnlock" format="boolean"/> </declare-styleable> <!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that @@ -2622,7 +2625,8 @@ <!-- Short description of what the AID group implements. This attribute is mandatory.--> <attr name="description" /> <!-- The category attribute will be used by the Android platform to present - multiple applications that register AIDs in the same category uniformly. + multiple applications that register ISO 7816 Application IDs (AIDs) in the + same category uniformly. Additionally, when a category is specified, Android will ensure that either all AIDs in this group are routed to this application, or none at all. This attribute is optional.--> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 5d4383f..d4a408d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -820,6 +820,10 @@ <!-- IP address of the dns server to use if nobody else suggests one --> <string name="config_default_dns_server" translatable="false">8.8.8.8</string> + <!-- The default mobile provisioning apn. Empty by default, maybe overridden by + an mcc/mnc specific config.xml --> + <string name="mobile_provisioning_apn" translatable="false"></string> + <!-- The default mobile provisioning url. Empty by default, maybe overridden by an mcc/mnc specific config.xml --> <string name="mobile_provisioning_url" translatable="false"></string> @@ -1207,4 +1211,15 @@ <!-- Default Gravity setting for the system Toast view. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM --> <integer name="config_toastDefaultGravity">0x00000051</integer> + <!-- set to false if we need to show user confirmation + when alpha identifier is not provided by the UICC --> + <bool name="config_stkNoAlphaUsrCnf">true</bool> + + <!-- Don't use roaming icon for considered operators. + Can use mcc or mcc+mnc as item. For example, 302 or 21407. + If operators, 21404 and 21407, make roaming agreements, user of 21404 should not see + the roaming icon as using 21407 network. + To do this, add 21407 item to values-mcc214-mnc04/config.xml --> + <string-array translatable="false" name="config_operatorConsideredNonRoaming"> + </string-array> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index f2ec04f..696e782 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2073,5 +2073,6 @@ <public type="attr" name="customRoots" /> <public type="attr" name="autoMirrored" /> <public type="attr" name="supportsSwitchingToNextInputMethod" /> + <public type="attr" name="requireDeviceUnlock" /> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index ead46c2..4b32e2b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -984,12 +984,13 @@ <string name="permdesc_bindPrintService">Allows the holder to bind to the top-level interface of a print service. Should never be needed for normal apps.</string> - <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permlab_accessAllPrintJobs">access all print jobs</string> - <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_accessAllPrintJobs">Allows the holder to access print jobs - created by another app. Should never be needed for normal apps.</string> - + <!-- Title of an application permission, listed so the user can choose + whether they want to allow the application to do this. --> + <string name="permlab_bindPrintSpoolerService">bind to a print spooler service</string> + <!-- Description of an application permission, listed so the user can + choose whether they want to allow the application to do this. --> + <string name="permdesc_bindPrintSpoolerService">Allows the holder to bind to the top-level + interface of a print spooler service. Should never be needed for normal apps.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_bindNfcService">bind to NFC service</string> @@ -4292,6 +4293,9 @@ <!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] --> <string name="write_fail_reason_cannot_write">Error writing content</string> + <!-- Print fail reason: unknown. [CHAR LIMIT=25] --> + <string name="reason_unknown">unknown</string> + <!-- PIN entry dialog label/hint for PIN [CHAR LIMIT=none] --> <string name="restr_pin_enter_pin">Enter PIN</string> <!-- PIN entry dialog label/hint for old PIN [CHAR LIMIT=none] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a9c812e..f008b10 100755..100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -668,6 +668,7 @@ <java-symbol type="string" name="preposition_for_time" /> <java-symbol type="string" name="progress_erasing" /> <java-symbol type="string" name="progress_unmounting" /> + <java-symbol type="string" name="mobile_provisioning_apn" /> <java-symbol type="string" name="mobile_provisioning_url" /> <java-symbol type="string" name="mobile_redirected_provisioning_url" /> <java-symbol type="string" name="reboot_safemode_confirm" /> @@ -868,6 +869,7 @@ <java-symbol type="string" name="mediaSize_na_junior_legal" /> <java-symbol type="string" name="mediaSize_na_ledger" /> <java-symbol type="string" name="mediaSize_na_tabloid" /> + <java-symbol type="string" name="reason_unknown" /> <java-symbol type="string" name="restr_pin_enter_pin" /> <java-symbol type="string" name="write_fail_reason_cancelled" /> <java-symbol type="string" name="write_fail_reason_cannot_write" /> @@ -910,6 +912,7 @@ <java-symbol type="array" name="config_masterVolumeRamp" /> <java-symbol type="array" name="config_cdma_dun_supported_types" /> <java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" /> + <java-symbol type="array" name="config_operatorConsideredNonRoaming" /> <java-symbol type="drawable" name="default_wallpaper" /> <java-symbol type="drawable" name="indicator_input_error" /> @@ -1526,8 +1529,8 @@ <java-symbol type="string" name="enable_explore_by_touch_warning_title" /> <java-symbol type="string" name="enable_explore_by_touch_warning_message" /> - <java-symbol type="layout" name="resolver_grid" /> - <java-symbol type="id" name="resolver_grid" /> + <java-symbol type="layout" name="resolver_list" /> + <java-symbol type="id" name="resolver_list" /> <java-symbol type="id" name="button_once" /> <java-symbol type="id" name="button_always" /> <java-symbol type="integer" name="config_maxResolverActivityColumns" /> @@ -1639,6 +1642,7 @@ <java-symbol type="bool" name="config_sf_slowBlur" /> <java-symbol type="drawable" name="ic_volume" /> <java-symbol type="drawable" name="stat_notify_sim_toolkit" /> + <java-symbol type="bool" name="config_stkNoAlphaUsrCnf" /> <!-- From maps library --> <java-symbol type="array" name="maps_starting_lat_lng" /> diff --git a/docs/downloads/training/AndroidTestingFun.zip b/docs/downloads/training/AndroidTestingFun.zip Binary files differnew file mode 100644 index 0000000..dca5812 --- /dev/null +++ b/docs/downloads/training/AndroidTestingFun.zip diff --git a/docs/html/images/training/lesson2_MyFirstTestActivityTest_result.png b/docs/html/images/training/lesson2_MyFirstTestActivityTest_result.png Binary files differnew file mode 100644 index 0000000..e0e869b --- /dev/null +++ b/docs/html/images/training/lesson2_MyFirstTestActivityTest_result.png diff --git a/docs/html/training/activity-testing/activity-basic-testing.jd b/docs/html/training/activity-testing/activity-basic-testing.jd new file mode 100644 index 0000000..016289d --- /dev/null +++ b/docs/html/training/activity-testing/activity-basic-testing.jd @@ -0,0 +1,227 @@ +page.title=Creating and Running a Test Case +trainingnavtop=true + +@jd:body + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#testcase">Create a Test Case for Activity Testing</a> + <ol> + <li><a href="#fixture">Set Up Your Test Fixture</a></li> + <li><a href="#preconditions">Add Test Preconditions</a></li> + <li><a href="#test_method">Add Test Methods to Verify Your Activity</a></li> + </ol> + </li> + <li><a href="#build_run">Build and Run Your Test</a></li> +</ol> + +<h2>You should also read</h2> +<ul> +<li><a href="{@docRoot}tools/testing/testing_android.html">Testing +Fundamentals</a></li> +</ul> + +</div> +</div> +<p>In order to verify that there are no regressions in the layout design and +functional behavior in your application, it's important to +create a test for each {@link android.app.Activity} in your application. For +each test, you need to create the individual parts of a test case, including +the test fixture, preconditions test method, and {@link android.app.Activity} +test methods. You can then run your test to get a test report. If any test +method fails, this might indicate a potential defect in your code.</p> +<p class="note"><strong>Note:</strong> In the Test-Driven Development (TDD) +approach, instead of writing most or all of your app code up-front and then +running tests later in the development cycle, you would progressively write +just enough production code to satisfy your test dependencies, update your +test cases to reflect new functional requirements, and iterate repeatedly this +way.</p> + +<h2 id="testcase">Create a Test Case</h2> +<p>{@link android.app.Activity} tests are written in a structured way. +Make sure to put your tests in a separate package, distinct from the code under +test.</p> +<p>By convention, your test package name should follow the same name as the +application package, suffixed with <strong>".tests"</strong>. In the test package +you created, add the Java class for your test case. By convention, your test case +name should also follow the same name as the Java or Android class that you +want to test, but suffixed with <strong>“Test”</strong>.</p> +<p>To create a new test case in Eclipse:</p> +<ol type="a"> + <li>In the Package Explorer, right-click on the {@code /src} directory for +your test project and select <strong>New > Package</strong>.</li> + <li>Set the <strong>Name</strong> field to +{@code <your_app_package_name>.tests} (for example, +{@code com.example.android.testingfun.tests}) and click +<strong>Finish</strong>.</li> + <li>Right-click on the test package you created, and select +<strong>New > Class</strong>.</li> + <li>Set the <strong>Name</strong> field to +{@code <your_app_activity_name>Test} (for example, +{@code MyFirstTestActivityTest}) and click <strong>Finish</strong>.</li> +</ol> + +<h3 id="fixture">Set Up Your Test Fixture</h3> +<p>A <em>test fixture</em> consists of objects that must be initialized for +running one or more tests. To set up the test fixture, you can override the +{@link junit.framework.TestCase#setUp()} and +{@link junit.framework.TestCase#tearDown()} methods in your test. The +test runner automatically runs {@link junit.framework.TestCase#setUp()} before +running any other test methods, and {@link junit.framework.TestCase#tearDown()} +at the end of each test method execution. You can use these methods to keep +the code for test initialization and clean up separate from the tests methods. +</p> +<p>To set up your test fixture in Eclipse:</p> +<ol> +<li>In the Package Explorer, double-click on the test case that you created +earlier to bring up the Eclipse Java editor, then modify your test case class +to extend one of the sub-classes of {@link android.test.ActivityTestCase}. +<p>For example:</p> +<pre> +public class MyFirstTestActivityTest + extends ActivityInstrumentationTestCase2<MyFirstTestActivity> { +</pre> +</li> +<li>Next, add the constructor and {@link junit.framework.TestCase#setUp()} +methods to your test case, and add variable declarations for the +{@link android.app.Activity} that you want to test.</p> +<p>For example:</p> +<pre> +public class MyFirstTestActivityTest + extends ActivityInstrumentationTestCase2<MyFirstTestActivity> { + + private MyFirstTestActivity mFirstTestActivity; + private TextView mFirstTestText; + + public MyFirstTestActivityTest() { + super(MyFirstTestActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mFirstTestActivity = getActivity(); + mFirstTestText = + (TextView) mFirstTestActivity + .findViewById(R.id.my_first_test_text_view); + } +} +</pre> +<p>The constructor is invoked by the test runner to instantiate the test +class, while the {@link junit.framework.TestCase#setUp()} method is invoked by +the test runner before it runs any tests in the test class.</p> +</li> +</ol> + +<p>Typically, in the {@link junit.framework.TestCase#setUp()} method, you +should:</p> +<ul> +<li>Invoke the superclass constructor for +{@link junit.framework.TestCase#setUp()}, which is required by JUnit.</li> +<li>Initialize your test fixture state by: + <ul> + <li>Defining the instance variables that store the state of the fixture.</li> + <li>Creating and storing a reference to an instance of the +{@link android.app.Activity} under test.</li> + <li>Obtaining a reference to any UI components in the +{@link android.app.Activity} that you want to test.</li> + </ul> +</ul> + +<p>You can use the +{@link android.test.ActivityInstrumentationTestCase2#getActivity()} method to +get a reference to the {@link android.app.Activity} under test.</p> + +<h3 id="preconditions">Add Test Preconditions</h3> +<p>As a sanity check, it is good practice to verify that the test fixture has +been set up correctly, and the objects that you want to test have been correctly +instantiated or initialized. That way, you won’t have to see +tests failing because something was wrong with the setup of your test fixture. +By convention, the method for verifying your test fixture is called +{@code testPreconditions()}.</p> + +<p>For example, you might want to add a {@code testPreconditons()} method like +this to your test case:</p> + +<pre> +public void testPreconditions() { + assertNotNull(“mFirstTestActivity is null”, mFirstTestActivity); + assertNotNull(“mFirstTestText is null”, mFirstTestText); +} +</pre> + +<p>The assertion methods are from the JUnit {@link junit.framework.Assert} +class. Generally, you can use assertions to +verify if a specific condition that you want to test is true. +<ul> +<li>If the condition is false, the assertion method throws an +{@link android.test.AssertionFailedError} exception, which is then typically +reported by the test runner. You can provide a string in the first argument of +your assertion method to give some contextual details if the assertion fails.</li> +<li>If the condition is true, the test passes.</li> +</ul> +<p>In both cases, the test runner proceeds to run the other test methods in the +test case.</p> + +<h3 id="test_method">Add Test Methods to Verify Your Activity</h3> +<p>Next, add one or more test methods to verify the layout and functional +behavior of your {@link android.app.Activity}.</p> +<p>For example, if your {@link android.app.Activity} includes a +{@link android.widget.TextView}, you can add a test method like this to check +that it has the correct label text:</p> +<pre> +public void testMyFirstTestTextView_labelText() { + final String expected = + mFirstTestActivity.getString(R.string.my_first_test); + final String actual = mFirstTestText.getText().toString(); + assertEquals(expected, actual); +} +</pre> + +<p>The {@code testMyFirstTestTextView_labelText()} method simply checks that the +default text of the {@link android.widget.TextView} that is set by the layout +is the same as the expected text defined in the {@code strings.xml} resource.</p> +<p class="note"><strong>Note:</strong> When naming test methods, you can use +an underscore to separate what is being tested from the specific case being +tested. This style makes it easier to see exactly what cases are being tested.</p> +<p>When doing this type of string value comparison, it’s good practice to read +the expected string from your resources, instead of hardcoding the string in +your comparison code. This prevents your test from easily breaking whenever the +string definitions are modified in the resource file.</p> +<p>To perform the comparison, pass both the expected and actual strings as +arguments to the +{@link junit.framework.Assert#assertEquals(java.lang.String, java.lang.String) assertEquals()} +method. If the values are not the same, the assertion will throw an +{@link junit.framework.AssertionFailedError} exception.</p> +<p>If you added a {@code testPreconditions()} method, put your test methods +after the {@code testPreconditions()} definition in your Java class.</p> +<p>For a complete test case example, take a look at +{@code MyFirstTestActivityTest.java} in the sample app.</p> + +<h2 id="build_run">Build and Run Your Test</h2> +<p>You can build and run your test easily from the Package Explorer in +Eclipse.</p> +<p>To build and run your test:</p> +<ol> +<li>Connect an Android device to your machine. On the device or emulator, open +the <strong>Settings</strong> menu, select <strong>Developer options</strong> +and make sure that USB debugging is enabled.</li> +<li>In the Project Explorer, right-click on the test class that you created +earlier and select <strong>Run As > Android Junit Test</strong>.</li> +<li>In the Android Device Chooser dialog, select the device that you just +connected, then click <strong>OK</strong>.</li> +<li>In the JUnit view, verify that the test passes with no errors or failures.</li> +</ol> +<p>For example, if the test case passes with no errors, the result should look +like this:</p> +<img src="{@docRoot}images/training/activity-testing_lesson2_MyFirstTestActivityTest_result.png" alt="" /> +<p class="img-caption"> + <strong>Figure 1.</strong> Result of a test with no errors. +</p> + + + diff --git a/docs/html/training/activity-testing/activity-functional-testing.jd b/docs/html/training/activity-testing/activity-functional-testing.jd new file mode 100644 index 0000000..7c8ff1d --- /dev/null +++ b/docs/html/training/activity-testing/activity-functional-testing.jd @@ -0,0 +1,166 @@ +page.title=Creating Functional Tests +trainingnavtop=true +@jd:body + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#test_methods">Add Test Method to Validate Functional Behavior</a> + <ol> + <li><a href="#activitymonitor">Set Up an ActivityMonitor</a></li> + <li><a href="#keyinput">Send Keyboard Input Using Instrumentation</a></li> + </ol> + </li> +</ol> + +<h2>Try it out</h2> +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip" +class="button">Download the demo</a> + <p class="filename">AndroidTestingFun.zip</p> +</div> + +</div> +</div> +<p>Functional testing involves verifying that individual application +components work together as expected by the user. For example, you can create a +functional test to verify that an {@link android.app.Activity} correctly +launches a target {@link android.app.Activity} when the user performs a UI +interaction.</p> + +<p>To create a functional test for your {@link android.app.Activity}, your test +class should extend {@link android.test.ActivityInstrumentationTestCase2}. +Unlike {@link android.test.ActivityUnitTestCase}, +tests in {@link android.test.ActivityInstrumentationTestCase2} can +communicate with the Android system and send keyboard input and click events to +the UI.</p> + +<p>For a complete test case example, take a look at +{@code SenderActivityTest.java} in the sample app.</p> + +<h2 id="test_methods">Add Test Method to Validate Functional Behavior</h2> +<p id="test_goals">Your functional testing goals might include:</p> +<ul> +<li>Verifying that a target {@link android.app.Activity} is started when a +UI control is pushed in the sender {@link android.app.Activity}.</li> +<li>Verifying that the target {@link android.app.Activity} displays the +correct data based on the user's input in the sender +{@link android.app.Activity}.</li> +</ul> +<p>You might implement your test method like this:</p> + +<pre> +@MediumTest +public void testSendMessageToReceiverActivity() { + final Button sendToReceiverButton = (Button) + mSenderActivity.findViewById(R.id.send_message_button); + + final EditText senderMessageEditText = (EditText) + mSenderActivity.findViewById(R.id.message_input_edit_text); + + // Set up an ActivityMonitor + ... + + // Send string input value + ... + + // Validate that ReceiverActivity is started + ... + + // Validate that ReceiverActivity has the correct data + ... + + // Remove the ActivityMonitor + ... +} +</pre> +<p>The test waits for an {@link android.app.Activity} that matches this monitor, +otherwise returns null after a timeout elapses. If {@code ReceiverActivity} was +started, the {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} +that you set +up earlier receives a hit. You can use the assertion methods to verify that +the {@code ReceiverActivity} is indeed started, and that the hit count on the +{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} incremented +as expected.</p> + +<h2 id="activitymonitor">Set up an ActivityMonitor</h2> +<p>To monitor a single {@link android.app.Activity} in your application, you +can register an {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}. +The {@link android.app.Instrumentation.ActivityMonitor ActivityMonitor} is +notified by the system whenever an {@link android.app.Activity} that matches your criteria is started. +If a match is found, the monitor’s hit count is updated.</p> +<p>Generally, to use an +{@link android.app.Instrumentation.ActivityMonitor ActivityMonitor}, you should:</p> +<ol> +<li>Retrieve the {@link android.app.Instrumentation} instance for your test +case by using the +{@link android.test.InstrumentationTestCase#getInstrumentation()} method.</li> +<li>Add an instance of {@link android.app.Instrumentation.ActivityMonitor} to +the current instrumentation using one of the {@link android.app.Instrumentation} +{@code addMonitor()} methods. The match criteria can be specified as an +{@link android.content.IntentFilter} or a class name string.</li> +<li>Wait for the {@link android.app.Activity} to start.</li> +<li>Verify that the monitor hits were incremented.</li> +<li>Remove the monitor.</li> +</ol> +<p>For example:</p> +<pre> +// Set up an ActivityMonitor +ActivityMonitor receiverActivityMonitor = + getInstrumentation().addMonitor(ReceiverActivity.class.getName(), + null, false); + +// Validate that ReceiverActivity is started +TouchUtils.clickView(this, sendToReceiverButton); +ReceiverActivity receiverActivity = (ReceiverActivity) + receiverActivityMonitor.waitForActivityWithTimeout(TIMEOUT_IN_MS); +assertNotNull("ReceiverActivity is null", receiverActivity); +assertEquals("Monitor for ReceiverActivity has not been called", + 1, receiverActivityMonitor.getHits()); +assertEquals("Activity is of wrong type", + ReceiverActivity.class, receiverActivity.getClass()); + +// Remove the ActivityMonitor +getInstrumentation().removeMonitor(receiverActivityMonitor); +</pre> + +<h2 id="keyinput">Send Keyboard Input Using Instrumentation</h2> +<p>If your {@link android.app.Activity} has an {@link android.widget.EditText} +field, you might want to test that users can enter values into the +{@link android.widget.EditText} object.</p> +<p>Generally, to send a string input value to an {@link android.widget.EditText} +object in {@link android.test.ActivityInstrumentationTestCase2}, you should:</p> +<ol> +<li>Use the {@link android.app.Instrumentation#runOnMainSync(java.lang.Runnable) runOnMainSync()} +method to run the {@link android.view.View#requestFocus()} call synchronously +in a loop. This way, the UI thread is blocked until focus is received.</li> +<li>Call {@link android.app.Instrumentation#waitForIdleSync()} method to wait +for the main thread to become idle (that is, have no more events to process).</li> +<li>Send a text string to the {@link android.widget.EditText} by calling +{@link android.app.Instrumentation#sendStringSync(java.lang.String) +sendStringSync()} and pass your input string as the parameter.</p> +</ol> +<p>For example:</p> +<pre> +// Send string input value +getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + senderMessageEditText.requestFocus(); + } +}); +getInstrumentation().waitForIdleSync(); +getInstrumentation().sendStringSync("Hello Android!"); +getInstrumentation().waitForIdleSync(); +</pre> + + + + + + + + diff --git a/docs/html/training/activity-testing/activity-ui-testing.jd b/docs/html/training/activity-testing/activity-ui-testing.jd new file mode 100644 index 0000000..644f3ca --- /dev/null +++ b/docs/html/training/activity-testing/activity-ui-testing.jd @@ -0,0 +1,216 @@ +page.title=Testing UI Components +trainingnavtop=true + +@jd:body + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#testcase">Create a Test Case for UI Testing with Instrumentation</a> + <li><a href="#test_method">Add Test Methods to Verify UI Behavior</a> + <ol> + <li><a href="#verify_button_display">Verify Button Layout Parameters</a></li> + <li><a href="#verify_TextView">Verify TextView Layout Parameters</a></li> + <li><a href="#verify_button_behavior">Verify Button Behavior</a></li> + </ol> + </li> + <li><a href="#annotations">Apply Test Annotations</a></li> +</ol> + +<h2>Try it out</h2> +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip" +class="button">Download the demo</a> + <p class="filename">AndroidTestingFun.zip</p> +</div> + +</div> +</div> + +<p>Typically, your {@link android.app.Activity} includes user interface +components (such as buttons, editable text fields, checkboxes, and pickers) to +allow users to interact with your Android application. This lesson shows how +you can test an {@link android.app.Activity} with a simple push-button UI. You +can use the same general steps to test other, more sophisticated types of UI +components.</p> + +<p class="note"><strong>Note:</strong> The type of UI testing in this lesson is +called <em>white-box testing</em> because you have the +source code for the application that you want to test. The Android +<a href="{@docRoot}tools/testing/testing_android.html#Instrumentation">Instrumentation</a> +framework is suitable for creating white-box tests for UI components within an +application. An alternative type of UI testing is <em>black-box testing</em>, +where you may not have access to the application source. This type of testing +is useful when you want to test how your app interacts with other apps or with +the system. Black-box testing is not covered in this training. To learn more +about how to perform black-box testing on your Android apps, see the +<a href="{@docRoot}tools/testing/testing_ui.html">UI Testing guide</a>. +<p>For a complete test case example, take a look at +{@code ClickFunActivityTest.java} in the sample app.</p> + +<h2 id="testcase">Create a Test Case for UI Testing with Instrumentation</h2> +<p>When testing an {@link android.app.Activity} that has a user interface (UI), +the {@link android.app.Activity} under test runs in the UI thread. However, the +test application itself runs in a separate thread in the same process as the +application under test. This means that your test app can reference objects +from the UI thread, but if it attempts to change properties on those objects or +send events to the UI thread, you will usually get a {@code WrongThreadException} +error.</p> +<p>To safely inject {@link android.content.Intent} objects into your +{@link android.app.Activity} or run test methods on the UI thread, you can +extend your test class to use {@link android.test.ActivityInstrumentationTestCase2}. +To learn more about how to run test methods on the UI thread, see +<a href="{@docRoot}tools/testing/activity_testing.html#RunOnUIThread">Testing +on the UI thread</a>.</p> + +<h3 id="fixture">Set Up Your Test Fixture</h3> +<p>When setting up the test fixture for UI testing, you should specify the +<a href="{@docRoot}guide/topics/ui/ui-events.html#TouchMode">touch mode</a> +in your {@link junit.framework.TestCase#setUp()} method. Setting the touch mode +to {@code true} prevents the UI control from taking focus when you click it +programmatically in the test method later (for example, a button UI will just +fire its on-click listener). Make sure that you call +{@link android.test.ActivityInstrumentationTestCase2#setActivityInitialTouchMode(boolean) setActivityInitialTouchMode()} +before calling {@link android.test.ActivityInstrumentationTestCase2#getActivity()}. +</p> +<p>For example:</ap> +<pre> +public class ClickFunActivityTest + extends ActivityInstrumentationTestCase2<ClickFunActivity> { + ... + @Override + protected void setUp() throws Exception { + super.setUp(); + + setActivityInitialTouchMode(true); + + mClickFunActivity = getActivity(); + mClickMeButton = (Button) + mClickFunActivity + .findViewById(R.id.launch_next_activity_button); + mInfoTextView = (TextView) + mClickFunActivity.findViewById(R.id.info_text_view); + } +} +</pre> + +<h2 id="test_methods">Add Test Methods to Validate UI Behavior</h2> +<p id="test_goals">Your UI testing goals might include:</p> +<ul> +<li>Verifying that a button is displayed with the correct layout when the +{@link android.app.Activity} is launched.</li> +<li>Verifying that a {@link android.widget.TextView} is initially hidden.</li> +<li>Verifying that a {@link android.widget.TextView} displays the expected string +when a button is pushed.</li> +</ul> +<p>The following section demonstrates how you can implement test methods +to perform these verifications.</p> + +<h3 id="verify_button_display">Verify Button Layout Parameters</h3> +<p>You might add a test method like this to verify that a button is displayed +correctly in your {@link android.app.Activity}:</p> +<pre> +@MediumTest +public void testClickMeButton_layout() { + final View decorView = mClickFunActivity.getWindow().getDecorView(); + + ViewAsserts.assertOnScreen(decorView, mClickMeButton); + + final ViewGroup.LayoutParams layoutParams = + mClickMeButton.getLayoutParams(); + assertNotNull(layoutParams); + assertEquals(layoutParams.width, WindowManager.LayoutParams.MATCH_PARENT); + assertEquals(layoutParams.height, WindowManager.LayoutParams.WRAP_CONTENT); +} +</pre> + +<p>In the {@link android.test.ViewAsserts#assertOnScreen(android.view.View,android.view.View) assertOnScreen()} +method call, you should pass in the root view and the view that you are +expecting to be present on the screen. If the expected view is not found in the +root view, the assertion method throws an {@link junit.framework.AssertionFailedError} +exception, otherwise the test passes.</p> +<p>You can also verify that the layout of a {@link android.widget.Button} is +correct by getting a reference to its {@link android.view.ViewGroup.LayoutParams} +object, then call assertion methods to verify that the +{@link android.widget.Button} object's width and height attributes match the +expected values.</p> +<p>The {@code @MediumTest} annotation specifies how the test is categorized, +relative to its absolute execution time. To learn more about using test size +annotations, see <a href="#annotations">Apply Test Annotations</a>.</p> + +<h3 id="verify_TextView">Verify TextView Layout Parameters</h3> +<p>You might add a test method like this to verify that a +{@link android.widget.TextView} initially appears hidden in +your {@link android.app.Activity}:</p> +<pre> +@MediumTest +public void testInfoTextView_layout() { + final View decorView = mClickFunActivity.getWindow().getDecorView(); + ViewAsserts.assertOnScreen(decorView, mInfoTextView); + assertTrue(View.GONE == mInfoTextView.getVisibility()); +} +</pre> +<p>You can call {@link android.view.Window#getDecorView()} to get a reference +to the decor view for the {@link android.app.Activity}. The decor view is the +top-level ViewGroup ({@link android.widget.FrameLayout}) view in the layout +hierarchy.</p> + +<h3 id="verify_button_behavior">Verify Button Behavior</h3> +<p>You can use a test method like this to verify that a +{@link android.widget.TextView} becomes visible when a +{@link android.widget.Button} is pushed:</p> + +<pre> +@MediumTest +public void testClickMeButton_clickButtonAndExpectInfoText() { + String expectedInfoText = mClickFunActivity.getString(R.string.info_text); + TouchUtils.clickView(this, mClickMeButton); + assertTrue(View.VISIBLE == mInfoTextView.getVisibility()); + assertEquals(expectedInfoText, mInfoTextView.getText()); +} +</pre> + +<p>To programmatically click a {@link android.widget.Button} in your +test, call {@link android.test.TouchUtils#clickView(android.test.InstrumentationTestCase,android.view.View) clickView()}. +You must pass in a reference to the test case that is being run and a reference +to the {@link android.widget.Button} to manipulate.</p> + +<p class="note"><strong>Note: </strong>The {@link android.test.TouchUtils} +helper class provides convenience methods for simulating touch interactions +with your application. You can use these methods to simulate clicking, tapping, +and dragging of Views or the application screen.</p> +<p class="caution"><strong>Caution: </strong>The {@link android.test.TouchUtils} +methods are designed to send events to the UI thread safely from the test thread. +You should not run {@link android.test.TouchUtils} directly in the UI thread or +any test method annotated with {@code @UIThread}. Doing so might +raise the {@code WrongThreadException}.</p> + +<h2 id="annotations">Apply Test Annotations</h2> +<p>The following annotations can be applied to indicate the size of a test +method:</p> +<dl> +<dt>{@link +android.test.suitebuilder.annotation.SmallTest @SmallTest}</dt> +<dd>Marks a test that should run as part of the small tests.</dd> +<dt>{@link +android.test.suitebuilder.annotation.MediumTest @MediumTest}</dt> +<dd>Marks a test that should run as part of the medium tests.</dd> +<dt>{@link android.test.suitebuilder.annotation.LargeTest @LargeTest}</dt> +<dd>Marks a test that should run as part of the large tests.</dd> +</dl> +<p>Typically, a short running test that take only a few milliseconds should be +marked as a {@code @SmallTest}. Longer running tests (100 milliseconds or +more) are usually marked as {@code @MediumTest}s or {@code @LargeTest}s, +depending on whether the test accesses resources on the local system only or +remote resources over a network. For guidance on using test size annotations, +see this <a href="https://plus.sandbox.google.com/+AndroidDevelopers/posts/TPy1EeSaSg8">Android Tools Protip</a>.</p> +<p>You can mark up your test methods with other test annotations to control +how the tests are organized and run. For more information on other annotations, +see the {@link java.lang.annotation.Annotation} class reference.</p> + + + + diff --git a/docs/html/training/activity-testing/activity-unit-testing.jd b/docs/html/training/activity-testing/activity-unit-testing.jd new file mode 100644 index 0000000..74dcda9 --- /dev/null +++ b/docs/html/training/activity-testing/activity-unit-testing.jd @@ -0,0 +1,134 @@ +page.title=Creating Unit Tests +trainingnavtop=true +@jd:body + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#testcase">Create a Test Case for Activity Unit Testing</a> + <li><a href="#test_method">Validate Launch of Another Activity</a> +</ol> + +<h2>Try it out</h2> +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip" +class="button">Download the demo</a> + <p class="filename">AndroidTestingFun.zip</p> +</div> + +</div> +</div> + +<p>An {@link android.app.Activity} unit test is an excellent way to quickly +verify the state of an {@link android.app.Activity} and its interactions with +other components in isolation (that is, disconnected from the rest of the +system). A unit test generally tests the smallest possible unit of code +(which could be a method, class, or component), without dependencies on system +or network resources. For example, you can write a unit test to check +that an {@link android.app.Activity} has the correct layout or that it +triggers an {@link android.content.Intent} object correctly.</p> +<p>Unit tests are generally not suitable for testing complex UI interaction +events with the system. Instead, you should use +the {@link android.test.ActivityInstrumentationTestCase2} class, as described +in <a href="activity-ui-testing.html">Testing UI Components</a>.</p> +<p>This lesson shows how you can write a unit test to verify that an +{@link android.content.Intent} is triggered to launch another +{@link android.app.Activity}. +Since the test runs in an isolated environment, the +{@link android.content.Intent} +is not actually sent to the Android system, but you can inspect that the +{@link android.content.Intent} object's payload data is accurate.</p> +<p>For a complete test case example, take a look at +{@code LaunchActivityTest.java} in the sample app.</p> + +<p class="note"><strong>Note: </strong>To test against system or external +dependencies, you can use mock objects from a mocking +framework and inject them into your unit tests. To learn more about the mocking +framework provided by Android, see +<a href="{@docRoot}tools/testing/testing_android.html#MockObjectClasses}">Mock +Object Classes</a>.</p> + +<h2 id="testcase">Create a Test Case for Activity Unit Testing</h2> +<p>The {@link android.test.ActivityUnitTestCase} class provides support for +isolated testing of a single {@link android.app.Activity}. To create a unit +test for your {@link android.app.Activity}, your test class should extend +{@link android.test.ActivityUnitTestCase}.</p> + +<p>The {@link android.app.Activity} in an {@link android.test.ActivityUnitTestCase} +is not automatically started by Android Instrumentation. To start the +{@link android.app.Activity} in isolation, you need to explicitly call the +{@link android.test.ActivityUnitTestCase#startActivity(android.content.Intent, android.os.Bundle, java.lang.Object) startActivity()} +method, and pass in the {@link android.content.Intent} to +launch your target {@link android.app.Activity}.</p> + +<p>For example:</p> +<pre> +public class LaunchActivityTest + extends ActivityUnitTestCase<LaunchActivity> { + ... + + @Override + protected void setUp() throws Exception { + super.setUp(); + mLaunchIntent = new Intent(getInstrumentation() + .getTargetContext(), LaunchActivity.class); + startActivity(mLaunchIntent, null, null); + final Button launchNextButton = + (Button) getActivity() + .findViewById(R.id.launch_next_activity_button); + } +} +</pre> + +<h2 id="test_method">Validate Launch of Another Activity</h2> +<p id="test_goals">Your unit testing goals might include:</p> +<ul> +<li>Verifying that {@code LaunchActivity} fires an +{@link android.content.Intent} when a button is pushed clicked.</li> +<li>Verifying that the launched {@link android.content.Intent} contains the +correct payload data.</li> +</ul> + +<p>To verify if an {@link android.content.Intent} was triggered +following the {@link android.widget.Button} click, you can use the +{@link android.test.ActivityUnitTestCase#getStartedActivityIntent()} method. +By using assertion methods, you can verify that the returned +{@link android.content.Intent} is not null, and that it contains the expected +string value to launch the next {@link android.app.Activity}. If both assertions +evaluate to {@code true}, you've successfully verified that the +{@link android.content.Intent} was correctly sent by your +{@link android.app.Activity}.</p> + +<p>You might implement your test method like this:</p> +<pre> +@MediumTest +public void testNextActivityWasLaunchedWithIntent() { + startActivity(mLaunchIntent, null, null); + final Button launchNextButton = + (Button) getActivity() + .findViewById(R.id.launch_next_activity_button); + launchNextButton.performClick(); + + final Intent launchIntent = getStartedActivityIntent(); + assertNotNull("Intent was null", launchIntent); + assertTrue(isFinishCalled()); + + final String payload = + launchIntent.getStringExtra(NextActivity.EXTRAS_PAYLOAD_KEY); + assertEquals("Payload is empty", LaunchActivity.STRING_PAYLOAD, payload); +} +</pre> +<p>Because {@code LaunchActivity} runs in isolation, you cannot use the +{@link android.test.TouchUtils} library to manipulate UI controls. To directly +click a {@link android.widget.Button}, you can call the +{@link android.view.View#performClick()} method instead.</p> + + + + + + + diff --git a/docs/html/training/activity-testing/index.jd b/docs/html/training/activity-testing/index.jd new file mode 100644 index 0000000..ddede71 --- /dev/null +++ b/docs/html/training/activity-testing/index.jd @@ -0,0 +1,68 @@ +page.title=Testing Your Android Activity +page.tags="testing" + +trainingnavtop=true +startpage=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- Required platform, tools, add-ons, devices, knowledge, etc. --> +<h2>Dependencies and prerequisites</h2> +<ul> + <li>Android 2.2 (API Level 8) or higher.</li> +</ul> + +<h2>You Should Also Read</h2> +<ul> +<li><a href="{@docRoot}tools/testing/index.html">Testing +(Developer's Guide)</a></li> +</ul> + +</div> +</div> + +<p>You should be writing and running tests as part of your Android application +development cycle. Well-written tests can help you to catch bugs early in +development and give you confidence in your code.</p> + +<p>A <em>test case</em> defines a set of objects and methods to run multiple +tests independently from each other. Test cases can be organized into +<em>test suites</em> and run programmatically, in a repeatable manner, with +a <em>test runner</em> provided by a testing framework.</p> + +<p>The lessons in this class teaches you how to use the Android's custom +testing framework that is based on the popular JUnit framework. You can +write test cases to verify specific behavior in your application, and check for +consistency across different Android devices. Your test cases also serve as a +form of internal code documentation by describing the expected behavior of +app components.</p> + +<h2>Lessons</h2> + +<!-- Create a list of the lessons in this class along with a short description +of each lesson. These should be short and to the point. It should be clear from +reading the summary whether someone will want to jump to a lesson or not.--> + +<dl> + <dt><b><a href="preparing-activity-testing.html">Setting Up Your Test +Environment</a></b></dt> + <dd>Learn how to create your test project.</dd> + <dt><b><a href="activity-basic-testing.html">Creating and Running a Test +Case</a></b></dt> + <dd>Learn how to write test cases to verify the +expected properties of your {@link android.app.Activity}, and run the test +cases with the {@code Instrumentation} test runner provided by the Android +framework.</dd> + <dt><b><a href="activity-ui-testing.html">Testing UI Components</a></b></dt> + <dd>Learn how to test the behavior of specific UI +components in your {@link android.app.Activity}.</dd> + <dt><b><a href="activity-unit-testing.html">Creating Unit Tests</a></b></dt> + <dd>Learn how to how to perform unit testing to +verify the behavior of an Activity in isolation.</dd> + <dt><b><a href="activity-functional-testing.html">Creating Functional Tests</a></b></dt> + <dd>Learn how to perform functional testing to +verify the interaction of multiple Activities.</dd> + diff --git a/docs/html/training/activity-testing/preparing-activity-testing.jd b/docs/html/training/activity-testing/preparing-activity-testing.jd new file mode 100644 index 0000000..c43c9ed --- /dev/null +++ b/docs/html/training/activity-testing/preparing-activity-testing.jd @@ -0,0 +1,95 @@ +page.title=Setting Up Your Test Environment +trainingnavtop=true + +@jd:body + +<!-- This is the training bar --> +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to</h2> +<ol> + <li><a href="#eclipse">Set Up Eclipse for Testing</a></li> + <li><a href="#cmdline">Set Up the Command Line Interface for Testing</a></li> +</ol> + +<h2>You should also read</h2> +<ul> +<li><a href="{@docRoot}sdk/index.html">Getting the SDK Bundle</a></li> +<li><a href="{@docRoot}tools/testing/testing_eclipse.html">Testing from Eclipse +with ADT</a></li> +<li><a href="{@docRoot}tools/testing/testing_otheride.html">Testing from Other +IDEs</a></li> +</ul> + +<h2>Try it out</h2> +<div class="download-box"> + <a href="http://developer.android.com/shareables/training/AndroidTestingFun.zip" +class="button">Download the demo</a> + <p class="filename">AndroidTestingFun.zip</p> +</div> + +</div> +</div> + +<p>Before you start writing and running your tests, you should set up your test +development environment. This lesson teaches you how to set up the Eclipse +IDE to build and run tests, and how to +build and run tests with the Gradle framework by using the command line +interface.</p> + +<p class="note"><strong>Note:</strong> To help you get started, the lessons are +based on Eclipse with the ADT plugin. However, for your own test development, you +are free to use the IDE of your choice or the command-line.</p> + +<h2 id="eclipse">Set Up Eclipse for Testing</h2> +<p>Eclipse with the Android Developer Tools (ADT) plugin provides an integrated +development environment for you to create, build, and run Android application +test cases from a graphical user interface (GUI). A convenient feature that +Eclipse provides is the ability to auto-generate a new test project that +corresponds with your Android application project</a>. + +<p>To set up your test environment in Eclipse:</p> + +<ol> +<li><a href="{@docRoot}sdk/installing/bundle.html">Download and install the +Eclipse ADT plugin</a>, if you haven’t installed it yet.</li> +<li>Import or create the Android application project that you want to test +against.</li> +<li>Generate a test project that corresponds to the application project under +test. To generate a test project for the app project that you imported:</p> + <ol type="a"> + <li>In the Package Explorer, right-click on your app project, then +select <strong>Android Tools</strong> > <strong>New Test Project</strong>.</li> + <li>In the New Android Test Project wizard, set the property +values for your test project then click <strong>Finish</strong>.</li> + </ol> +</li> +</ol> +<p>You should now be able to create, build, and run test +cases from your Eclipse environment. To learn how to perform these tasks in +Eclipse, proceed to <a href="activity-basic-testing.html">Creating and Running +a Test Case</a>.</p> + +<h2 id="cmdline">Set Up the Command Line Interface for Testing</h2> +<p>If you are using Gradle version 1.6 or higher as your build environment, you +can build and run your Android application tests from the command line by using +the Gradle Wrapper. Make sure that in your {@code gradle.build} file, the +<a href={@docRoot}guide/topics/manifest/uses-sdk-element.html#min>minSdkVersion</a> +attribute in the {@code defaultConfig} section is set to 8 or higher. You can +refer to the sample {@code gradle.build} file that is +included in the download bundle for this training class.</p> +<p>To run your tests with the Gradle Wrapper:</p> +<ol> + <li>Connect a physical Android device to your machine or launch the Android +Emulator.</li> + <li>Run the following command from your project directory: + <pre>./gradlew build connectedCheck</pre> + </li> +</ol> +<p>To learn more about using Gradle for Android testing, see the +<a href="//tools.android.com/tech-docs/new-build-system/user-guide#TOC-Testing">Gradle Plugin User Guide</a>.</p> +<p>To learn more about using command line tools other than Gradle for test +development, see +<a href="{@docRoot}tools/testing/testing_otheride.html">Testing from Other IDEs</a>.</p> + diff --git a/docs/html/training/testing.jd b/docs/html/training/testing.jd new file mode 100644 index 0000000..c55370d --- /dev/null +++ b/docs/html/training/testing.jd @@ -0,0 +1,7 @@ +page.title=Best Practices for Testing +page.trainingcourse=true + +@jd:body + +<p>These classes and articles provide information about how to +test your Android application.</p> diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 40c170e..b884620 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -1205,6 +1205,45 @@ include the action bar on devices running Android 2.1 or higher." </li> <!-- End security and user info --> + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot ?>training/testing.html"> + <span class="small">Best Practices for</span><br/> + Testing + </a> + </div> + <ul> + <li class="nav-section"> + <div class="nav-section-header"><a href="<?cs var:toroot ?>training/activity-testing/index.html" + description="How to test Activities in your Android applications."> + Testing Your Activity + </a></div> + <ul> + <li><a href="<?cs var:toroot ?>training/activity-testing/preparing-activity-testing.html"> + <span class="en">Setting Up Your Test Environment</span> + </a> + </li> + <li><a href="<?cs var:toroot ?>training/activity-testing/activity-basic-testing.html"> + <span class="en">Creating and Running a Test Case</span> + </a> + </li> + <li><a href="<?cs var:toroot ?>training/activity-testing/activity-ui-testing.html"> + <span class="en">Testing UI Components</span> + </a> + </li> + <li><a href="<?cs var:toroot ?>training/activity-testing/activity-unit-testing.html"> + <span class="en">Creating Unit Tests</span> + </a> + </li> + <li><a href="<?cs var:toroot ?>training/activity-testing/activity-functional-testing.html"> + <span class="en">Creating Functional Tests</span> + </a> + </li> + </ul> + </li> + </ul> + </li> + <!-- End best Testing --> <li class="nav-section"> <div class="nav-section-header"> diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 1c426fd..1721bee 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -23,7 +23,6 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; -import java.io.BufferedInputStream; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; @@ -545,28 +544,28 @@ public class BitmapFactory { return null; } - Bitmap bm; + Bitmap bm = null; Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap"); try { - // we need mark/reset to work properly - if (!is.markSupported()) { - is = new BufferedInputStream(is, DECODE_BUFFER_SIZE); - } - - // so we can call reset() if a given codec gives up after reading up to - // this many bytes. FIXME: need to find out from the codecs what this - // value should be. - is.mark(1024); - + boolean decodeGenericStream = true; if (is instanceof AssetManager.AssetInputStream) { final int asset = ((AssetManager.AssetInputStream) is).getAssetInt(); bm = nativeDecodeAsset(asset, outPadding, opts); - } else { - // pass some temp storage down to the native code. 1024 is made up, - // but should be large enough to avoid too many small calls back - // into is.read(...) This number is not related to the value passed - // to mark(...) above. + // Do not follow the normal case. + decodeGenericStream = false; + } else if (is instanceof FileInputStream) { + try { + FileDescriptor fd = ((FileInputStream) is).getFD(); + // decodeFileDescriptor will take care of throwing the IAE and + // calling setDensityFromOptions. + return decodeFileDescriptor(fd, outPadding, opts); + } catch (IOException e) { + // Fall through to nativeDecodeStream. + } + } + + if (decodeGenericStream) { byte [] tempStorage = null; if (opts != null) tempStorage = opts.inTempStorage; if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE]; @@ -610,26 +609,41 @@ public class BitmapFactory { * no bitmap is returned (null) then padding is * unchanged. * @param opts null-ok; Options that control downsampling and whether the - * image should be completely decoded, or just is size returned. + * image should be completely decoded, or just its size returned. * @return the decoded bitmap, or null */ public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) { - if (nativeIsSeekable(fd)) { - Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts); + Bitmap bm; + + Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeFileDescriptor"); + try { + if (nativeIsSeekable(fd)) { + bm = nativeDecodeFileDescriptor(fd, outPadding, opts); + } else { + FileInputStream fis = new FileInputStream(fd); + // FIXME: If nativeDecodeStream grabbed the pointer to tempStorage + // from Options, this code would not need to be duplicated. + byte [] tempStorage = null; + if (opts != null) tempStorage = opts.inTempStorage; + if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE]; + try { + bm = nativeDecodeStream(fis, tempStorage, outPadding, opts); + } finally { + try { + fis.close(); + } catch (Throwable t) {/* ignore */} + } + } + if (bm == null && opts != null && opts.inBitmap != null) { throw new IllegalArgumentException("Problem decoding into existing bitmap"); } - return bm; - } else { - FileInputStream fis = new FileInputStream(fd); - try { - return decodeStream(fis, outPadding, opts); - } finally { - try { - fis.close(); - } catch (Throwable t) {/* ignore */} - } + + setDensityFromOptions(bm, opts); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); } + return bm; } /** diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java index b38d107..3524b25 100644 --- a/graphics/java/android/graphics/BitmapRegionDecoder.java +++ b/graphics/java/android/graphics/BitmapRegionDecoder.java @@ -17,7 +17,6 @@ package android.graphics; import android.content.res.AssetManager; -import java.io.BufferedInputStream; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; @@ -108,12 +107,6 @@ public final class BitmapRegionDecoder { */ public static BitmapRegionDecoder newInstance(InputStream is, boolean isShareable) throws IOException { - // we need mark/reset to work properly in JNI - - if (!is.markSupported()) { - is = new BufferedInputStream(is, 16 * 1024); - } - if (is instanceof AssetManager.AssetInputStream) { return nativeNewInstance( ((AssetManager.AssetInputStream) is).getAssetInt(), diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index 7d05a74..ca72c25 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -80,7 +80,7 @@ public class Allocation extends BaseObj { int mCurrentCount; static HashMap<Integer, Allocation> mAllocationMap = new HashMap<Integer, Allocation>(); - IoInputNotifier mBufferNotifier; + OnBufferAvailableListener mBufferNotifier; /** * The usage of the Allocation. These signal to RenderScript where to place @@ -1838,26 +1838,22 @@ public class Allocation extends BaseObj { } /** - * @hide - * * Interface to handle notification when new buffers are available via * {@link #USAGE_IO_INPUT}. An application will receive one notification * when a buffer is available. Additional buffers will not trigger new * notifications until a buffer is processed. */ - public interface IoInputNotifier { + public interface OnBufferAvailableListener { public void onBufferAvailable(Allocation a); } /** - * @hide - * * Set a notification handler for {@link #USAGE_IO_INPUT}. * - * @param callback instance of the IoInputNotifier class to be called - * when buffer arrive. + * @param callback instance of the OnBufferAvailableListener + * class to be called when buffer arrive. */ - public void setIoInputNotificationHandler(IoInputNotifier callback) { + public void setOnBufferAvailableListener(OnBufferAvailableListener callback) { synchronized(mAllocationMap) { mAllocationMap.put(new Integer(getID(mRS)), this); mBufferNotifier = callback; diff --git a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java index 6881627..32c3d15 100644 --- a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java +++ b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java @@ -56,8 +56,12 @@ public final class ScriptIntrinsicColorMatrix extends ScriptIntrinsic { * this parameter is ignored. The Element type check is * performed in the kernel launch. * + * @deprecated Use the single argument version as Element is now + * ignored. + * * @return ScriptIntrinsicColorMatrix */ + @Deprecated public static ScriptIntrinsicColorMatrix create(RenderScript rs, Element e) { return create(rs); } diff --git a/graphics/java/android/renderscript/ScriptIntrinsicHistogram.java b/graphics/java/android/renderscript/ScriptIntrinsicHistogram.java index f143326..adc2d95 100644 --- a/graphics/java/android/renderscript/ScriptIntrinsicHistogram.java +++ b/graphics/java/android/renderscript/ScriptIntrinsicHistogram.java @@ -151,7 +151,7 @@ public final class ScriptIntrinsicHistogram extends ScriptIntrinsic { * * @param ain The input image */ - public void forEach_dot(Allocation ain) { + public void forEach_Dot(Allocation ain) { if (mOut.getType().getElement().getVectorSize() != 1) { throw new RSIllegalArgumentException("Output vector size must be one."); } @@ -170,7 +170,7 @@ public final class ScriptIntrinsicHistogram extends ScriptIntrinsic { * * @return Script.KernelID The KernelID object. */ - public Script.KernelID getKernelID_seperate() { + public Script.KernelID getKernelID_Separate() { return createKernelID(0, 3, null, null); } diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 7f1d946..92edb8a 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -155,7 +155,7 @@ CpuConsumer::LockedBuffer* JNIImageReaderContext::getLockedBuffer() { return buffer; } -void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer * buffer) { +void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer* buffer) { mBuffers.push_back(buffer); } @@ -698,8 +698,11 @@ static jboolean ImageReader_imageSetup(JNIEnv* env, jobject thiz, CpuConsumer* consumer = ctx->getCpuConsumer(); CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer(); if (buffer == NULL) { - ALOGE("Unable to acquire a lockedBuffer, very likely client tries to lock more than" - "maxImages buffers"); + ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than" + " maxImages buffers"); + jniThrowException(env, OutOfResourcesException, + "Too many outstanding images, close existing images" + " to be able to acquire more."); return false; } status_t res = consumer->lockNextBuffer(buffer); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java index fbae8b1..40d55cf 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java @@ -16,6 +16,7 @@ package com.android.keyguard; import android.animation.ObjectAnimator; +import android.app.ActivityManager; import android.app.PendingIntent; import android.app.SearchManager; import android.app.admin.DevicePolicyManager; @@ -23,7 +24,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; -import android.os.Build; import android.os.Bundle; import android.os.PowerManager; import android.os.UserHandle; @@ -41,15 +41,15 @@ import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.multiwaveview.GlowPadView; import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener; -import com.android.keyguard.KeyguardHostView.OnDismissAction; public class KeyguardSelectorView extends LinearLayout implements KeyguardSecurityView { private static final boolean DEBUG = KeyguardHostView.DEBUG; private static final String TAG = "SecuritySelectorView"; private static final String ASSIST_ICON_METADATA_NAME = "com.android.systemui.action_assist_icon"; - // Flag to enable/disable hotword detection on lock screen. - private static final boolean FLAG_HOTWORD = true; + + // Don't enable hotword on limited-memory devices. + private static final boolean ENABLE_HOTWORD = !ActivityManager.isLowRamDeviceStatic(); // TODO: Fix this to be non-static. private static HotwordRecognizer sHotwordClient; @@ -132,7 +132,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri @Override public void onPhoneStateChanged(int phoneState) { - if (FLAG_HOTWORD) { + if (ENABLE_HOTWORD) { // We need to stop hotword detection when a call state is not idle anymore. if (phoneState != TelephonyManager.CALL_STATE_IDLE) { if (DEBUG) Log.d(TAG, "Stopping due to call state not being idle"); @@ -183,7 +183,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame); mBouncerFrame = bouncerFrameView.getBackground(); - if (FLAG_HOTWORD && sHotwordClient == null) { + if (ENABLE_HOTWORD && sHotwordClient == null) { sHotwordClient = HotwordRecognizer.createHotwordRecognizer(getContext()); } } @@ -334,7 +334,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri * it attempts to stop hotword detection if it's running. */ private void maybeStartHotwordDetector() { - if (FLAG_HOTWORD && sHotwordClient != null) { + if (ENABLE_HOTWORD && sHotwordClient != null) { if (DEBUG) Log.d(TAG, "maybeStartHotwordDetector()"); // Don't start it if the screen is off or not showing PowerManager powerManager = (PowerManager) getContext().getSystemService( @@ -364,7 +364,7 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri * Stop hotword detector if HOTWORDING_ENABLED is true. */ private void maybeStopHotwordDetector() { - if (FLAG_HOTWORD && sHotwordClient != null) { + if (ENABLE_HOTWORD && sHotwordClient != null) { if (DEBUG) Log.d(TAG, "maybeStopHotwordDetector()"); try { sHotwordClient.stopRecognition(); diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk index 8ae0302..f65fe4b 100644 --- a/packages/PrintSpooler/Android.mk +++ b/packages/PrintSpooler/Android.mk @@ -24,8 +24,6 @@ LOCAL_PACKAGE_NAME := PrintSpooler LOCAL_JAVA_LIBRARIES := framework-base -LOCAL_CERTIFICATE := platform - LOCAL_PROGUARD_ENABLED := disabled include $(BUILD_PACKAGE) diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index ab7ea09..6fa3ed4 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -20,18 +20,22 @@ package="com.android.printspooler" android:sharedUserId="android.uid.printspooler" android:versionName="1" - android:versionCode="1" - coreApp="true"> + android:versionCode="1"> - <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/> + <!-- Allows an application to call APIs that give it access to all print jobs + on the device. Usually an app can access only the print jobs it created. + --> + <permission + android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS" + android:label="@string/permlab_accessAllPrintJobs" + android:description="@string/permdesc_accessAllPrintJobs" + android:protectionLevel="signature" /> + <uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/> <uses-permission android:name="android.permission.ACCESS_ALL_PRINT_JOBS"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> - <permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE" - android:label="@string/permlab_bindPrintSpoolerService" - android:description="@string/permdesc_bindPrintSpoolerService" - android:protectionLevel="signature" /> + <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/> <application android:allowClearUserData="false" diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index ee3cf84..235a7a1 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -94,6 +94,9 @@ <!-- Template for the notificaiton label for a failed print job. [CHAR LIMIT=25] --> <string name="failed_notification_title_template">Printer error <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string> + <!-- Template for the notificaiton label for a blocked print job. [CHAR LIMIT=25] --> + <string name="blocked_notification_title_template">Printer blocked <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string> + <!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] --> <string name="cancel">Cancel</string> @@ -103,6 +106,9 @@ <!-- Message that there is no connection to a printer. [CHAR LIMIT=40] --> <string name="no_connection_to_printer">No connection to printer</string> + <!-- Label for an unknown reason for failed or blocked print job. [CHAR LIMIT=25] --> + <string name="reason_unknown">unknown</string> + <!-- Arrays --> <!-- Color mode labels. --> @@ -129,12 +135,14 @@ <item>Range</item> </string-array> - <!-- Title of an application permission, listed so the user can choose - whether they want to allow the application to do this. --> - <string name="permlab_bindPrintSpoolerService">bind to a print spooler service</string> - <!-- Description of an application permission, listed so the user can - choose whether they want to allow the application to do this. --> - <string name="permdesc_bindPrintSpoolerService">Allows the holder to bind to the top-level - interface of a print spooler service. Should never be needed for normal apps.</string> + <!-- Permissions --> + + <!-- Title of an application permission, listed so the user can choose whether they want + to allow the application to do this. --> + <string name="permlab_accessAllPrintJobs">access all print jobs</string> + <!-- Description of an application permission, listed so the user can choose whether + they want to allow the application to do this. --> + <string name="permdesc_accessAllPrintJobs">Allows the holder to access print jobs + created by another app. Should never be needed for normal apps.</string> </resources> diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java index 28fd0e0..ad8d95a 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java +++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java @@ -75,6 +75,8 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { private List<PrinterInfo> mFavoritePrinters; + private PrinterId mTrackedPrinter; + public FusedPrintersProvider(Context context) { super(context); mPersistenceManager = new PersistenceManager(context); @@ -166,6 +168,10 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { private boolean cancelInternal() { if (mDiscoverySession != null && mDiscoverySession.isPrinterDiscoveryStarted()) { + if (mTrackedPrinter != null) { + mDiscoverySession.stopPrinterStateTracking(mTrackedPrinter); + mTrackedPrinter = null; + } mDiscoverySession.stopPrinterDiscovery(); return true; } else if (mPersistenceManager.isReadHistoryInProgress()) { @@ -195,10 +201,14 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> { onStopLoading(); } - public void refreshPrinter(PrinterId printerId) { + public void setTrackedPrinter(PrinterId printerId) { if (isStarted() && mDiscoverySession != null && mDiscoverySession.isPrinterDiscoveryStarted()) { - mDiscoverySession.requestPrinterUpdate(printerId); + if (mTrackedPrinter != null) { + mDiscoverySession.stopPrinterStateTracking(mTrackedPrinter); + } + mTrackedPrinter = printerId; + mDiscoverySession.startPrinterStateTracking(printerId); } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java index c116d37..43a751c 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java +++ b/packages/PrintSpooler/src/com/android/printspooler/NotificationController.java @@ -32,6 +32,7 @@ import android.os.UserHandle; import android.print.IPrintManager; import android.print.PrintJobInfo; import android.print.PrintManager; +import android.text.TextUtils; import android.util.Log; /** @@ -64,22 +65,27 @@ public class NotificationController { + " state:" + PrintJobInfo.stateToString(printJob.getState())); } switch (printJob.getState()) { - case PrintJobInfo.STATE_QUEUED: { - createPrintingNotificaiton(printJob); + case PrintJobInfo.STATE_QUEUED: + case PrintJobInfo.STATE_STARTED: { + createPrintingNotification(printJob); } break; case PrintJobInfo.STATE_FAILED: { - createFailedNotificaiton(printJob); + createFailedNotification(printJob); } break; case PrintJobInfo.STATE_COMPLETED: case PrintJobInfo.STATE_CANCELED: { removeNotification(printJob.getId()); } break; + + case PrintJobInfo.STATE_BLOCKED: { + createBlockedNotification(printJob); + } break; } } - private void createPrintingNotificaiton(PrintJobInfo printJob) { + private void createPrintingNotification(PrintJobInfo printJob) { Notification.Builder builder = new Notification.Builder(mContext) .setSmallIcon(R.drawable.stat_notify_print) .setContentTitle(mContext.getString(R.string.printing_notification_title_template, @@ -93,17 +99,36 @@ public class NotificationController { mNotificationManager.notify(printJob.getId(), builder.build()); } - private void createFailedNotificaiton(PrintJobInfo printJob) { + private void createFailedNotification(PrintJobInfo printJob) { + String reason = !TextUtils.isEmpty(printJob.getStateReason()) + ? printJob.getStateReason() : mContext.getString(R.string.reason_unknown); + Notification.Builder builder = new Notification.Builder(mContext) .setSmallIcon(R.drawable.stat_notify_error) .setContentTitle(mContext.getString(R.string.failed_notification_title_template, printJob.getLabel())) .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), createCancelIntent(printJob)) - // TODO: Use appropriate icon when assets are ready .addAction(android.R.drawable.ic_secure, mContext.getString(R.string.restart), createRestartIntent(printJob.getId())) - .setContentText(printJob.getFailureReason()) + .setContentText(reason) + .setWhen(System.currentTimeMillis()) + .setOngoing(true) + .setShowWhen(true); + mNotificationManager.notify(printJob.getId(), builder.build()); + } + + private void createBlockedNotification(PrintJobInfo printJob) { + String reason = !TextUtils.isEmpty(printJob.getStateReason()) + ? printJob.getStateReason() : mContext.getString(R.string.reason_unknown); + + Notification.Builder builder = new Notification.Builder(mContext) + .setSmallIcon(R.drawable.stat_notify_error) + .setContentTitle(mContext.getString(R.string.blocked_notification_title_template, + printJob.getLabel())) + .addAction(R.drawable.stat_notify_cancelling, mContext.getString(R.string.cancel), + createCancelIntent(printJob)) + .setContentText(reason) .setWhen(System.currentTimeMillis()) .setOngoing(true) .setShowWhen(true); diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index 607be90..520331c 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -473,6 +473,11 @@ public class PrintJobConfigActivity extends Activity { mControllerState = CONTROLLER_STATE_WRITE_COMPLETED; + // Update the document size. + File file = PrintSpoolerService.peekInstance() + .generateFileForPrintJob(mPrintJobId); + mDocument.info.setDataSize(file.length()); + // Update which pages we have fetched. mDocument.pages = PageRangeUtils.normalize(pages); @@ -1117,7 +1122,7 @@ public class PrintJobConfigActivity extends Activity { (Loader<?>) getLoaderManager().getLoader( LOADER_ID_PRINTERS_LOADER); if (printersLoader != null) { - printersLoader.refreshPrinter(printer.getId()); + printersLoader.setTrackedPrinter(printer.getId()); } } } @@ -1351,10 +1356,6 @@ public class PrintJobConfigActivity extends Activity { return mEditorState == EDITOR_STATE_CONFIRMED_PRINT; } -// public void confirmPreview() { -// mEditorState = EDITOR_STATE_CONFIRMED_PREVIEW; -// } - public PageRange[] getRequestedPages() { if (hasErrors()) { return null; @@ -1374,7 +1375,7 @@ public class PrintJobConfigActivity extends Activity { toIndex = Integer.parseInt(range.substring( dashIndex + 1, range.length())) - 1; } else { - fromIndex = toIndex = Integer.parseInt(range); + fromIndex = toIndex = Integer.parseInt(range) - 1; } PageRange pageRange = new PageRange(fromIndex, toIndex); diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java index c1f4180..dd2598c 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java @@ -335,7 +335,9 @@ public final class PrintSpoolerService extends Service { final boolean sameState = (state == printJob.getState()) || (state == PrintJobInfo.STATE_ANY) || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS - && printJob.getState() > PrintJobInfo.STATE_CREATED); + && isStateVisibleToUser(printJob.getState())) + || (state == PrintJobInfo.STATE_ANY_ACTIVE + && isActiveState(printJob.getState())); if (sameComponent && sameAppId && sameState) { if (foundPrintJobs == null) { foundPrintJobs = new ArrayList<PrintJobInfo>(); @@ -347,6 +349,11 @@ public final class PrintSpoolerService extends Service { return foundPrintJobs; } + private boolean isStateVisibleToUser(int state) { + return (isActiveState(state) && (state == PrintJobInfo.STATE_FAILED + || state == PrintJobInfo.STATE_COMPLETED|| state == PrintJobInfo.STATE_CANCELED)); + } + public PrintJobInfo getPrintJobInfo(int printJobId, int appId) { synchronized (mLock) { final int printJobCount = mPrintJobs.size(); @@ -389,14 +396,12 @@ public final class PrintSpoolerService extends Service { switch (printJob.getState()) { case PrintJobInfo.STATE_QUEUED: - case PrintJobInfo.STATE_STARTED: { - // We have a print job that was queued or started in the - // past - // but the device battery died or a crash occurred. In this - // case - // we assume the print job failed and let the user decide - // whether - // to restart the job or just + case PrintJobInfo.STATE_STARTED: + case PrintJobInfo.STATE_BLOCKED: { + // We have a print job that was queued or started or blocked in + // the past but the device battery died or a crash occurred. In + // this case we assume the print job failed and let the user + // decide whether to restart the job or just cancel it. setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, getString(R.string.no_connection_to_printer)); } @@ -501,7 +506,7 @@ public final class PrintSpoolerService extends Service { success = true; printJob.setState(state); - printJob.setFailureReason(error); + printJob.setStateReason(error); mNotificationController.onPrintJobStateChanged(printJob); if (DEBUG_PRINT_JOB_LIFECYCLE) { @@ -568,7 +573,8 @@ public final class PrintSpoolerService extends Service { private boolean isActiveState(int printJobState) { return printJobState == PrintJobInfo.STATE_CREATED || printJobState == PrintJobInfo.STATE_QUEUED - || printJobState == PrintJobInfo.STATE_STARTED; + || printJobState == PrintJobInfo.STATE_STARTED + || printJobState == PrintJobInfo.STATE_BLOCKED; } public boolean setPrintJobTag(int printJobId, String tag) { diff --git a/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png Binary files differdeleted file mode 100644 index a8075d5..0000000 --- a/packages/SystemUI/res/drawable-hdpi/arrow_dashed.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png Binary files differdeleted file mode 100644 index aea8beb..0000000 --- a/packages/SystemUI/res/drawable-hdpi/btn_cling_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png Binary files differdeleted file mode 100644 index ebefd20..0000000 --- a/packages/SystemUI/res/drawable-hdpi/btn_cling_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png Binary files differdeleted file mode 100644 index 6f456f3..0000000 --- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png Binary files differdeleted file mode 100644 index e592ae6..0000000 --- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png Binary files differdeleted file mode 100644 index c1f87a7..0000000 --- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_normal_disable_focused.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png Binary files differdeleted file mode 100644 index 2d16eda..0000000 --- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png Binary files differdeleted file mode 100644 index 0749413..0000000 --- a/packages/SystemUI/res/drawable-hdpi/btn_default_small_selected.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index b5d8518..0000000 --- a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png Binary files differindex 652f66f..080f2f2 100644 --- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png +++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_dragging.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png Binary files differindex d000f7e..8b45500 100644 --- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png +++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_normal.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png Binary files differindex 288d818..e591a7b 100644 --- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png +++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png Binary files differindex 2509321..da56dcc 100644 --- a/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png +++ b/packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png Binary files differindex 773d418..2c55017 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_alarm.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png Binary files differindex ddf6b12..9befc34 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png Binary files differindex 859f7b1..58f67d0 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png Binary files differindex 2f2f291..b794c9a 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png Binary files differindex de6988f..6253d9a 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png Binary files differindex e322aa1..6253d9a 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png Binary files differindex cf9c992..0bed6d9 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png Binary files differindex 4892842..0b27331 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png Binary files differindex 4273a52..6bb92a3 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png Binary files differindex 201689b..c77c37f 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png Binary files differindex 0457c50..92e6837 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png Binary files differindex 22dc516..269eae2 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png Binary files differindex 2fdea79..ac2eaf0 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png Binary files differindex 8c4ed12..d9da0d9 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png Binary files differindex 56c497a..e02a84b 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png Binary files differindex 9013bc6..2dc2b17 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_sync.png diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync_error.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_sync_error.png Binary files differindex 38d04f2..70f839f 100644 --- a/packages/SystemUI/res/drawable-hdpi/stat_sys_sync_error.png +++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_sync_error.png diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_bg_tile.png b/packages/SystemUI/res/drawable-hdpi/status_bar_bg_tile.png Binary files differdeleted file mode 100644 index aee197c..0000000 --- a/packages/SystemUI/res/drawable-hdpi/status_bar_bg_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png Binary files differindex 0c301ab..6feb622 100644 --- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png +++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_off.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png Binary files differindex ec0424a..eeee60f 100644 --- a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png +++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png diff --git a/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png Binary files differdeleted file mode 100644 index 4650417..0000000 --- a/packages/SystemUI/res/drawable-hdpi/title_bar_shadow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png Binary files differdeleted file mode 100644 index c17c668..0000000 --- a/packages/SystemUI/res/drawable-mdpi/arrow_dashed.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png Binary files differdeleted file mode 100644 index 43a407e..0000000 --- a/packages/SystemUI/res/drawable-mdpi/btn_cling_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png Binary files differdeleted file mode 100644 index bf0c8cb..0000000 --- a/packages/SystemUI/res/drawable-mdpi/btn_cling_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png Binary files differdeleted file mode 100644 index 9b59b05..0000000 --- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png Binary files differdeleted file mode 100644 index b517af6..0000000 --- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png Binary files differdeleted file mode 100644 index 019f33a..0000000 --- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_normal_disable_focused.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png Binary files differdeleted file mode 100644 index 6ce1bd3..0000000 --- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png Binary files differdeleted file mode 100644 index 0633543..0000000 --- a/packages/SystemUI/res/drawable-mdpi/btn_default_small_selected.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index 5744885..0000000 --- a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png Binary files differindex 6f4d658..60dc3f2 100644 --- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png +++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_dragging.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png Binary files differindex f19dc93..4b7de52 100644 --- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png +++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_normal.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png Binary files differindex 10e4fd2..7dfea4c 100644 --- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png +++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png Binary files differindex be1cd31..295e91f 100644 --- a/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png +++ b/packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png Binary files differindex 7640c87..c6dc466 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_alarm.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png Binary files differindex f698605..2e24f6f 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png Binary files differindex 24717d7..1e05a91 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png Binary files differindex a77fe7f..f4afa52 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png Binary files differindex 43f5468..55173f8 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png Binary files differindex cadcd03..55173f8 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png Binary files differindex 54e0685..6649d7c 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png Binary files differindex 2efaf45..dcfe5b4 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png Binary files differindex d3bc458..be3fe62 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png Binary files differindex 9c3f44c..734c52a 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png Binary files differindex a7ba08a..0deb868 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png Binary files differindex e16bee6..d808990 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png Binary files differindex 7e1e8de..f890c2b 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png Binary files differindex e599443..0e11ce8 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png Binary files differindex 688b6d6..1ffeaa3 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png Binary files differindex 1cacf93..ad5b2ff 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_sync.png diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync_error.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_sync_error.png Binary files differindex 5425af4..6db607d 100644 --- a/packages/SystemUI/res/drawable-mdpi/stat_sys_sync_error.png +++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_sync_error.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_bg_tile.png b/packages/SystemUI/res/drawable-mdpi/status_bar_bg_tile.png Binary files differdeleted file mode 100644 index 6579ff9..0000000 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_bg_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png Binary files differindex 5c577cb..bd1cd12 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_close_off.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png Binary files differindex 7efb502..c73ff35 100644 --- a/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png +++ b/packages/SystemUI/res/drawable-mdpi/status_bar_close_on.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png Binary files differdeleted file mode 100644 index f334023..0000000 --- a/packages/SystemUI/res/drawable-mdpi/title_bar_shadow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png Binary files differnew file mode 100644 index 0000000..586a738 --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/heads_up_window_bg.9.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png Binary files differnew file mode 100644 index 0000000..8703e1d --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/notification_panel_bg.9.png diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_normal.9.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_normal.9.png Binary files differdeleted file mode 100644 index 88137e8..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_pressed.9.png Binary files differdeleted file mode 100644 index 6507a51..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-hdpi/notify_panel_clock_bg_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index 4ac131a..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-hdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-hdpi/sysbar_notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw720dp-hdpi/sysbar_notification_panel_bg.9.png Binary files differdeleted file mode 100644 index 0c20ba2..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-hdpi/sysbar_notification_panel_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_normal.9.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_normal.9.png Binary files differdeleted file mode 100644 index 798f589..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_pressed.9.png Binary files differdeleted file mode 100644 index 73247e5..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-mdpi/notify_panel_clock_bg_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index 4362836..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-mdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-mdpi/sysbar_notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw720dp-mdpi/sysbar_notification_panel_bg.9.png Binary files differdeleted file mode 100644 index 56cd238..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-mdpi/sysbar_notification_panel_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-tvdpi/sysbar_notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw720dp-tvdpi/sysbar_notification_panel_bg.9.png Binary files differdeleted file mode 100644 index 571a7a5..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-tvdpi/sysbar_notification_panel_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_normal.9.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_normal.9.png Binary files differdeleted file mode 100644 index 2b46c89..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_pressed.9.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_pressed.9.png Binary files differdeleted file mode 100644 index dd476b7..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/notify_panel_clock_bg_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index 3938502..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-sw720dp-xhdpi/sysbar_notification_panel_bg.9.png b/packages/SystemUI/res/drawable-sw720dp-xhdpi/sysbar_notification_panel_bg.9.png Binary files differdeleted file mode 100644 index 3f05767..0000000 --- a/packages/SystemUI/res/drawable-sw720dp-xhdpi/sysbar_notification_panel_bg.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png b/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png Binary files differdeleted file mode 100644 index c26ed9c..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/arrow_dashed.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png Binary files differdeleted file mode 100644 index 35511d6..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/btn_cling_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png Binary files differdeleted file mode 100644 index a38b40f..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/btn_cling_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal.9.png Binary files differdeleted file mode 100644 index 5e601d2..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable.9.png Binary files differdeleted file mode 100644 index ed92cd0..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable_focused.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable_focused.9.png Binary files differdeleted file mode 100644 index f77dbfb..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_normal_disable_focused.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_pressed.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_pressed.9.png Binary files differdeleted file mode 100644 index e34107b..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_selected.9.png b/packages/SystemUI/res/drawable-xhdpi/btn_default_small_selected.9.png Binary files differdeleted file mode 100644 index 8f70177..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/btn_default_small_selected.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png Binary files differdeleted file mode 100644 index e1e08c6..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png Binary files differindex 1d097c5..79d1b3c 100644 --- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png +++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_dragging.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png Binary files differindex 80fc849..c57ec67 100644 --- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png +++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_normal.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png Binary files differindex 5bae56d..f01a79e 100644 --- a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png +++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-xhdpi/screenshot_panel.9.png Binary files differindex c096c7a..511537a 100644 --- a/packages/SystemUI/res/drawable-xhdpi/screenshot_panel.9.png +++ b/packages/SystemUI/res/drawable-xhdpi/screenshot_panel.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png Binary files differindex c8882e0..8bca860 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_alarm.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png Binary files differindex dbd370d..a7f0017 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png Binary files differindex 19fa2e8..662d062 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png Binary files differindex bc41395..18be9c0 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png Binary files differindex f5843ad..8b34373 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png Binary files differindex df5138e..8b34373 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png Binary files differindex 41a46ed..610e78f 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png Binary files differindex a76bca3..f682a0e 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png Binary files differindex d4dca0b..5bb372e 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png Binary files differindex a91f099..ef05975 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png Binary files differindex 33e8072..d556733 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png Binary files differindex e1c0f71..c5088b5 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png Binary files differindex cad7427..e1bd8bd 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png Binary files differindex c36c6d9..c82a435 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png Binary files differindex 674be33..298b27d 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png Binary files differindex ab6f812..75b002d 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync.png diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync_error.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync_error.png Binary files differindex a7780cf..6276f47 100644 --- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync_error.png +++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_sync_error.png diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_bg_tile.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_bg_tile.png Binary files differdeleted file mode 100644 index d01b117..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/status_bar_bg_tile.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png Binary files differindex 98d0cfb..1fed081 100644 --- a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png +++ b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_off.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png Binary files differindex 17f4169..e931314 100644 --- a/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png +++ b/packages/SystemUI/res/drawable-xhdpi/status_bar_close_on.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-xhdpi/title_bar_shadow.9.png Binary files differdeleted file mode 100644 index 89f14db..0000000 --- a/packages/SystemUI/res/drawable-xhdpi/title_bar_shadow.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png Binary files differnew file mode 100644 index 0000000..586a738 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/heads_up_window_bg.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_menu_share.png b/packages/SystemUI/res/drawable-xxhdpi/ic_menu_share.png Binary files differnew file mode 100644 index 0000000..d450531 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_menu_share.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png Binary files differnew file mode 100644 index 0000000..0a46dde --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_15.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_orange.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_orange.png Binary files differnew file mode 100644 index 0000000..2b333d7 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_orange.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_red.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_red.png Binary files differnew file mode 100644 index 0000000..4c71154 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_red.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_white.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_white.png Binary files differnew file mode 100644 index 0000000..976a36b --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_bang_white.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_0.png Binary files differnew file mode 100644 index 0000000..82d4806 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_0.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png Binary files differnew file mode 100644 index 0000000..96d39db --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_battery_charge_15.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png Binary files differnew file mode 100644 index 0000000..0df6203 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_land.png Binary files differnew file mode 100644 index 0000000..b400b14 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_highlight_land.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png b/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png Binary files differnew file mode 100644 index 0000000..adcdcb7 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/notification_panel_bg.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_dragging.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_dragging.9.png Binary files differnew file mode 100644 index 0000000..c424ffe --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_dragging.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png Binary files differnew file mode 100644 index 0000000..a446448 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_normal.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png Binary files differnew file mode 100644 index 0000000..b7bbd82 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/recents_thumbnail_bg_press.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/screenshot_panel.9.png b/packages/SystemUI/res/drawable-xxhdpi/screenshot_panel.9.png Binary files differnew file mode 100644 index 0000000..45259d7 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/screenshot_panel.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png Binary files differindex ed4b8c4..d42d9d6 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_alarm.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png Binary files differindex 8e00f6d..ad34d49 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_device_access_location_found.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png Binary files differindex 4e511c6..aabf0aa 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png Binary files differindex efd0ca6..654c2a5 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0.png Binary files differindex 18f63e5..361ff48 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0_fully.png Binary files differindex 8106087..937839b 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0_fully.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_0_fully.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1.png Binary files differindex d863597..d185a4d 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1_fully.png Binary files differindex 01fce1a..2bd6eb1 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1_fully.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_1_fully.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2.png Binary files differindex f9ee187..9594607 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2_fully.png Binary files differindex e72fda6..aad369e 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2_fully.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_2_fully.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3.png Binary files differindex a1540d7..6f9f50c 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3_fully.png Binary files differindex eebc585..c76e188 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3_fully.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_3_fully.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4.png Binary files differindex bf22fbb..75a182f 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4_fully.png Binary files differindex 754e3b9..1889813 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4_fully.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_4_fully.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_null.png Binary files differindex 78e94c6..b388b8f 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_null.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_signal_null.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png Binary files differindex e36bf10..99b2fff 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync_error.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync_error.png Binary files differindex 274b02f..2f6a4c0 100644 --- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync_error.png +++ b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_sync_error.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png Binary files differnew file mode 100644 index 0000000..d50ff85 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_off.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png Binary files differnew file mode 100644 index 0000000..5d27ccd --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/status_bar_close_on.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/title_bar_shadow.9.png b/packages/SystemUI/res/drawable-xxhdpi/title_bar_shadow.9.png Binary files differnew file mode 100644 index 0000000..e86f891 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/title_bar_shadow.9.png diff --git a/packages/SystemUI/res/drawable/btn_default_small.xml b/packages/SystemUI/res/drawable/btn_default_small.xml deleted file mode 100644 index 5485ea0..0000000 --- a/packages/SystemUI/res/drawable/btn_default_small.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2008 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_window_focused="false" android:state_enabled="true" - android:drawable="@drawable/btn_default_small_normal" /> - <item android:state_window_focused="false" android:state_enabled="false" - android:drawable="@drawable/btn_default_small_normal_disable" /> - <item android:state_pressed="true" - android:drawable="@drawable/btn_default_small_pressed" /> - <item android:state_focused="true" android:state_enabled="true" - android:drawable="@drawable/btn_default_small_selected" /> - <item android:state_enabled="true" - android:drawable="@drawable/btn_default_small_normal" /> - <item android:state_focused="true" - android:drawable="@drawable/btn_default_small_normal_disable_focused" /> - <item - android:drawable="@drawable/btn_default_small_normal_disable" /> -</selector> - diff --git a/packages/SystemUI/res/drawable/cling_button_bg.xml b/packages/SystemUI/res/drawable/cling_button_bg.xml deleted file mode 100644 index d175f53..0000000 --- a/packages/SystemUI/res/drawable/cling_button_bg.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" android:drawable="@drawable/btn_cling_pressed" /> - <item android:drawable="@drawable/btn_cling_normal" /> -</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml b/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml deleted file mode 100644 index c83d878..0000000 --- a/packages/SystemUI/res/drawable/notify_panel_clock_bg.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" - android:drawable="@drawable/notify_panel_clock_bg_pressed" /> - <item android:drawable="@drawable/notify_panel_clock_bg_normal" /> -</selector> - diff --git a/packages/SystemUI/res/drawable/status_bar_bg.xml b/packages/SystemUI/res/drawable/status_bar_bg.xml deleted file mode 100644 index 403493b..0000000 --- a/packages/SystemUI/res/drawable/status_bar_bg.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<bitmap - xmlns:android="http://schemas.android.com/apk/res/android" - android:tileMode="repeat" - android:src="@drawable/status_bar_bg_tile" - /> diff --git a/packages/SystemUI/res/layout-land/status_bar_help.xml b/packages/SystemUI/res/layout-land/status_bar_help.xml deleted file mode 100644 index a885b86..0000000 --- a/packages/SystemUI/res/layout-land/status_bar_help.xml +++ /dev/null @@ -1,71 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -** -** Copyright 2012, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<!-- This is the combined status bar / notification panel window. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" - xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/status_bar_cling" - android:paddingStart="40dp" - android:paddingEnd="40dp" - android:background="#DD000000" - android:focusable="true" - android:orientation="horizontal" - android:gravity="top|start" - > - - <ImageView - android:layout_width="wrap_content" - android:layout_weight="0" - android:layout_height="wrap_content" - android:layout_marginEnd="50dp" - android:gravity="center" - android:src="@drawable/arrow_dashed" - tools:ignore="ContentDescription" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_weight="1" - android:orientation="vertical" - android:layout_marginTop="40dp" - > - <TextView - style="@style/ClingTitleText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/status_bar_help_title" /> - - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="30dp" - android:text="@string/status_bar_help_text" /> - - <Button - android:id="@+id/ok" - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:paddingStart="50dp" - android:paddingEnd="50dp" - android:text="@android:string/ok" /> - </LinearLayout> -</LinearLayout> diff --git a/packages/SystemUI/res/layout/status_bar_help.xml b/packages/SystemUI/res/layout/status_bar_help.xml deleted file mode 100644 index f638767..0000000 --- a/packages/SystemUI/res/layout/status_bar_help.xml +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -** -** Copyright 2012, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ ---> - -<!-- This is the combined status bar / notification panel window. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" - xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/status_bar_cling" - android:paddingStart="40dp" - android:paddingEnd="40dp" - android:background="#DD000000" - android:focusable="true" - android:orientation="vertical" - android:gravity="top|start" - > - - <ImageView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="50dp" - android:gravity="center" - android:src="@drawable/arrow_dashed" - tools:ignore="ContentDescription" /> - - <TextView - style="@style/ClingTitleText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/status_bar_help_title" /> - - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="30dp" - android:text="@string/status_bar_help_text" /> - - <Button - android:id="@+id/ok" - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:paddingStart="50dp" - android:paddingEnd="50dp" - android:text="@android:string/ok" /> - -</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml deleted file mode 100644 index d876a95..0000000 --- a/packages/SystemUI/res/values/ids.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2012 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - <item type="id" name="status_bar_cling_stub" /> -</resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 8e88610..3ffa6f4 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -493,10 +493,6 @@ <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] --> <string name="quick_settings_brightness_dialog_auto_brightness_label">AUTO</string> - <!-- Title of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] --> - <string name="status_bar_help_title">Notifications appear here</string> - <!-- Body of help text shown when the notification panel is pulled down for the very first time. [CHAR LIMIT=NONE] --> - <string name="status_bar_help_text">Access them anytime by swiping down.\nSwipe down again for system controls.</string> <!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. --> <string name="battery_meter_very_low_overlay_symbol">!</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index cd78041..134f228 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -159,33 +159,4 @@ <item name="android:textSize">14dp</item> </style> - <style name="ClingButton"> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:paddingTop">10dp</item> - <item name="android:paddingBottom">15dp</item> - <item name="android:paddingLeft">35dp</item> - <item name="android:paddingRight">35dp</item> - <item name="android:textStyle">bold</item> - <item name="android:background">@drawable/cling_button_bg</item> - </style> - <style name="ClingTitleText"> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:layout_marginBottom">5dp</item> - <item name="android:textSize">23sp</item> - <item name="android:textColor">#49C0EC</item> - <item name="android:shadowColor">#000000</item> - <item name="android:shadowDy">2</item> - <item name="android:shadowRadius">2.0</item> - </style> - <style name="ClingText"> - <item name="android:textSize">15sp</item> - <item name="android:textColor">#FFFFFF</item> - <item name="android:shadowColor">#000000</item> - <item name="android:shadowDy">2</item> - <item name="android:shadowRadius">2.0</item> - <item name="android:lineSpacingMultiplier">1.1</item> - </style> - </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 4b0a2b7..870202a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -37,7 +37,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Canvas; @@ -97,7 +96,6 @@ import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NotificationRowLayout; import com.android.systemui.statusbar.policy.OnSizeChangedListener; -import com.android.systemui.statusbar.policy.Prefs; import com.android.systemui.statusbar.policy.RotationLockController; import java.io.FileDescriptor; @@ -111,11 +109,8 @@ public class PhoneStatusBar extends BaseStatusBar { public static final boolean DUMPTRUCK = true; // extra dumpsys info public static final boolean DEBUG_GESTURES = false; - public static final boolean DEBUG_CLINGS = false; public static final boolean DEBUG_WINDOW_STATE = true; - public static final boolean ENABLE_NOTIFICATION_PANEL_CLING = false; - public static final boolean SETTINGS_DRAG_SHORTCUT = true; // additional instrumentation for testing purposes; intended to be left on during development @@ -251,11 +246,6 @@ public class PhoneStatusBar extends BaseStatusBar { boolean mTracking; VelocityTracker mVelocityTracker; - // help screen - private boolean mClingShown; - private ViewGroup mCling; - private boolean mSuppressStatusBarDrags; // while a cling is up, briefly deaden the bar to give things time to settle - int[] mAbsPos = new int[2]; Runnable mPostCollapseCleanup = null; @@ -615,13 +605,6 @@ public class PhoneStatusBar extends BaseStatusBar { } } - mClingShown = ! (DEBUG_CLINGS - || !Prefs.read(mContext).getBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, false)); - - if (!ENABLE_NOTIFICATION_PANEL_CLING || ActivityManager.isRunningInTestHarness()) { - mClingShown = true; - } - // final ImageView wimaxRSSI = // (ImageView)sb.findViewById(R.id.wimax_signal); // if (wimaxRSSI != null) { @@ -1733,63 +1716,6 @@ public class PhoneStatusBar extends BaseStatusBar { } } - public boolean isClinging() { - return mCling != null && mCling.getVisibility() == View.VISIBLE; - } - - public void hideCling() { - if (isClinging()) { - mCling.animate().alpha(0f).setDuration(250).start(); - mCling.setVisibility(View.GONE); - mSuppressStatusBarDrags = false; - } - } - - public void showCling() { - // lazily inflate this to accommodate orientation change - final ViewStub stub = (ViewStub) mStatusBarWindow.findViewById(R.id.status_bar_cling_stub); - if (stub == null) { - mClingShown = true; - return; // no clings on this device - } - - mSuppressStatusBarDrags = true; - - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - mCling = (ViewGroup) stub.inflate(); - - mCling.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; // e eats everything - }}); - mCling.findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - hideCling(); - }}); - - mCling.setAlpha(0f); - mCling.setVisibility(View.VISIBLE); - mCling.animate().alpha(1f); - - mClingShown = true; - SharedPreferences.Editor editor = Prefs.edit(mContext); - editor.putBoolean(Prefs.SHOWN_QUICK_SETTINGS_HELP, true); - editor.apply(); - - makeExpandedVisible(); // enforce visibility in case the shade is still animating closed - animateExpandNotificationsPanel(); - - mSuppressStatusBarDrags = false; - } - }, 500); - - animateExpandNotificationsPanel(); - } - public boolean interceptTouchEvent(MotionEvent event) { if (DEBUG_GESTURES) { if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { @@ -1815,21 +1741,6 @@ public class PhoneStatusBar extends BaseStatusBar { mGestureRec.add(event); } - // Cling (first-run help) handling. - // The cling is supposed to show the first time you drag, or even tap, the status bar. - // It should show the notification panel, then fade in after half a second, giving you - // an explanation of what just happened, as well as teach you how to access quick - // settings (another drag). The user can dismiss the cling by clicking OK or by - // dragging quick settings into view. - final int act = event.getActionMasked(); - if (mSuppressStatusBarDrags) { - return true; - } else if (act == MotionEvent.ACTION_UP && !mClingShown) { - showCling(); - } else { - hideCling(); - } - setInteracting(true); return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java index 73979a6..f339401 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java @@ -22,8 +22,6 @@ import android.content.SharedPreferences; public class Prefs { private static final String SHARED_PREFS_NAME = "status_bar"; - public static final String SHOWN_QUICK_SETTINGS_HELP = "shown_quick_settings_help"; - public static SharedPreferences read(Context context) { return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 136a85e..9c14654 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -36,6 +36,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothTetheringDataTracker; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -152,6 +153,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** @@ -424,9 +426,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; - // We only want one checkMobileProvisioning after booting. - volatile boolean mFirstProvisioningCheckStarted = false; - public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -656,9 +655,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); mSettingsObserver.observe(mContext); - mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); - loadGlobalProxy(); - mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); @@ -686,6 +682,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { new IntentFilter(filter)); mPacManager = new PacManager(mContext); + + filter = new IntentFilter(); + filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + mContext.registerReceiver(mProvisioningReceiver, filter); } /** @@ -954,6 +954,46 @@ public class ConnectivityService extends IConnectivityManager.Stub { return getNetworkInfo(mActiveDefaultNetwork, uid); } + /** + * Find the first Provisioning network. + * + * @return NetworkInfo or null if none. + */ + private NetworkInfo getProvisioningNetworkInfo() { + enforceAccessPermission(); + + // Find the first Provisioning Network + NetworkInfo provNi = null; + for (NetworkInfo ni : getAllNetworkInfo()) { + if (ni.getDetailedState() + == NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + provNi = ni; + break; + } + } + if (DBG) log("getProvisioningNetworkInfo: X provNi=" + provNi); + return provNi; + } + + /** + * Find the first Provisioning network or the ActiveDefaultNetwork + * if there is no Provisioning network + * + * @return NetworkInfo or null if none. + */ + @Override + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + enforceAccessPermission(); + + NetworkInfo provNi = getProvisioningNetworkInfo(); + if (provNi == null) { + final int uid = Binder.getCallingUid(); + provNi = getNetworkInfo(mActiveDefaultNetwork, uid); + } + if (DBG) log("getProvisioningOrActiveNetworkInfo: X provNi=" + provNi); + return provNi; + } + public NetworkInfo getActiveNetworkInfoUnfiltered() { enforceAccessPermission(); if (isNetworkTypeValid(mActiveDefaultNetwork)) { @@ -1316,8 +1356,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { feature); } if (network.reconnect()) { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED"); return PhoneConstants.APN_REQUEST_STARTED; } else { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED"); return PhoneConstants.APN_REQUEST_FAILED; } } else { @@ -1329,9 +1371,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[usedNetworkType].add(currentPid); } } + if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature."); return -1; } } + if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE"); return PhoneConstants.APN_TYPE_NOT_AVAILABLE; } finally { if (DBG) { @@ -1365,11 +1409,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } if (found && u != null) { + if (VDBG) log("stopUsingNetworkFeature: X"); // stop regardless of how many other time this proc had called start return stopUsingNetworkFeature(u, true); } else { // none found! - if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring"); + if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring"); return 1; } } @@ -1952,6 +1997,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ if (mNetConfigs[prevNetType].isDefault()) { if (mActiveDefaultNetwork == prevNetType) { + if (DBG) { + log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType); + } mActiveDefaultNetwork = -1; } @@ -2146,6 +2194,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void systemReady() { + mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); + loadGlobalProxy(); + synchronized(this) { mSystemReady = true; if (mInitialBroadcast != null) { @@ -2176,10 +2227,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; private boolean isNewNetTypePreferredOverCurrentNetType(int type) { - if ((type != mNetworkPreference && - mNetConfigs[mActiveDefaultNetwork].priority > - mNetConfigs[type].priority) || - mNetworkPreference == mActiveDefaultNetwork) return false; + if (((type != mNetworkPreference) + && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority)) + || (mNetworkPreference == mActiveDefaultNetwork)) { + return false; + } return true; } @@ -2193,6 +2245,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { final NetworkStateTracker thisNet = mNetTrackers[newNetType]; final String thisIface = thisNet.getLinkProperties().getInterfaceName(); + if (VDBG) { + log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface + + " isFailover" + isFailover); + } + // if this is a default net and other default is running // kill the one not preferred if (mNetConfigs[newNetType].isDefault()) { @@ -2355,6 +2412,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleConnectivityChange(int netType, boolean doReset) { int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType); + if (VDBG) { + log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset + + " resetMask=" + resetMask); + } /* * If a non-default network is enabled, add the host routes that @@ -2422,7 +2483,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt); if (resetMask != 0 || resetDns) { + if (VDBG) log("handleConnectivityChange: resetting"); if (curLp != null) { + if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp); for (String iface : curLp.getAllInterfaceNames()) { if (TextUtils.isEmpty(iface) == false) { if (resetMask != 0) { @@ -2459,6 +2522,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Update 464xlat state. NetworkStateTracker tracker = mNetTrackers[netType]; if (mClat.requiresClat(netType, tracker)) { + // If the connection was previously using clat, but is not using it now, stop the clat // daemon. Normally, this happens automatically when the connection disconnects, but if // the disconnect is not reported, or if the connection's LinkProperties changed for @@ -2512,6 +2576,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { + if (VDBG) log("updateRoutes: default remove route r=" + r); removeRoute(curLp, r, TO_DEFAULT_TABLE); } if (isLinkDefault == false) { @@ -2849,9 +2914,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { - case NetworkStateTracker.EVENT_STATE_CHANGED: + case NetworkStateTracker.EVENT_STATE_CHANGED: { info = (NetworkInfo) msg.obj; - int type = info.getType(); NetworkInfo.State state = info.getState(); if (VDBG || (state == NetworkInfo.State.CONNECTED) || @@ -2861,15 +2925,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } - // After booting we'll check once for mobile provisioning - // if we've provisioned by and connected. - if (!mFirstProvisioningCheckStarted + // Since mobile has the notion of a network/apn that can be used for + // provisioning we need to check every time we're connected as + // CaptiveProtalTracker won't detected it because DCT doesn't report it + // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its + // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which + // is received by MDST and sent here as EVENT_STATE_CHANGED. + if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) && (state == NetworkInfo.State.CONNECTED)) { - log("check provisioning after booting"); - mFirstProvisioningCheckStarted = true; - checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); + checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } EventLogTags.writeConnectivityStateChanged( @@ -2881,6 +2947,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (info.getDetailedState() == DetailedState.CAPTIVE_PORTAL_CHECK) { handleCaptivePortalTrackerCheck(info); + } else if (info.getDetailedState() == + DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + /** + * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING + * for now its an in between network, its a network that + * is actually a default network but we don't want it to be + * announced as such to keep background applications from + * trying to use it. It turns out that some still try so we + * take the additional step of clearing any default routes + * to the link that may have incorrectly setup by the lower + * levels. + */ + LinkProperties lp = getLinkProperties(info.getType()); + if (DBG) { + log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp); + } + + // Clear any default routes setup by the radio so + // any activity by applications trying to use this + // connection will fail until the provisioning network + // is enabled. + for (RouteInfo r : lp.getRoutes()) { + removeRoute(lp, r, TO_DEFAULT_TABLE); + } } else if (state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) { @@ -2899,18 +2989,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { mLockdownTracker.onNetworkInfoChanged(info); } break; - case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: + } + case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: { info = (NetworkInfo) msg.obj; // TODO: Temporary allowing network configuration // change not resetting sockets. // @see bug/4455071 handleConnectivityChange(info.getType(), false); break; - case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + } + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { info = (NetworkInfo) msg.obj; - type = info.getType(); + int type = info.getType(); updateNetworkSettings(mNetTrackers[type]); break; + } } } } @@ -3806,76 +3899,153 @@ public class ConnectivityService extends IConnectivityManager.Stub { enabled)); } - @Override - public int checkMobileProvisioning(final boolean sendNotification, int suggestedTimeOutMs, - final ResultReceiver resultReceiver) { - log("checkMobileProvisioning: E sendNotification=" + sendNotification - + " suggestedTimeOutMs=" + suggestedTimeOutMs - + " resultReceiver=" + resultReceiver); - enforceChangePermission(); + private boolean isMobileDataStateTrackerReady() { + MobileDataStateTracker mdst = + (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + return (mdst != null) && (mdst.isReady()); + } - mFirstProvisioningCheckStarted = true; + /** + * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) + */ - int timeOutMs = suggestedTimeOutMs; - if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { - timeOutMs = CheckMp.MAX_TIMEOUT_MS; - } + /** + * No connection was possible to the network. + */ + public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; - // Check that mobile networks are supported - if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) - || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { - log("checkMobileProvisioning: X no mobile network"); - if (resultReceiver != null) { - resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); - } - return timeOutMs; - } + /** + * A connection was made to the internet, all is well. + */ + 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. + */ + 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. + */ + 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. + */ + public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; + + /** + * The mobile network is a provisioning network. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + + AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); + + @Override + public int checkMobileProvisioning(int suggestedTimeOutMs) { + int timeOutMs = -1; + if (DBG) log("checkMobileProvisioning: E suggestedTimeOutMs=" + suggestedTimeOutMs); + enforceConnectivityInternalPermission(); final long token = Binder.clearCallingIdentity(); try { + timeOutMs = suggestedTimeOutMs; + if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { + timeOutMs = CheckMp.MAX_TIMEOUT_MS; + } + + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + if (DBG) log("checkMobileProvisioning: X no mobile network"); + return timeOutMs; + } + + // If we're already checking don't do it again + // TODO: Add a queue of results... + if (mIsCheckingMobileProvisioning.getAndSet(true)) { + if (DBG) log("checkMobileProvisioning: X already checking ignore for the moment"); + return timeOutMs; + } + + // Start off with notification off + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // See if we've alreadying determined if we've got a provsioning connection + // if so we don't need to do anything active + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + + if (isDefaultProvisioning || isHipriProvisioning) { + if (mIsNotificationVisible) { + if (DBG) { + log("checkMobileProvisioning: provisioning-ignore notification is visible"); + } + } else { + NetworkInfo ni = null; + if (isDefaultProvisioning) { + ni = mdstDefault.getNetworkInfo(); + } + if (isHipriProvisioning) { + ni = mdstHipri.getNetworkInfo(); + } + String url = getMobileProvisioningUrl(); + if ((ni != null) && (!TextUtils.isEmpty(url))) { + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); + } else { + if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); + } + } + mIsCheckingMobileProvisioning.set(false); + return timeOutMs; + } + CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override void onComplete(Integer result) { - log("CheckMp.onComplete: result=" + result); - if (resultReceiver != null) { - log("CheckMp.onComplete: send result"); - resultReceiver.send(result, null); - } - if (!sendNotification) { - log("CheckMp.onComplete: done, not sending notification"); - return; - } + if (DBG) log("CheckMp.onComplete: result=" + result); NetworkInfo ni = mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { - case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE: - case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: { - log("CheckMp.onComplete: ignore, connected or no connection"); + case CMP_RESULT_CODE_CONNECTABLE: + case CMP_RESULT_CODE_NO_CONNECTION: { + if (DBG) log("CheckMp.onComplete: ignore, connected or no connection"); break; } - case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { - log("CheckMp.onComplete: warm sim"); + case CMP_RESULT_CODE_REDIRECTED: { + if (DBG) log("CheckMp.onComplete: warm sim"); String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url)) { url = getMobileRedirectedProvisioningUrl(); } if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (redirected), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (redirected), no url"); + if (DBG) log("CheckMp.onComplete: warm (redirected), no url"); } break; } - case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: - case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { + case CMP_RESULT_CODE_NO_DNS: + case CMP_RESULT_CODE_NO_TCP_CONNECTION: { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (no dns/tcp), no url"); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); } break; } @@ -3884,16 +4054,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } } + mIsCheckingMobileProvisioning.set(false); } }; CheckMp.Params params = new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); - log("checkMobileProvisioning: params=" + params); - setNotificationVisible(false, null, null); + if (DBG) log("checkMobileProvisioning: params=" + params); checkMp.execute(params); } finally { Binder.restoreCallingIdentity(token); - log("checkMobileProvisioning: X"); + if (DBG) log("checkMobileProvisioning: X"); } return timeOutMs; } @@ -3965,26 +4135,38 @@ public class ConnectivityService extends IConnectivityManager.Stub { * a known address that fetches the data we expect. */ private synchronized Integer isMobileOk(Params params) { - Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + Integer result = CMP_RESULT_CODE_NO_CONNECTION; Uri orgUri = Uri.parse(params.mUrl); Random rand = new Random(); mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; return result; } try { - // Enable fail fast as we'll do retries here and use a - // hipri connection so the default connection stays active. - log("isMobileOk: start hipri url=" + params.mUrl); - mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + if (!mCs.isMobileDataStateTrackerReady()) { + // Wait for MobileDataStateTracker to be ready. + if (DBG) log("isMobileOk: mdst is not ready"); + while(SystemClock.elapsedRealtime() < endTime) { + if (mCs.isMobileDataStateTrackerReady()) { + // Enable fail fast as we'll do retries here and use a + // hipri connection so the default connection stays active. + if (DBG) log("isMobileOk: mdst ready, enable fail fast of mobile data"); + mCs.setEnableFailFastMobileData(DctConstants.ENABLED); + break; + } + sleep(1); + } + } + + log("isMobileOk: start hipri url=" + params.mUrl); + // First wait until we can start using hipri Binder binder = new Binder(); while(SystemClock.elapsedRealtime() < endTime) { @@ -3996,7 +4178,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } if (VDBG) log("isMobileOk: hipri not started yet"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; sleep(1); } @@ -4009,15 +4191,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - if (VDBG) { + if (true/*VDBG*/) { log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } sleep(1); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; continue; } + // Hipri has started check if this is a provisioning url + MobileDataStateTracker mdst = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + if (mdst.isProvisioningNetwork()) { + if (DBG) log("isMobileOk: isProvisioningNetwork is true, no TCP conn"); + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; + return result; + } else { + if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); + } + // Get of the addresses associated with the url host. We need to use the // address otherwise HttpURLConnection object will use the name to get // the addresses and is will try every address but that will bypass the @@ -4028,7 +4221,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { log("isMobileOk: UnknownHostException"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS; + result = CMP_RESULT_CODE_NO_DNS; return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -4093,9 +4286,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); if (responseCode == 204) { - result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE; + result = CMP_RESULT_CODE_CONNECTABLE; } else { - result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED; + result = CMP_RESULT_CODE_REDIRECTED; } log("isMobileOk: connected responseCode=" + responseCode); urlConn.disconnect(); @@ -4109,7 +4302,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION; + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; log("isMobileOk: loops|timed out"); return result; } catch (Exception e) { @@ -4123,6 +4316,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCs.setEnableFailFastMobileData(DctConstants.DISABLED); mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_HIPRI); + + // Wait for hipri to disconnect. + long endTime = SystemClock.elapsedRealtime() + 5000; + + while(SystemClock.elapsedRealtime() < endTime) { + NetworkInfo.State state = mCs + .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); + if (state != NetworkInfo.State.DISCONNECTED) { + if (VDBG) { + log("isMobileOk: connected ni=" + + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } + sleep(1); + continue; + } + } + log("isMobileOk: X result=" + result); } return result; @@ -4188,10 +4398,55 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + // TODO: Move to ConnectivityManager and make public? + private static final String CONNECTED_TO_PROVISIONING_NETWORK_ACTION = + "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION"; + + private BroadcastReceiver mProvisioningReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CONNECTED_TO_PROVISIONING_NETWORK_ACTION)) { + handleMobileProvisioningAction(intent.getStringExtra("EXTRA_URL")); + } + } + }; + + private void handleMobileProvisioningAction(String url) { + // Notication mark notification as not visible + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // If provisioning network handle as a special case, + // otherwise launch browser with the intent directly. + NetworkInfo ni = getProvisioningNetworkInfo(); + if ((ni != null) && ni.getDetailedState() == + NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if (DBG) log("handleMobileProvisioningAction: on provisioning network"); + MobileDataStateTracker mdst = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.enableMobileProvisioning(url); + } else { + if (DBG) log("handleMobileProvisioningAction: on default network"); + Intent newIntent = + new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(newIntent); + } catch (ActivityNotFoundException e) { + loge("handleMobileProvisioningAction: startActivity failed" + e); + } + } + } + private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + private volatile boolean mIsNotificationVisible = false; - private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) { - log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url); + private void setProvNotificationVisible(boolean visible, int networkType, String extraInfo, + String url) { + if (DBG) { + log("setProvNotificationVisible: E visible=" + visible + " networkType=" + networkType + + " extraInfo=" + extraInfo + " url=" + url); + } Resources r = Resources.getSystem(); NotificationManager notificationManager = (NotificationManager) mContext @@ -4201,50 +4456,64 @@ public class ConnectivityService extends IConnectivityManager.Stub { CharSequence title; CharSequence details; int icon; - switch (networkInfo.getType()) { + Intent intent; + Notification notification = new Notification(); + switch (networkType) { case ConnectivityManager.TYPE_WIFI: - log("setNotificationVisible: TYPE_WIFI"); title = r.getString(R.string.wifi_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_wifi_in_range; + 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); break; case ConnectivityManager.TYPE_MOBILE: case ConnectivityManager.TYPE_MOBILE_HIPRI: - log("setNotificationVisible: TYPE_MOBILE|HIPRI"); 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; + intent = new Intent(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + intent.putExtra("EXTRA_URL", url); + intent.setFlags(0); + notification.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); break; default: - log("setNotificationVisible: other type=" + networkInfo.getType()); title = r.getString(R.string.network_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_rssi_in_range; + 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); 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); - log("setNotificaitionVisible: notify notificaiton=" + notification); - notificationManager.notify(NOTIFICATION_ID, 1, notification); + try { + notificationManager.notify(NOTIFICATION_ID, 1, notification); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: visible notificationManager npe=" + npe); + npe.printStackTrace(); + } } else { - log("setNotificaitionVisible: cancel"); - notificationManager.cancel(NOTIFICATION_ID, 1); + try { + notificationManager.cancel(NOTIFICATION_ID, 1); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: cancel notificationManager npe=" + npe); + npe.printStackTrace(); + } } - log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); + mIsNotificationVisible = visible; } /** Location to an updatable file listing carrier provisioning urls. @@ -4373,6 +4642,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + @Override + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + enforceConnectivityInternalPermission(); + setProvNotificationVisible(visible, networkType, extraInfo, url); + } + private void onUserStart(int userId) { synchronized(mVpns) { Vpn userVpn = mVpns.get(userId); diff --git a/services/java/com/android/server/PreferredComponent.java b/services/java/com/android/server/PreferredComponent.java index bb22545..134b198 100644 --- a/services/java/com/android/server/PreferredComponent.java +++ b/services/java/com/android/server/PreferredComponent.java @@ -33,8 +33,16 @@ import java.io.PrintWriter; import java.util.List; public class PreferredComponent { + private static final String TAG_SET = "set"; + private static final String ATTR_ALWAYS = "always"; // boolean + private static final String ATTR_MATCH = "match"; // number + private static final String ATTR_NAME = "name"; // component name + private static final String ATTR_SET = "set"; // number + public final int mMatch; public final ComponentName mComponent; + // Whether this is to be the one that's always chosen. If false, it's the most recently chosen. + public boolean mAlways; private final String[] mSetPackages; private final String[] mSetClasses; @@ -50,10 +58,11 @@ public class PreferredComponent { } public PreferredComponent(Callbacks callbacks, int match, ComponentName[] set, - ComponentName component) { + ComponentName component, boolean always) { mCallbacks = callbacks; mMatch = match&IntentFilter.MATCH_CATEGORY_MASK; mComponent = component; + mAlways = always; mShortComponent = component.flattenToShortString(); mParseError = null; if (set != null) { @@ -86,15 +95,17 @@ public class PreferredComponent { public PreferredComponent(Callbacks callbacks, XmlPullParser parser) throws XmlPullParserException, IOException { mCallbacks = callbacks; - mShortComponent = parser.getAttributeValue(null, "name"); + mShortComponent = parser.getAttributeValue(null, ATTR_NAME); mComponent = ComponentName.unflattenFromString(mShortComponent); if (mComponent == null) { mParseError = "Bad activity name " + mShortComponent; } - String matchStr = parser.getAttributeValue(null, "match"); + String matchStr = parser.getAttributeValue(null, ATTR_MATCH); mMatch = matchStr != null ? Integer.parseInt(matchStr, 16) : 0; - String setCountStr = parser.getAttributeValue(null, "set"); + String setCountStr = parser.getAttributeValue(null, ATTR_SET); int setCount = setCountStr != null ? Integer.parseInt(setCountStr) : 0; + String alwaysStr = parser.getAttributeValue(null, ATTR_ALWAYS); + mAlways = alwaysStr != null ? Boolean.parseBoolean(alwaysStr) : true; String[] myPackages = setCount > 0 ? new String[setCount] : null; String[] myClasses = setCount > 0 ? new String[setCount] : null; @@ -115,8 +126,8 @@ public class PreferredComponent { String tagName = parser.getName(); //Log.i(TAG, "Parse outerDepth=" + outerDepth + " depth=" // + parser.getDepth() + " tag=" + tagName); - if (tagName.equals("set")) { - String name = parser.getAttributeValue(null, "name"); + if (tagName.equals(TAG_SET)) { + String name = parser.getAttributeValue(null, ATTR_NAME); if (name == null) { if (mParseError == null) { mParseError = "No name in set tag in preferred activity " @@ -166,16 +177,17 @@ public class PreferredComponent { public void writeToXml(XmlSerializer serializer, boolean full) throws IOException { final int NS = mSetClasses != null ? mSetClasses.length : 0; - serializer.attribute(null, "name", mShortComponent); + serializer.attribute(null, ATTR_NAME, mShortComponent); if (full) { if (mMatch != 0) { - serializer.attribute(null, "match", Integer.toHexString(mMatch)); + serializer.attribute(null, ATTR_MATCH, Integer.toHexString(mMatch)); } - serializer.attribute(null, "set", Integer.toString(NS)); + serializer.attribute(null, ATTR_ALWAYS, Boolean.toString(mAlways)); + serializer.attribute(null, ATTR_SET, Integer.toString(NS)); for (int s=0; s<NS; s++) { - serializer.startTag(null, "set"); - serializer.attribute(null, "name", mSetComponents[s]); - serializer.endTag(null, "set"); + serializer.startTag(null, TAG_SET); + serializer.attribute(null, ATTR_NAME, mSetComponents[s]); + serializer.endTag(null, TAG_SET); } } } diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java index 250ab4a..3e0b5eb 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -1426,8 +1426,7 @@ public final class ActivityStackSupervisor { if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) { - // Caller wants to appear on home activity, so before starting - // their own activity we will bring home to the front. + // Caller wants to appear on home activity. r.mLaunchHomeTaskNext = true; } targetStack.moveTaskToFrontLocked(intentActivity.task, r, options); @@ -1541,6 +1540,8 @@ public final class ActivityStackSupervisor { // don't use that intent!) And for paranoia, make // sure we have correctly resumed the top activity. if (doResume) { + // Reset flag so it gets correctly reevaluated. + intentActivity.mLaunchHomeTaskNext = false; setLaunchHomeTaskNextFlag(sourceRecord, intentActivity, targetStack); targetStack.resumeTopActivityLocked(null, options); } else { diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java index e3693f8..1b9ed98 100644 --- a/services/java/com/android/server/content/SyncStorageEngine.java +++ b/services/java/com/android/server/content/SyncStorageEngine.java @@ -71,7 +71,7 @@ import java.util.TimeZone; public class SyncStorageEngine extends Handler { private static final String TAG = "SyncManager"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private static final String TAG_FILE = "SyncManagerFile"; private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId"; diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 4942141..686b64e 100755 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -122,6 +122,7 @@ import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; import android.util.LogPrinter; +import android.util.PrintStreamPrinter; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; @@ -2595,6 +2596,37 @@ public class PackageManagerService extends IPackageManager.Stub { return chooseBestActivity(intent, resolvedType, flags, query, userId); } + @Override + public void setLastChosenActivity(Intent intent, String resolvedType, int flags, + IntentFilter filter, int match, ComponentName activity) { + final int userId = UserHandle.getCallingUserId(); + if (DEBUG_PREFERRED) { + Log.v(TAG, "setLastChosenActivity intent=" + intent + + " resolvedType=" + resolvedType + + " flags=" + flags + + " filter=" + filter + + " match=" + match + + " activity=" + activity); + filter.dump(new PrintStreamPrinter(System.out), " "); + } + intent.setComponent(null); + List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId); + // Find any earlier preferred or last chosen entries and nuke them + findPreferredActivity(intent, resolvedType, + flags, query, 0, false, true, userId); + // Add the new activity as the last chosen for this filter + addPreferredActivityInternal(filter, match, null, activity, false, userId); + } + + @Override + public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) { + final int userId = UserHandle.getCallingUserId(); + if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent); + List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId); + return findPreferredActivity(intent, resolvedType, flags, query, 0, + false, false, userId); + } + private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int userId) { if (query != null) { @@ -2620,7 +2652,7 @@ public class PackageManagerService extends IPackageManager.Stub { // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivity(intent, resolvedType, - flags, query, r0.priority, userId); + flags, query, r0.priority, true, false, userId); if (ri != null) { return ri; } @@ -2639,16 +2671,18 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } - ResolveInfo findPreferredActivity(Intent intent, String resolvedType, - int flags, List<ResolveInfo> query, int priority, int userId) { + ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, + List<ResolveInfo> query, int priority, boolean always, + boolean removeMatches, int userId) { if (!sUserManager.exists(userId)) return null; // writer synchronized (mPackages) { if (intent.getSelector() != null) { - intent = intent.getSelector(); + intent = intent.getSelector(); } if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); + // Get the list of preferred activities that handle the intent List<PreferredActivity> prefs = pir != null ? pir.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId) @@ -2683,7 +2717,25 @@ public class PackageManagerService extends IPackageManager.Stub { final int M = prefs.size(); for (int i=0; i<M; i++) { final PreferredActivity pa = prefs.get(i); + if (DEBUG_PREFERRED) { + Log.v(TAG, "Checking PreferredActivity ds=" + + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>") + + "\n component=" + pa.mPref.mComponent); + pa.dump(new PrintStreamPrinter(System.out), " "); + } if (pa.mPref.mMatch != match) { + if (DEBUG_PREFERRED) { + Log.v(TAG, "Skipping bad match " + + Integer.toHexString(pa.mPref.mMatch)); + } + continue; + } + // If it's not an "always" type preferred activity and that's what we're + // looking for, skip it. + if (always && !pa.mPref.mAlways) { + if (DEBUG_PREFERRED) { + Log.v(TAG, "Skipping lastChosen entry"); + } continue; } final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, @@ -2717,22 +2769,41 @@ public class PackageManagerService extends IPackageManager.Stub { continue; } - // Okay we found a previously set preferred app. + if (removeMatches) { + pir.removeFilter(pa); + if (DEBUG_PREFERRED) { + Log.v(TAG, "Removing match " + pa.mPref.mComponent); + } + break; + } + + // Okay we found a previously set preferred or last chosen app. // If the result set is different from when this // was created, we need to clear it and re-ask the - // user their preference. - if (!pa.mPref.sameSet(query, priority)) { + // user their preference, if we're looking for an "always" type entry. + if (always && !pa.mPref.sameSet(query, priority)) { Slog.i(TAG, "Result set changed, dropping preferred activity for " + intent + " type " + resolvedType); + if (DEBUG_PREFERRED) { + Log.v(TAG, "Removing preferred activity since set changed " + + pa.mPref.mComponent); + } pir.removeFilter(pa); + // Re-add the filter as a "last chosen" entry (!always) + PreferredActivity lastChosen = new PreferredActivity( + pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false); + pir.addFilter(lastChosen); + mSettings.writePackageRestrictionsLPr(userId); return null; } - // Yay! + // Yay! Either the set matched or we're looking for the last chosen + mSettings.writePackageRestrictionsLPr(userId); return ri; } } } + mSettings.writePackageRestrictionsLPr(userId); } return null; } @@ -9606,9 +9677,14 @@ public class PackageManagerService extends IPackageManager.Stub { } return Build.VERSION_CODES.CUR_DEVELOPMENT; } - + public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity, int userId) { + addPreferredActivityInternal(filter, match, set, activity, true, userId); + } + + private void addPreferredActivityInternal(IntentFilter filter, int match, + ComponentName[] set, ComponentName activity, boolean always, int userId) { // writer int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true, "add preferred activity"); @@ -9629,7 +9705,7 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); mSettings.editPreferredActivitiesLPw(userId).addFilter( - new PreferredActivity(filter, match, set, activity)); + new PreferredActivity(filter, match, set, activity, always)); mSettings.writePackageRestrictionsLPr(userId); } } @@ -9691,7 +9767,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } } - addPreferredActivity(filter, match, set, activity, callingUserId); + addPreferredActivityInternal(filter, match, set, activity, true, callingUserId); } } @@ -9736,8 +9812,11 @@ public class PackageManagerService extends IPackageManager.Stub { Iterator<PreferredActivity> it = pir.filterIterator(); while (it.hasNext()) { PreferredActivity pa = it.next(); + // Mark entry for removal only if it matches the package name + // and the entry is of type "always". if (packageName == null || - pa.mPref.mComponent.getPackageName().equals(packageName)) { + (pa.mPref.mComponent.getPackageName().equals(packageName) + && pa.mPref.mAlways)) { if (removed == null) { removed = new ArrayList<PreferredActivity>(); } @@ -9781,7 +9860,8 @@ public class PackageManagerService extends IPackageManager.Stub { while (it.hasNext()) { final PreferredActivity pa = it.next(); if (packageName == null - || pa.mPref.mComponent.getPackageName().equals(packageName)) { + || (pa.mPref.mComponent.getPackageName().equals(packageName) + && pa.mPref.mAlways)) { if (outFilters != null) { outFilters.add(new IntentFilter(pa)); } diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java index c655bb1..963cbe4 100644 --- a/services/java/com/android/server/pm/PreferredActivity.java +++ b/services/java/com/android/server/pm/PreferredActivity.java @@ -33,13 +33,13 @@ class PreferredActivity extends IntentFilter implements PreferredComponent.Callb private static final String TAG = "PreferredActivity"; private static final boolean DEBUG_FILTERS = false; - static final String ATTR_USER_ID = "userId"; final PreferredComponent mPref; - PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) { + PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity, + boolean always) { super(filter); - mPref = new PreferredComponent(this, match, set, activity); + mPref = new PreferredComponent(this, match, set, activity, always); } PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException { diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/java/com/android/server/pm/PreferredIntentResolver.java index 7fe6a05..bce24d7 100644 --- a/services/java/com/android/server/pm/PreferredIntentResolver.java +++ b/services/java/com/android/server/pm/PreferredIntentResolver.java @@ -26,10 +26,12 @@ public class PreferredIntentResolver protected PreferredActivity[] newArray(int size) { return new PreferredActivity[size]; } + @Override protected boolean isPackageForFilter(String packageName, PreferredActivity filter) { return packageName.equals(filter.mPref.mComponent.getPackageName()); } + @Override protected void dumpFilter(PrintWriter out, String prefix, PreferredActivity filter) { diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index e18202b..ff1128d 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -2071,7 +2071,7 @@ final class Settings { if (path != null) { filter.addDataPath(path); } - PreferredActivity pa = new PreferredActivity(filter, match, set, cn); + PreferredActivity pa = new PreferredActivity(filter, match, set, cn, true); editPreferredActivitiesLPw(userId).addFilter(pa); } else if (!haveNonSys) { Slog.w(TAG, "No component found for default preferred activity " + cn); diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java index bb37917..af60f84 100644 --- a/services/java/com/android/server/pm/UserManagerService.java +++ b/services/java/com/android/server/pm/UserManagerService.java @@ -26,8 +26,6 @@ import android.app.IStopUserCallback; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.RestrictionEntry; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -42,7 +40,6 @@ import android.os.Handler; import android.os.IUserManager; import android.os.Process; import android.os.RemoteException; -import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.util.AtomicFile; @@ -50,7 +47,6 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; -import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; @@ -163,8 +159,6 @@ public class UserManagerService extends IUserManager.Stub { private boolean mGuestEnabled; private int mNextSerialNumber; private int mUserVersion = 0; - // Temporary cleanup variable, this and associated code should be removed later. - private boolean mUnblockAppsTemp; private static UserManagerService sInstance; @@ -241,8 +235,6 @@ public class UserManagerService extends IUserManager.Stub { final Context context = ActivityThread.systemMain().getSystemContext(); mUserPackageMonitor.register(context, null, UserHandle.ALL, false); - context.registerReceiver(mBootCompletedReceiver, - new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); userForeground(UserHandle.USER_OWNER); } @@ -502,12 +494,6 @@ public class UserManagerService extends IUserManager.Stub { return mUserIds; } - private void readUserList() { - synchronized (mPackagesLock) { - readUserListLocked(); - } - } - private void readUserListLocked() { mGuestEnabled = false; if (!mUserListFile.exists()) { @@ -601,20 +587,8 @@ public class UserManagerService extends IUserManager.Stub { userVersion = 2; } - if (userVersion < 3) { - // Remove restrictions PIN for all users - for (int i = 0; i < mRestrictionsPinStates.size(); i++) { - int userId = mRestrictionsPinStates.keyAt(i); - RestrictionsPinState state = mRestrictionsPinStates.valueAt(i); - if (state.salt != 0 && state.pinHash != null) { - removeRestrictionsForUser(userId, false); - } - } - userVersion = 3; - } if (userVersion < 4) { - mUnblockAppsTemp = true; userVersion = 4; } @@ -634,6 +608,7 @@ public class UserManagerService extends IUserManager.Stub { UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED); mUsers.put(0, primary); mNextSerialNumber = MIN_USER_ID; + mUserVersion = USER_VERSION; Bundle restrictions = new Bundle(); mUserRestrictions.append(UserHandle.USER_OWNER, restrictions); @@ -1588,19 +1563,4 @@ public class UserManagerService extends IUserManager.Stub { } } }; - - private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { - @Override public void onReceive(Context context, Intent intent) { - // This code block can be removed after cleanup - if (mUnblockAppsTemp) { - synchronized (mPackagesLock) { - // Unblock apps due to removal of restrictions feature - for (int i = 0; i < mUsers.size(); i++) { - int userId = mUsers.keyAt(i); - unblockAllAppsForUser(userId); - } - } - } - } - }; } diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java index 671a5dc..2563b58 100644 --- a/services/java/com/android/server/print/PrintManagerService.java +++ b/services/java/com/android/server/print/PrintManagerService.java @@ -254,7 +254,7 @@ public final class PrintManagerService extends IPrintManager.Stub { } @Override - public void requestPrinterUpdate(PrinterId printerId, int userId) { + public void validatePrinters(List<PrinterId> printerIds, int userId) { final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); final UserState userState; synchronized (mLock) { @@ -262,7 +262,37 @@ public final class PrintManagerService extends IPrintManager.Stub { } final long identity = Binder.clearCallingIdentity(); try { - userState.requestPrinterUpdate(printerId); + userState.validatePrinters(printerIds); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void startPrinterStateTracking(PrinterId printerId, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.startPrinterStateTracking(printerId); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void stopPrinterStateTracking(PrinterId printerId, int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + userState.stopPrinterStateTracking(printerId); } finally { Binder.restoreCallingIdentity(identity); } @@ -432,10 +462,12 @@ public final class PrintManagerService extends IPrintManager.Stub { if (appId == callingAppId) { return appId; } - if (mContext.checkCallingPermission(Manifest.permission.ACCESS_ALL_PRINT_JOBS) + if (mContext.checkCallingPermission( + "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS") != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Call from app " + callingAppId + " as app " - + appId + " without permission ACCESS_ALL_PRINT_JOBS"); + + appId + " without com.android.printspooler.permission" + + ".ACCESS_ALL_PRINT_JOBS"); } return appId; } diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java index 7f4b343..14af9d8 100644 --- a/services/java/com/android/server/print/RemotePrintService.java +++ b/services/java/com/android/server/print/RemotePrintService.java @@ -25,6 +25,7 @@ import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; +import android.os.AsyncTask; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; @@ -38,6 +39,8 @@ import android.printservice.IPrintService; import android.printservice.IPrintServiceClient; import android.util.Slog; +import com.android.internal.R; + import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -121,6 +124,36 @@ final class RemotePrintService implements DeathRecipient { mHasPrinterDiscoverySession = false; mPendingCommands.clear(); ensureUnbound(); + + // Makes sure all active print jobs are failed since the service + // just died. Do this off the main thread since we do to allow + // calls into the spooler on the main thread. + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + failAllActivePrintJobs(); + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); + } + + private void failAllActivePrintJobs() { + List<PrintJobInfo> printJobs = mSpooler.getPrintJobInfos(mComponentName, + PrintJobInfo.STATE_ANY_ACTIVE, PrintManager.APP_ID_ANY); + if (printJobs == null) { + return; + } + final long identity = Binder.clearCallingIdentity(); + try { + final int printJobCount = printJobs.size(); + for (int i = 0; i < printJobCount; i++) { + PrintJobInfo printJob = printJobs.get(i); + mSpooler.setPrintJobState(printJob.getId(), PrintJobInfo.STATE_FAILED, + mContext.getString(R.string.reason_unknown)); + } + } finally { + Binder.restoreCallingIdentity(identity); + } } private void handleOnAllPrintJobsHandled() { @@ -308,29 +341,83 @@ final class RemotePrintService implements DeathRecipient { } } - public void requestPrinterUpdate(PrinterId printerId) { - mHandler.obtainMessage(MyHandler.MSG_REQUEST_PRINTER_UPDATE, + public void validatePrinters(List<PrinterId> printerIds) { + mHandler.obtainMessage(MyHandler.MSG_VALIDATE_PRINTERS, + printerIds).sendToTarget(); + } + + private void handleValidatePrinters(final List<PrinterId> printerIds) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleValidatePrinters(printerIds); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleValidatePrinters()"); + } + try { + mPrintService.validatePrinters(printerIds); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting printers validation.", re); + } + } + } + + public void startPrinterStateTracking(PrinterId printerId) { + mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING, + printerId).sendToTarget(); + } + + private void handleStartPrinterStateTracking(final PrinterId printerId) { + throwIfDestroyed(); + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleStartPrinterStateTracking(printerId); + } + }); + } else { + if (DEBUG) { + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleStartPrinterTracking()"); + } + try { + mPrintService.startPrinterStateTracking(printerId); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Error requesting start printer tracking.", re); + } + } + } + + public void stopPrinterStateTracking(PrinterId printerId) { + mHandler.obtainMessage(MyHandler.MSG_STOP_PRINTER_STATE_TRACKING, printerId).sendToTarget(); } - private void handleRequestPrinterUpdate(final PrinterId printerId) { + private void handleStopPrinterStateTracking(final PrinterId printerId) { throwIfDestroyed(); if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @Override public void run() { - handleRequestPrinterUpdate(printerId); + handleStopPrinterStateTracking(printerId); } }); } else { if (DEBUG) { - Slog.i(LOG_TAG, "[user: " + mUserId + "] requestPrinterUpdate()"); + Slog.i(LOG_TAG, "[user: " + mUserId + "] handleStopPrinterTracking()"); } try { - mPrintService.requestPrinterUpdate(printerId); + mPrintService.stopPrinterStateTracking(printerId); } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error requesting a printer update.", re); + Slog.e(LOG_TAG, "Error requesting stop printer tracking.", re); } } } @@ -417,12 +504,14 @@ final class RemotePrintService implements DeathRecipient { 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_ALL_PRINT_JOBS_HANDLED = 6; - public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 7; - public static final int MSG_ON_PRINT_JOB_QUEUED = 8; - public static final int MSG_DESTROY = 9; - public static final int MSG_BINDER_DIED = 10; + 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_ALL_PRINT_JOBS_HANDLED = 8; + public static final int MSG_ON_REQUEST_CANCEL_PRINT_JOB = 9; + public static final int MSG_ON_PRINT_JOB_QUEUED = 10; + public static final int MSG_DESTROY = 11; + public static final int MSG_BINDER_DIED = 12; public MyHandler(Looper looper) { super(looper, null, false); @@ -449,9 +538,19 @@ final class RemotePrintService implements DeathRecipient { handleStopPrinterDiscovery(); } break; - case MSG_REQUEST_PRINTER_UPDATE: { + case MSG_VALIDATE_PRINTERS: { + List<PrinterId> printerIds = (List<PrinterId>) message.obj; + handleValidatePrinters(printerIds); + } break; + + case MSG_START_PRINTER_STATE_TRACKING: { + PrinterId printerId = (PrinterId) message.obj; + handleStartPrinterStateTracking(printerId); + } break; + + case MSG_STOP_PRINTER_STATE_TRACKING: { PrinterId printerId = (PrinterId) message.obj; - handleRequestPrinterUpdate(printerId); + handleStopPrinterStateTracking(printerId); } break; case MSG_ON_ALL_PRINT_JOBS_HANDLED: { diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index c979a11..4a1b96b 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -19,8 +19,12 @@ package com.android.server.print; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -46,6 +50,7 @@ import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -63,6 +68,11 @@ final class UserState implements PrintSpoolerCallbacks { private static final char COMPONENT_NAME_SEPARATOR = ':'; + private static final String SHARED_PREFERENCES_FILE = "shared_prefs"; + + private static final String KEY_SYSTEM_PRINT_SERVICES_ENABLED = + "KEY_SYSTEM_PRINT_SERVICES_ENABLED"; + private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); @@ -95,6 +105,7 @@ final class UserState implements PrintSpoolerCallbacks { mUserId = userId; mLock = lock; mSpooler = new RemotePrintSpooler(context, userId, this); + enableSystemPrintServicesOnce(); } @Override @@ -190,7 +201,7 @@ final class UserState implements PrintSpoolerCallbacks { } } - public void requestPrinterUpdate(PrinterId printerId) { + public void validatePrinters(List<PrinterId> printerIds) { synchronized (mLock) { throwIfDestroyedLocked(); // No services - nothing to do. @@ -202,7 +213,39 @@ final class UserState implements PrintSpoolerCallbacks { return; } // Request an updated. - mPrinterDiscoverySession.requestPrinterUpdateLocked(printerId); + mPrinterDiscoverySession.validatePrintersLocked(printerIds); + } + } + + public void startPrinterStateTracking(PrinterId printerId) { + synchronized (mLock) { + throwIfDestroyedLocked(); + // No services - nothing to do. + if (mActiveServices.isEmpty()) { + return; + } + // No session - nothing to do. + if (mPrinterDiscoverySession == null) { + return; + } + // Request start tracking the printer. + mPrinterDiscoverySession.startPrinterStateTrackingLocked(printerId); + } + } + + public void stopPrinterStateTracking(PrinterId printerId) { + synchronized (mLock) { + throwIfDestroyedLocked(); + // No services - nothing to do. + if (mActiveServices.isEmpty()) { + return; + } + // No session - nothing to do. + if (mPrinterDiscoverySession == null) { + return; + } + // Request stop tracking the printer. + mPrinterDiscoverySession.stopPrinterStateTrackingLocked(printerId); } } @@ -365,6 +408,36 @@ final class UserState implements PrintSpoolerCallbacks { return false; } + private void enableSystemPrintServicesOnce() { + SharedPreferences preferences = mContext.getSharedPreferences( + SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE); + if (preferences.getInt(KEY_SYSTEM_PRINT_SERVICES_ENABLED, 0) == 0) { + Editor editor = preferences.edit(); + editor.putInt(KEY_SYSTEM_PRINT_SERVICES_ENABLED, 1); + editor.commit(); + + readInstalledPrintServicesLocked(); + + StringBuilder builder = new StringBuilder(); + + final int serviceCount = mInstalledServices.size(); + for (int i = 0; i < serviceCount; i++) { + ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo; + if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + ComponentName serviceName = new ComponentName( + serviceInfo.packageName, serviceInfo.name); + if (builder.length() > 0) { + builder.append(":"); + } + builder.append(serviceName.flattenToString()); + } + } + + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.ENABLED_PRINT_SERVICES, builder.toString(), mUserId); + } + } + private void onConfigurationChangedLocked() { final int installedCount = mInstalledServices.size(); for (int i = 0; i < installedCount; i++) { @@ -415,6 +488,8 @@ final class UserState implements PrintSpoolerCallbacks { private final List<IBinder> mStartedPrinterDiscoveryTokens = new ArrayList<IBinder>(); + private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>(); + private final Handler mHandler; private boolean mIsDestroyed; @@ -461,14 +536,10 @@ final class UserState implements PrintSpoolerCallbacks { } // If printer discovery is ongoing and the start request has a list - // of printer to be checked, then we just request refreshing each of - // them rather making another start discovery request. + // of printer to be checked, then we just request validating them. if (!mStartedPrinterDiscoveryTokens.isEmpty() && priorityList != null && !priorityList.isEmpty()) { - final int priorityIdCount = priorityList.size(); - for (int i = 0; i < priorityIdCount; i++) { - requestPrinterUpdate(priorityList.get(i)); - } + validatePrinters(priorityList); return; } @@ -508,20 +579,97 @@ final class UserState implements PrintSpoolerCallbacks { .sendToTarget(); } - public void requestPrinterUpdateLocked(PrinterId printerId) { + public void validatePrintersLocked(List<PrinterId> printerIds) { if (mIsDestroyed) { - Log.w(LOG_TAG, "Not updating pritner - session destroyed"); + Log.w(LOG_TAG, "Not validating pritners - session destroyed"); return; } + + List<PrinterId> remainingList = new ArrayList<PrinterId>(printerIds); + while (!remainingList.isEmpty()) { + Iterator<PrinterId> iterator = remainingList.iterator(); + // Gather the printers per service and request a validation. + List<PrinterId> updateList = new ArrayList<PrinterId>(); + ComponentName serviceName = null; + while (iterator.hasNext()) { + PrinterId printerId = iterator.next(); + if (updateList.isEmpty()) { + updateList.add(printerId); + serviceName = printerId.getServiceName(); + iterator.remove(); + } else if (printerId.getServiceName().equals(serviceName)) { + updateList.add(printerId); + iterator.remove(); + } + } + // Schedule a notification of the service. + RemotePrintService service = mActiveServices.get(serviceName); + if (service != null) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = service; + args.arg2 = updateList; + mHandler.obtainMessage(SessionHandler + .MSG_VALIDATE_PRINTERS, args) + .sendToTarget(); + } + } + } + + public final void startPrinterStateTrackingLocked(PrinterId printerId) { + if (mIsDestroyed) { + Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed"); + return; + } + // If printer discovery is not started - nothing to do. + if (mStartedPrinterDiscoveryTokens.isEmpty()) { + return; + } + final boolean containedPrinterId = mStateTrackedPrinters.contains(printerId); + // Keep track of the number of requests to track this one. + mStateTrackedPrinters.add(printerId); + // If we were tracking this printer - nothing to do. + if (containedPrinterId) { + return; + } + // No service - nothing to do. RemotePrintService service = mActiveServices.get(printerId.getServiceName()); - if (service != null) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = service; - args.arg2 = printerId; - mHandler.obtainMessage(SessionHandler - .MSG_REQUEST_PRINTER_UPDATE, args) - .sendToTarget(); + if (service == null) { + return; } + // Ask the service to start tracking. + SomeArgs args = SomeArgs.obtain(); + args.arg1 = service; + args.arg2 = printerId; + mHandler.obtainMessage(SessionHandler + .MSG_START_PRINTER_STATE_TRACKING, args) + .sendToTarget(); + } + + public final void stopPrinterStateTrackingLocked(PrinterId printerId) { + if (mIsDestroyed) { + Log.w(LOG_TAG, "Not stopping printer state tracking - session destroyed"); + return; + } + // If printer discovery is not started - nothing to do. + if (mStartedPrinterDiscoveryTokens.isEmpty()) { + return; + } + // If we did not track this printer - nothing to do. + if (!mStateTrackedPrinters.remove(printerId)) { + return; + } + // No service - nothing to do. + RemotePrintService service = mActiveServices.get(printerId.getServiceName()); + if (service == null) { + return; + } + // Ask the service to start tracking. + SomeArgs args = SomeArgs.obtain(); + args.arg1 = service; + args.arg2 = printerId; + mHandler.obtainMessage(SessionHandler + .MSG_STOP_PRINTER_STATE_TRACKING, args) + .sendToTarget(); } public void onDestroyed() { @@ -533,6 +681,12 @@ final class UserState implements PrintSpoolerCallbacks { Log.w(LOG_TAG, "Not destroying - session destroyed"); return; } + // Make sure printer tracking is stopped. + final int printerCount = mStateTrackedPrinters.size(); + for (int i = 0; i < printerCount; i++) { + PrinterId printerId = mStateTrackedPrinters.get(i); + stopPrinterStateTracking(printerId); + } // Make sure discovery is stopped. final int observerCount = mStartedPrinterDiscoveryTokens.size(); for (int i = 0; i < observerCount; i++) { @@ -744,9 +898,19 @@ final class UserState implements PrintSpoolerCallbacks { } } - private void handleRequestPrinterUpdate(RemotePrintService service, + private void handleValidatePrinters(RemotePrintService service, + List<PrinterId> printerIds) { + service.validatePrinters(printerIds); + } + + private void handleStartPrinterStateTracking(RemotePrintService service, + PrinterId printerId) { + service.startPrinterStateTracking(printerId); + } + + private void handleStopPrinterStateTracking(RemotePrintService service, PrinterId printerId) { - service.requestPrinterUpdate(printerId); + service.stopPrinterStateTracking(printerId); } private void handlePrintersAdded(IPrinterDiscoveryObserver observer, @@ -804,7 +968,9 @@ final class UserState implements PrintSpoolerCallbacks { public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 9; public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 10; public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 11; - public static final int MSG_REQUEST_PRINTER_UPDATE = 12; + public static final int MSG_VALIDATE_PRINTERS = 12; + public static final int MSG_START_PRINTER_STATE_TRACKING = 13; + public static final int MSG_STOP_PRINTER_STATE_TRACKING = 14; SessionHandler(Looper looper) { super(looper, null, false); @@ -878,13 +1044,29 @@ final class UserState implements PrintSpoolerCallbacks { handleDispatchStopPrinterDiscovery(services); } break; - case MSG_REQUEST_PRINTER_UPDATE: { + case MSG_VALIDATE_PRINTERS: { + SomeArgs args = (SomeArgs) message.obj; + RemotePrintService service = (RemotePrintService) args.arg1; + List<PrinterId> printerIds = (List<PrinterId>) args.arg2; + args.recycle(); + handleValidatePrinters(service, printerIds); + } break; + + case MSG_START_PRINTER_STATE_TRACKING: { SomeArgs args = (SomeArgs) message.obj; RemotePrintService service = (RemotePrintService) args.arg1; PrinterId printerId = (PrinterId) args.arg2; args.recycle(); - handleRequestPrinterUpdate(service, printerId); + handleStartPrinterStateTracking(service, printerId); } break; + + case MSG_STOP_PRINTER_STATE_TRACKING: { + SomeArgs args = (SomeArgs) message.obj; + RemotePrintService service = (RemotePrintService) args.arg1; + PrinterId printerId = (PrinterId) args.arg2; + args.recycle(); + handleStopPrinterStateTracking(service, printerId); + } } } } diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index 4f1ae11..c661b00 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -94,6 +94,8 @@ public class DctConstants { public static final int EVENT_DISCONNECT_DC_RETRYING = BASE + 34; public static final int EVENT_DATA_SETUP_COMPLETE_ERROR = BASE + 35; public static final int CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA = BASE + 36; + public static final int CMD_ENABLE_MOBILE_PROVISIONING = BASE + 37; + public static final int CMD_IS_PROVISIONING_APN = BASE + 38; /***** Constants *****/ @@ -113,4 +115,5 @@ public class DctConstants { public static final int ENABLED = 1; public static final String APN_TYPE_KEY = "apnType"; + public static final String PROVISIONING_URL_KEY = "provisioningUrl"; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 65bdacf..a7baf1c 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -145,6 +145,29 @@ public class TelephonyIntents { public static final String ACTION_ANY_DATA_CONNECTION_STATE_CHANGED = "android.intent.action.ANY_DATA_STATE"; + /** + * Broadcast Action: Occurs when a data connection connects to a provisioning apn + * and is broadcast by the low level data connection code. + * The intent will have the following extra values:</p> + * <ul> + * <li><em>apn</em> - A string that is the APN associated with this + * connection.</li> + * <li><em>apnType</em> - A string array of APN types associated with + * this connection. The APN type <code>"*"</code> is a special + * type that means this APN services all types.</li> + * <li><em>linkProperties</em> - The <code>LinkProperties</code> for this APN</li> + * <li><em>linkCapabilities</em> - The <code>linkCapabilities</code> for this APN</li> + * <li><em>iface</em> - A string that is the name of the interface</li> + * </ul> + * + * <p class="note"> + * Requires the READ_PHONE_STATE permission. + * + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + public static final String ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN + = "android.intent.action.DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN"; /** * Broadcast Action: An attempt to establish a data connection has failed. |
