diff options
Diffstat (limited to 'core/java/android')
27 files changed, 608 insertions, 88 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 4e6c3dc..c65f17e 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -16,14 +16,13 @@ package android.app; -import android.R; import android.os.BatteryStats; import android.os.IBinder; import com.android.internal.app.IUsageStats; +import com.android.internal.app.ProcessStats; import com.android.internal.os.PkgUsageStats; import com.android.internal.os.TransferPipe; import com.android.internal.util.FastPrintWriter; -import com.android.internal.util.MemInfoReader; import android.content.ComponentName; import android.content.Context; @@ -35,9 +34,7 @@ import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Point; import android.graphics.Rect; -import android.hardware.display.DisplayManagerGlobal; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -52,7 +49,6 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; -import android.view.Display; import java.io.FileDescriptor; import java.io.FileOutputStream; @@ -2253,7 +2249,7 @@ public class ActivityManager { PrintWriter pw = new FastPrintWriter(fout); dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName }); pw.println(); - dumpService(pw, fd, "procstats", new String[] { packageName }); + dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName }); pw.println(); dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName }); pw.println(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 9faaace..eb5c3e7 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1979,7 +1979,7 @@ class ContextImpl extends Context { " compatiblity info:" + container.getDisplayMetrics()); } if (compatInfo == null) { - compatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; + compatInfo = packageInfo.getCompatibilityInfo(); } mDisplayAdjustments.setCompatibilityInfo(compatInfo); mDisplayAdjustments.setActivityToken(activityToken); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 17e8dd9..be831d7 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1527,9 +1527,26 @@ public class DevicePolicyManager { */ public boolean setDeviceOwner(String packageName) throws IllegalArgumentException, IllegalStateException { + return setDeviceOwner(packageName, null); + } + + /** + * @hide + * Sets the given package as the device owner. The package must already be installed and there + * shouldn't be an existing device owner registered, for this call to succeed. Also, this + * method must be called before the device is provisioned. + * @param packageName the package name of the application to be registered as the device owner. + * @param ownerName the human readable name of the institution that owns this device. + * @return whether the package was successfully registered as the device owner. + * @throws IllegalArgumentException if the package name is null or invalid + * @throws IllegalStateException if a device owner is already registered or the device has + * already been provisioned. + */ + public boolean setDeviceOwner(String packageName, String ownerName) + throws IllegalArgumentException, IllegalStateException { if (mService != null) { try { - return mService.setDeviceOwner(packageName); + return mService.setDeviceOwner(packageName, ownerName); } catch (RemoteException re) { Log.w(TAG, "Failed to set device owner"); } @@ -1581,4 +1598,16 @@ public class DevicePolicyManager { } return null; } + + /** @hide */ + public String getDeviceOwnerName() { + if (mService != null) { + try { + return mService.getDeviceOwnerName(); + } catch (RemoteException re) { + Log.w(TAG, "Failed to get device owner"); + } + } + return null; + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index b2a65bf..9659a91 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -98,7 +98,8 @@ interface IDevicePolicyManager { void reportFailedPasswordAttempt(int userHandle); void reportSuccessfulPasswordAttempt(int userHandle); - boolean setDeviceOwner(String packageName); + boolean setDeviceOwner(String packageName, String ownerName); boolean isDeviceOwner(String packageName); String getDeviceOwner(); + String getDeviceOwnerName(); } diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java index 81c0a6a..0aedecb 100644 --- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java +++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java @@ -152,6 +152,11 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker { // not implemented } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + /** * Re-enable connectivity to a network after a {@link #teardown()}. */ diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 6318e38..1c28138 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -786,10 +786,14 @@ public final class Configuration implements Parcelable, Comparable<Configuration // 2 most significant bits in screenLayout). setLayoutDirection(locale); } + if (delta.screenLayout != 0 && screenLayout != delta.screenLayout) { + changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; + setLayoutDirection(locale); + } if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0))) { - userSetLocale = true; changed |= ActivityInfo.CONFIG_LOCALE; + userSetLocale = true; } if (delta.touchscreen != TOUCHSCREEN_UNDEFINED && touchscreen != delta.touchscreen) { @@ -933,6 +937,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_LOCALE; changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; } + if (delta.screenLayout != 0 && screenLayout != delta.screenLayout) { + changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION; + } if (delta.touchscreen != TOUCHSCREEN_UNDEFINED && touchscreen != delta.touchscreen) { changed |= ActivityInfo.CONFIG_TOUCHSCREEN; @@ -1005,7 +1012,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static boolean needNewResources(int configChanges, int interestingChanges) { return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0; } - + /** * @hide Return true if the sequence of 'other' is better than this. Assumes * that 'this' is your current sequence and 'other' is a new one you have diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java index a9e39c3..b234e34 100644..100755 --- a/core/java/android/database/DefaultDatabaseErrorHandler.java +++ b/core/java/android/database/DefaultDatabaseErrorHandler.java @@ -99,7 +99,7 @@ public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler { } Log.e(TAG, "deleting the database file: " + fileName); try { - new File(fileName).delete(); + SQLiteDatabase.deleteDatabase(new File(fileName)); } catch (Exception e) { /* print warning and ignore exception */ Log.w(TAG, "delete failed: " + e.getMessage()); diff --git a/core/java/android/hardware/location/IFusedLocationHardware.aidl b/core/java/android/hardware/location/IFusedLocationHardware.aidl new file mode 100644 index 0000000..382c12c --- /dev/null +++ b/core/java/android/hardware/location/IFusedLocationHardware.aidl @@ -0,0 +1,117 @@ +/* + * Copyright (C) 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/license/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.location; + +import android.hardware.location.IFusedLocationHardwareSink; +import android.location.FusedBatchOptions; + +/** + * Fused Location hardware interface. + * This interface is the basic set of supported functionality by Fused Hardware + * modules that offer Location batching capabilities. + * + * @hide + */ +interface IFusedLocationHardware { + /** + * Registers a sink with the Location Hardware object. + * + * @param eventSink The sink to register. + */ + void registerSink(in IFusedLocationHardwareSink eventSink); + + /** + * Unregisters a sink with the Location Hardware object. + * + * @param eventSink The sink to unregister. + */ + void unregisterSink(in IFusedLocationHardwareSink eventSink); + + /** + * Provides access to the batch size available in Hardware. + * + * @return The batch size the hardware supports. + */ + int getSupportedBatchSize(); + + /** + * Requests the Hardware to start batching locations. + * + * @param id An Id associated with the request. + * @param batchOptions The options required for batching. + * + * @throws RuntimeException if the request Id exists. + */ + void startBatching(in int id, in FusedBatchOptions batchOptions); + + /** + * Requests the Hardware to stop batching for the given Id. + * + * @param id The request that needs to be stopped. + * @throws RuntimeException if the request Id is unknown. + */ + void stopBatching(in int id); + + /** + * Updates a batching operation in progress. + * + * @param id The Id of the operation to update. + * @param batchOptions The options to apply to the given operation. + * + * @throws RuntimeException if the Id of the request is unknown. + */ + void updateBatchingOptions(in int id, in FusedBatchOptions batchOptions); + + /** + * Requests the most recent locations available in Hardware. + * This operation does not dequeue the locations, so still other batching + * events will continue working. + * + * @param batchSizeRequested The number of locations requested. + */ + void requestBatchOfLocations(in int batchSizeRequested); + + /** + * Flags if the Hardware supports injection of diagnostic data. + * + * @return True if data injection is supported, false otherwise. + */ + boolean supportsDiagnosticDataInjection(); + + /** + * Injects diagnostic data into the Hardware subsystem. + * + * @param data The data to inject. + * @throws RuntimeException if injection is not supported. + */ + void injectDiagnosticData(in String data); + + /** + * Flags if the Hardware supports injection of device context information. + * + * @return True if device context injection is supported, false otherwise. + */ + boolean supportsDeviceContextInjection(); + + /** + * Injects device context information into the Hardware subsystem. + * + * @param deviceEnabledContext The context to inject. + * @throws RuntimeException if injection is not supported. + */ + void injectDeviceContext(in int deviceEnabledContext); +} diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl new file mode 100644 index 0000000..a11d8ab --- /dev/null +++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 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/license/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.location; + +import android.location.Location; + +/** + * Fused Location hardware event sink interface. + * This interface defines the set of events that the FusedLocationHardware provides. + * + * @hide + */ +interface IFusedLocationHardwareSink { + /** + * Event generated when a batch of location information is available. + * + * @param locations The batch of location information available. + */ + void onLocationAvailable(in Location[] locations); + + /** + * Event generated from FLP HAL to provide diagnostic data to the platform. + * + * @param data The diagnostic data provided by FLP HAL. + */ + void onDiagnosticDataAvailable(in String data); +}
\ No newline at end of file diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java index 1165281..e87f84c 100644 --- a/core/java/android/net/BaseNetworkStateTracker.java +++ b/core/java/android/net/BaseNetworkStateTracker.java @@ -102,6 +102,11 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker { } @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + + @Override public boolean setRadio(boolean turnOn) { // Base tracker doesn't handle radios return true; diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java index 19d74ed..74c2c59 100644 --- a/core/java/android/net/CaptivePortalTracker.java +++ b/core/java/android/net/CaptivePortalTracker.java @@ -46,6 +46,7 @@ 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; @@ -54,6 +55,7 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.Inet4Address; +import java.net.SocketTimeoutException; import java.net.URL; import java.net.UnknownHostException; import java.util.List; @@ -65,7 +67,7 @@ import com.android.internal.R; * @hide */ public class CaptivePortalTracker extends StateMachine { - private static final boolean DBG = false; + private static final boolean DBG = true; private static final String TAG = "CaptivePortalTracker"; private static final String DEFAULT_SERVER = "clients3.google.com"; @@ -301,6 +303,7 @@ public class CaptivePortalTracker extends StateMachine { } else { if (DBG) log("Not captive network " + mNetworkInfo); } + notifyPortalCheckCompleted(mNetworkInfo, captive); if (mDeviceProvisioned) { if (captive) { // Setup Wizard will assist the user in connecting to a captive @@ -331,12 +334,26 @@ public class CaptivePortalTracker extends StateMachine { return; } try { + if (DBG) log("notifyPortalCheckComplete: ni=" + info); mConnService.captivePortalCheckComplete(info); } catch(RemoteException e) { e.printStackTrace(); } } + private void notifyPortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + if (info == null) { + loge("notifyPortalCheckComplete on null"); + return; + } + try { + if (DBG) log("notifyPortalCheckCompleted: captive=" + isCaptivePortal + " ni=" + info); + mConnService.captivePortalCheckCompleted(info, isCaptivePortal); + } catch(RemoteException e) { + e.printStackTrace(); + } + } + private boolean isActiveNetwork(NetworkInfo info) { try { NetworkInfo active = mConnService.getActiveNetworkInfo(); @@ -382,6 +399,12 @@ public class CaptivePortalTracker extends StateMachine { sendNetworkConditionsBroadcast(true /* response received */, isCaptivePortal, requestTimestamp, responseTimestamp); 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) { @@ -415,6 +438,7 @@ public class CaptivePortalTracker extends StateMachine { 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; } @@ -426,12 +450,14 @@ public class CaptivePortalTracker extends StateMachine { 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); @@ -439,12 +465,24 @@ public class CaptivePortalTracker extends StateMachine { // 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; } @@ -452,15 +490,17 @@ public class CaptivePortalTracker extends StateMachine { notification.when = 0; notification.icon = icon; notification.flags = Notification.FLAG_AUTO_CANCEL; - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl)); + 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; diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1dbe34e..1b418fa 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1324,6 +1324,25 @@ public class ConnectivityManager { } /** + * Signal that the captive portal check on the indicated network + * is complete and whether its a captive portal or not. + * + * @param info the {@link NetworkInfo} object for the networkType + * in question. + * @param isCaptivePortal true/false. + * + * <p>This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * {@hide} + */ + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + try { + mService.captivePortalCheckCompleted(info, isCaptivePortal); + } catch (RemoteException e) { + } + } + + /** * Supply the backend messenger for a network tracker * * @param type NetworkType to set @@ -1401,7 +1420,7 @@ public class ConnectivityManager { } /** - * Get the carrier provisioning url. + * Get the mobile provisioning url. * {@hide} */ public String getMobileProvisioningUrl() { @@ -1411,4 +1430,16 @@ public class ConnectivityManager { } return null; } + + /** + * Get the mobile redirected provisioning url. + * {@hide} + */ + public String getMobileRedirectedProvisioningUrl() { + try { + return mService.getMobileRedirectedProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/DummyDataStateTracker.java b/core/java/android/net/DummyDataStateTracker.java index 15a81f3..ee738fd 100644 --- a/core/java/android/net/DummyDataStateTracker.java +++ b/core/java/android/net/DummyDataStateTracker.java @@ -120,10 +120,16 @@ public class DummyDataStateTracker implements NetworkStateTracker { return true; } + @Override public void captivePortalCheckComplete() { // not implemented } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + /** * Record the detailed state of a network, and if it is a * change from the previous state, send a notification to diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java index 7b803a8..7999c66 100644 --- a/core/java/android/net/EthernetDataTracker.java +++ b/core/java/android/net/EthernetDataTracker.java @@ -280,6 +280,11 @@ public class EthernetDataTracker implements NetworkStateTracker { // not implemented } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + // not implemented + } + /** * Turn the wireless radio off for a network. * @param turnOn {@code true} to turn the radio on, {@code false} diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b0f7fc6..992ec37 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -134,6 +134,8 @@ interface IConnectivityManager void captivePortalCheckComplete(in NetworkInfo info); + void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); + void supplyMessenger(int networkType, in Messenger messenger); int findConnectionTypeForIface(in String iface); @@ -141,4 +143,6 @@ interface IConnectivityManager int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); String getMobileProvisioningUrl(); + + String getMobileRedirectedProvisioningUrl(); } diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 54273ee..e4fd312 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -40,6 +40,7 @@ import com.android.internal.util.AsyncChannel; import java.io.CharArrayWriter; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicBoolean; /** * Track the state of mobile data connectivity. This is done by @@ -75,6 +76,8 @@ public class MobileDataStateTracker implements NetworkStateTracker { private Handler mHandler; private AsyncChannel mDataConnectionTrackerAc; + private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false); + /** * Create a new MobileDataStateTracker * @param netType the ConnectivityManager network type @@ -377,6 +380,15 @@ public class MobileDataStateTracker implements NetworkStateTracker { // not implemented } + @Override + public void captivePortalCheckCompleted(boolean isCaptivePortal) { + if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) { + // Captive portal change enable/disable failing fast + setEnableFailFastMobileData( + isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED); + } + } + /** * Record the detailed state of a network, and if it is a * change from the previous state, send a notification to diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index cf77a1c..9ed7533 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -144,6 +144,11 @@ public interface NetworkStateTracker { public void captivePortalCheckComplete(); /** + * Captive portal check has completed + */ + public void captivePortalCheckCompleted(boolean isCaptive); + + /** * Turn the wireless radio off for a network. * @param turnOn {@code true} to turn the radio on, {@code false} */ diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 12646bd..38ffb96 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -155,6 +155,7 @@ public abstract class BatteryStats implements Parcelable { private static final String BATTERY_LEVEL_DATA = "lv"; private static final String WIFI_DATA = "wfl"; private static final String MISC_DATA = "m"; + private static final String HISTORY_DATA = "h"; private static final String SCREEN_BRIGHTNESS_DATA = "br"; private static final String SIGNAL_STRENGTH_TIME_DATA = "sgt"; private static final String SIGNAL_SCANNING_TIME_DATA = "sst"; @@ -2390,7 +2391,7 @@ public abstract class BatteryStats implements Parcelable { while (getNextHistoryLocked(rec)) { pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); pw.print(0); pw.print(','); - pw.print("h"); pw.print(','); + pw.print(HISTORY_DATA); pw.print(','); hprinter.printNextItemCheckin(pw, rec, now); pw.println(); } diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 97ea99d..4d48fd4 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -17,10 +17,17 @@ package android.os; import android.util.Log; +import android.util.Slog; + +import libcore.io.ErrnoException; +import libcore.io.IoUtils; +import libcore.io.Libcore; +import libcore.io.OsConstants; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -58,9 +65,84 @@ public class FileUtils { /** Regular expression for safe filenames: no spaces or metacharacters */ private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); - public static native int setPermissions(String file, int mode, int uid, int gid); + /** + * Set owner and mode of of given {@link File}. + * + * @param mode to apply through {@code chmod} + * @param uid to apply through {@code chown}, or -1 to leave unchanged + * @param gid to apply through {@code chown}, or -1 to leave unchanged + * @return 0 on success, otherwise errno. + */ + public static int setPermissions(File path, int mode, int uid, int gid) { + return setPermissions(path.getAbsolutePath(), mode, uid, gid); + } + + /** + * Set owner and mode of of given path. + * + * @param mode to apply through {@code chmod} + * @param uid to apply through {@code chown}, or -1 to leave unchanged + * @param gid to apply through {@code chown}, or -1 to leave unchanged + * @return 0 on success, otherwise errno. + */ + public static int setPermissions(String path, int mode, int uid, int gid) { + try { + Libcore.os.chmod(path, mode); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to chmod(" + path + "): " + e); + return e.errno; + } + + if (uid >= 0 || gid >= 0) { + try { + Libcore.os.chown(path, uid, gid); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to chown(" + path + "): " + e); + return e.errno; + } + } + + return 0; + } + + /** + * Set owner and mode of of given {@link FileDescriptor}. + * + * @param mode to apply through {@code chmod} + * @param uid to apply through {@code chown}, or -1 to leave unchanged + * @param gid to apply through {@code chown}, or -1 to leave unchanged + * @return 0 on success, otherwise errno. + */ + public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) { + try { + Libcore.os.fchmod(fd, mode); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to fchmod(): " + e); + return e.errno; + } - public static native int getUid(String file); + if (uid >= 0 || gid >= 0) { + try { + Libcore.os.fchown(fd, uid, gid); + } catch (ErrnoException e) { + Slog.w(TAG, "Failed to fchown(): " + e); + return e.errno; + } + } + + return 0; + } + + /** + * Return owning UID of given path, otherwise -1. + */ + public static int getUid(String path) { + try { + return Libcore.os.stat(path).st_uid; + } catch (ErrnoException e) { + return -1; + } + } /** returns the FAT file system volume ID for the volume mounted * at the given mount point, or -1 for failure diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index ab0543d..cf9ddb3 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -100,12 +100,6 @@ public class Process { public static final int DRM_UID = 1019; /** - * Defines the GID for the group that allows write access to the SD card. - * @hide - */ - public static final int SDCARD_RW_GID = 1015; - - /** * Defines the UID/GID for the group that controls VPN services. * @hide */ @@ -130,11 +124,18 @@ public class Process { public static final int MEDIA_RW_GID = 1023; /** + * Access to installed package details + * @hide + */ + public static final int PACKAGE_INFO_GID = 1032; + + /** * Defines the start of a range of UIDs (and GIDs), going from this * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning * to applications. */ public static final int FIRST_APPLICATION_UID = 10000; + /** * Last of application-specific UIDs starting at * {@link #FIRST_APPLICATION_UID}. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index cbc6c5c..585115a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -33,6 +33,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.database.Cursor; import android.database.SQLException; +import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.Uri; import android.net.wifi.WifiManager; @@ -754,6 +755,10 @@ public final class Settings { private static final String TAG = "Settings"; private static final boolean LOCAL_LOGV = false; + // Lock ensures that when enabling/disabling the master location switch, we don't end up + // with a partial enable/disable state in multi-threaded situations. + private static final Object mLocationSettingsLock = new Object(); + public static class SettingNotFoundException extends AndroidException { public SettingNotFoundException(String msg) { super(msg); @@ -4320,6 +4325,20 @@ public final class Settings { } /** + * Helper method for determining if the location master switch is enabled. + * @param cr the content resolver to use + * @return true if the master switch is enabled + * @hide + */ + public static final boolean isLocationMasterSwitchEnabled(ContentResolver cr) { + int uid = UserHandle.myUserId(); + synchronized (mLocationSettingsLock) { + return isLocationProviderEnabledForUser(cr, LocationManager.NETWORK_PROVIDER, uid) + || isLocationProviderEnabledForUser(cr, LocationManager.GPS_PROVIDER, uid); + } + } + + /** * Helper method for determining if a location provider is enabled. * @param cr the content resolver to use * @param provider the location provider to query @@ -4345,6 +4364,23 @@ public final class Settings { } /** + * Thread-safe method for enabling or disabling the location master switch. + * + * @param cr the content resolver to use + * @param enabled true if master switch should be enabled + * @hide + */ + public static final void setLocationMasterSwitchEnabled(ContentResolver cr, + boolean enabled) { + int uid = UserHandle.myUserId(); + synchronized (mLocationSettingsLock) { + setLocationProviderEnabledForUser(cr, LocationManager.GPS_PROVIDER, enabled, uid); + setLocationProviderEnabledForUser(cr, LocationManager.NETWORK_PROVIDER, enabled, + uid); + } + } + + /** * Thread-safe method for enabling or disabling a single location provider. * @param cr the content resolver to use * @param provider the location provider to enable or disable @@ -4354,16 +4390,18 @@ public final class Settings { */ public static final void setLocationProviderEnabledForUser(ContentResolver cr, String provider, boolean enabled, int userId) { - // to ensure thread safety, we write the provider name with a '+' or '-' - // and let the SettingsProvider handle it rather than reading and modifying - // the list of enabled providers. - if (enabled) { - provider = "+" + provider; - } else { - provider = "-" + provider; + synchronized (mLocationSettingsLock) { + // to ensure thread safety, we write the provider name with a '+' or '-' + // and let the SettingsProvider handle it rather than reading and modifying + // the list of enabled providers. + if (enabled) { + provider = "+" + provider; + } else { + provider = "-" + provider; + } + putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider, + userId); } - putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider, - userId); } } @@ -5641,6 +5679,12 @@ public final class Settings { public static final String SELINUX_STATUS = "selinux_status"; /** + * Developer setting to force RTL layout. + * @hide + */ + public static final String DEVELOPMENT_FORCE_RTL = "debug.force_rtl"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index e2035c2..596ca8c 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -19,6 +19,8 @@ package android.text; import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import android.os.SystemProperties; +import android.provider.Settings; import android.text.style.AbsoluteSizeSpan; import android.text.style.AlignmentSpan; import android.text.style.BackgroundColorSpan; @@ -1743,8 +1745,10 @@ public class TextUtils { return View.LAYOUT_DIRECTION_RTL; } } - - return View.LAYOUT_DIRECTION_LTR; + // If forcing into RTL layout mode, return RTL as default, else LTR + return SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false) + ? View.LAYOUT_DIRECTION_RTL + : View.LAYOUT_DIRECTION_LTR; } /** diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 6b530ef..dc31e0b 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -59,13 +59,14 @@ public class SurfaceControl { private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId); private static native IBinder nativeCreateDisplay(String name, boolean secure); + private static native void nativeDestroyDisplay(IBinder displayToken); private static native void nativeSetDisplaySurface( IBinder displayToken, int nativeSurfaceObject); private static native void nativeSetDisplayLayerStack( IBinder displayToken, int layerStack); private static native void nativeSetDisplayProjection( IBinder displayToken, int orientation, - int l, int t, int r, int b, + int l, int t, int r, int b, int L, int T, int R, int B); private static native boolean nativeGetDisplayInfo( IBinder displayToken, SurfaceControl.PhysicalDisplayInfo outInfo); @@ -103,7 +104,7 @@ public class SurfaceControl { * measures will be taken to disallow the surface's content to be copied * from another process. In particular, screenshots and VNC servers will * be disabled, but other measures can take place, for instance the - * surface might not be hardware accelerated. + * surface might not be hardware accelerated. * */ public static final int SECURE = 0x00000080; @@ -247,10 +248,10 @@ public class SurfaceControl { throw new OutOfResourcesException( "Couldn't allocate SurfaceControl native object"); } - + mCloseGuard.open("release"); } - + @Override protected void finalize() throws Throwable { try { @@ -300,7 +301,7 @@ public class SurfaceControl { if (mNativeObject == 0) throw new NullPointerException( "mNativeObject is null. Have you called release() already?"); } - + /* * set surface parameters. * needs to be inside open/closeTransaction block @@ -369,7 +370,7 @@ public class SurfaceControl { public void setWindowCrop(Rect crop) { checkNotReleased(); if (crop != null) { - nativeSetWindowCrop(mNativeObject, + nativeSetWindowCrop(mNativeObject, crop.left, crop.top, crop.right, crop.bottom); } else { nativeSetWindowCrop(mNativeObject, 0, 0, 0, 0); @@ -397,19 +398,19 @@ public class SurfaceControl { public float xDpi; public float yDpi; public boolean secure; - + public PhysicalDisplayInfo() { } - + public PhysicalDisplayInfo(PhysicalDisplayInfo other) { copyFrom(other); } - + @Override public boolean equals(Object o) { return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o); } - + public boolean equals(PhysicalDisplayInfo other) { return other != null && width == other.width @@ -420,12 +421,12 @@ public class SurfaceControl { && yDpi == other.yDpi && secure == other.secure; } - + @Override public int hashCode() { return 0; // don't care } - + public void copyFrom(PhysicalDisplayInfo other) { width = other.width; height = other.height; @@ -435,7 +436,7 @@ public class SurfaceControl { yDpi = other.yDpi; secure = other.secure; } - + // For debugging purposes @Override public String toString() { @@ -481,7 +482,7 @@ public class SurfaceControl { throw new IllegalArgumentException("displayRect must not be null"); } nativeSetDisplayProjection(displayToken, orientation, - layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom, + layerStackRect.left, layerStackRect.top, layerStackRect.right, layerStackRect.bottom, displayRect.left, displayRect.top, displayRect.right, displayRect.bottom); } @@ -513,6 +514,13 @@ public class SurfaceControl { return nativeCreateDisplay(name, secure); } + public static void destroyDisplay(IBinder displayToken) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + nativeDestroyDisplay(displayToken); + } + public static IBinder getBuiltInDisplay(int builtInDisplayId) { return nativeGetBuiltInDisplay(builtInDisplayId); } @@ -608,7 +616,7 @@ public class SurfaceControl { SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); return nativeScreenshot(displayToken, width, height, 0, 0, true); } - + private static void screenshot(IBinder display, Surface consumer, int width, int height, int minLayer, int maxLayer, boolean allLayers) { if (display == null) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 20938f5..3dff1b0 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12062,7 +12062,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Resolve padding depending on layout direction. + * Resolves padding depending on layout direction, if applicable, and + * recomputes internal padding values to adjust for scroll bars. * * @hide */ @@ -12102,11 +12103,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; - internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, - mUserPaddingBottom); onRtlPropertiesChanged(resolvedLayoutDirection); } + internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); + mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; } @@ -14659,13 +14660,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ protected void resolveDrawables() { - if (canResolveLayoutDirection()) { - if (mBackground != null) { - mBackground.setLayoutDirection(getLayoutDirection()); - } - mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; - onResolveDrawables(getLayoutDirection()); + // Drawables resolution may need to happen before resolving the layout direction (which is + // done only during the measure() call). + // If the layout direction is not resolved yet, we cannot resolve the Drawables except in + // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. + // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or + // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout + // direction to be resolved as its resolved value will be the same as its raw value. + if (!isLayoutDirectionResolved() && + getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { + return; + } + + final int layoutDirection = isLayoutDirectionResolved() ? + getLayoutDirection() : getRawLayoutDirection(); + + if (mBackground != null) { + mBackground.setLayoutDirection(layoutDirection); } + mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; + onResolveDrawables(layoutDirection); } /** diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3f391ad..0ed846b 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -1243,6 +1243,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mFastScroller = new FastScroller(this); mFastScroller.setEnabled(true); } + + recomputePadding(); + + if (mFastScroller != null) { + mFastScroller.updateLayout(); + } } /** @@ -1303,7 +1309,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @Override public int getVerticalScrollbarWidth() { - if (isFastScrollAlwaysVisible() && mFastScroller != null) { + if (mFastScroller != null && mFastScroller.isEnabled()) { return Math.max(super.getVerticalScrollbarWidth(), mFastScroller.getWidth()); } return super.getVerticalScrollbarWidth(); @@ -1327,6 +1333,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } + @Override + public void setScrollBarStyle(int style) { + super.setScrollBarStyle(style); + if (mFastScroller != null) { + mFastScroller.setScrollBarStyle(style); + } + } + /** * If fast scroll is enabled, then don't draw the vertical scrollbar. * @hide @@ -2787,7 +2801,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @Override public void onRtlPropertiesChanged(int layoutDirection) { super.onRtlPropertiesChanged(layoutDirection); - if (mFastScroller != null) { mFastScroller.setScrollbarPosition(getVerticalScrollbarPosition()); } diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index 393720f..c48955f 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -131,6 +131,9 @@ class FastScroller { /** Whether there is a track image to display. */ private final boolean mHasTrackImage; + /** Total width of decorations. */ + private final int mWidth; + /** Set containing decoration transition animations. */ private AnimatorSet mDecorAnimation; @@ -155,6 +158,9 @@ class FastScroller { /** The index of the current section. */ private int mCurrentSection = -1; + /** The current scrollbar position. */ + private int mScrollbarPosition = -1; + /** Whether the list is long enough to need a fast scroller. */ private boolean mLongList; @@ -194,6 +200,9 @@ class FastScroller { */ private int mOverlayPosition; + /** Current scrollbar style, including inset and overlay properties. */ + private int mScrollBarStyle; + /** Whether to precisely match the thumb position to the list. */ private boolean mMatchDragPosition; @@ -245,34 +254,44 @@ class FastScroller { final Resources res = context.getResources(); final TypedArray ta = context.getTheme().obtainStyledAttributes(ATTRS); - mTrackImage = new ImageView(context); + final ImageView trackImage = new ImageView(context); + mTrackImage = trackImage; + + int width = 0; // Add track to overlay if it has an image. - final int trackResId = ta.getResourceId(TRACK_DRAWABLE, 0); - if (trackResId != 0) { + final Drawable trackDrawable = ta.getDrawable(TRACK_DRAWABLE); + if (trackDrawable != null) { mHasTrackImage = true; - mTrackImage.setBackgroundResource(trackResId); - mOverlay.add(mTrackImage); + trackImage.setBackground(trackDrawable); + mOverlay.add(trackImage); + width = Math.max(width, trackDrawable.getIntrinsicWidth()); } else { mHasTrackImage = false; } - mThumbImage = new ImageView(context); + final ImageView thumbImage = new ImageView(context); + mThumbImage = thumbImage; // Add thumb to overlay if it has an image. final Drawable thumbDrawable = ta.getDrawable(THUMB_DRAWABLE); if (thumbDrawable != null) { - mThumbImage.setImageDrawable(thumbDrawable); - mOverlay.add(mThumbImage); + thumbImage.setImageDrawable(thumbDrawable); + mOverlay.add(thumbImage); + width = Math.max(width, thumbDrawable.getIntrinsicWidth()); } // If necessary, apply minimum thumb width and height. if (thumbDrawable.getIntrinsicWidth() <= 0 || thumbDrawable.getIntrinsicHeight() <= 0) { - mThumbImage.setMinimumWidth(res.getDimensionPixelSize(R.dimen.fastscroll_thumb_width)); - mThumbImage.setMinimumHeight( + final int minWidth = res.getDimensionPixelSize(R.dimen.fastscroll_thumb_width); + thumbImage.setMinimumWidth(minWidth); + thumbImage.setMinimumHeight( res.getDimensionPixelSize(R.dimen.fastscroll_thumb_height)); + width = Math.max(width, minWidth); } + mWidth = width; + final int previewSize = res.getDimensionPixelSize(R.dimen.fastscroll_overlay_size); mPreviewImage = new ImageView(context); mPreviewImage.setMinimumWidth(previewSize); @@ -297,10 +316,11 @@ class FastScroller { mOverlayPosition = ta.getInt(OVERLAY_POSITION, OVERLAY_FLOATING); ta.recycle(); + mScrollBarStyle = listView.getScrollBarStyle(); mScrollCompleted = true; mState = STATE_VISIBLE; - mMatchDragPosition = - context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB; + mMatchDragPosition = context.getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.HONEYCOMB; getSectionsFromIndexer(); refreshDrawablePressedState(); @@ -362,6 +382,14 @@ class FastScroller { return mAlwaysShow; } + public void setScrollBarStyle(int style) { + if (mScrollBarStyle != style) { + mScrollBarStyle = style; + + updateLayout(); + } + } + /** * Immediately transitions the fast scroller decorations to a hidden state. */ @@ -375,25 +403,29 @@ class FastScroller { View.SCROLLBAR_POSITION_LEFT : View.SCROLLBAR_POSITION_RIGHT; } - mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; + if (mScrollbarPosition != position) { + mScrollbarPosition = position; + mLayoutFromRight = position != View.SCROLLBAR_POSITION_LEFT; - final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; - mPreviewImage.setBackgroundResource(previewResId); + final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT]; + mPreviewImage.setBackgroundResource(previewResId); - // Add extra padding for text. - final Drawable background = mPreviewImage.getBackground(); - if (background != null) { - final Rect padding = mTempBounds; - background.getPadding(padding); - padding.offset(mPreviewPadding, mPreviewPadding); - mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom); - } + // Add extra padding for text. + final Drawable background = mPreviewImage.getBackground(); + if (background != null) { + final Rect padding = mTempBounds; + background.getPadding(padding); + padding.offset(mPreviewPadding, mPreviewPadding); + mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom); + } - updateLayout(); + // Requires re-layout. + updateLayout(); + } } public int getWidth() { - return mThumbImage.getWidth(); + return mWidth; } public void onSizeChanged(int w, int h, int oldw, int oldh) { @@ -437,7 +469,7 @@ class FastScroller { /** * Measures and layouts the scrollbar and decorations. */ - private void updateLayout() { + public void updateLayout() { // Prevent re-entry when RTL properties change as a side-effect of // resolving padding. if (mUpdatingLayout) { @@ -594,21 +626,36 @@ class FastScroller { out.set(left, top, right, bottom); } + /** + * Updates the container rectangle used for layout. + */ private void updateContainerRect() { final AbsListView list = mList; + list.resolvePadding(); + final Rect container = mContainerRect; container.left = 0; container.top = 0; container.right = list.getWidth(); container.bottom = list.getHeight(); - final int scrollbarStyle = list.getScrollBarStyle(); + final int scrollbarStyle = mScrollBarStyle; if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET || scrollbarStyle == View.SCROLLBARS_INSIDE_OVERLAY) { container.left += list.getPaddingLeft(); container.top += list.getPaddingTop(); container.right -= list.getPaddingRight(); container.bottom -= list.getPaddingBottom(); + + // In inset mode, we need to adjust for padded scrollbar width. + if (scrollbarStyle == View.SCROLLBARS_INSIDE_INSET) { + final int width = getWidth(); + if (mScrollbarPosition == View.SCROLLBAR_POSITION_RIGHT) { + container.right += width; + } else { + container.left -= width; + } + } } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3181164..9c21f0d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -1378,6 +1378,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0; } + resetResolvedDrawables(); + resolveDrawables(); } } |
