summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityThread.java77
-rw-r--r--core/java/android/app/SearchManager.java2
-rw-r--r--core/java/android/inputmethodservice/Keyboard.java46
-rw-r--r--core/java/android/inputmethodservice/KeyboardView.java4
-rw-r--r--core/java/android/net/DhcpInfoInternal.java45
-rw-r--r--core/java/android/net/DhcpStateMachine.java5
-rw-r--r--core/java/android/provider/MediaStore.java11
-rw-r--r--core/java/android/text/method/Touch.java43
-rw-r--r--core/java/android/view/ActionProvider.java28
-rw-r--r--core/java/android/view/IWindowManager.aidl13
-rw-r--r--core/java/android/view/Surface.java5
-rw-r--r--core/java/android/view/ViewGroup.java13
-rw-r--r--core/java/android/view/ViewRootImpl.java1
-rw-r--r--core/java/android/view/VolumePanel.java38
-rw-r--r--core/java/android/view/WindowManagerPolicy.java59
-rwxr-xr-xcore/java/android/view/WindowOrientationListener.java13
-rw-r--r--core/java/android/view/textservice/TextServicesManager.java4
-rw-r--r--core/java/android/webkit/CookieSyncManager.java4
-rw-r--r--core/java/android/webkit/JniUtil.java16
-rw-r--r--core/java/android/webkit/WebView.java37
-rw-r--r--core/java/android/webkit/WebViewCore.java9
-rw-r--r--core/java/android/webkit/ZoomManager.java6
-rw-r--r--core/java/android/widget/ActivityChooserView.java62
-rw-r--r--core/java/android/widget/AdapterView.java11
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java21
-rw-r--r--core/java/android/widget/CalendarView.java20
-rw-r--r--core/java/android/widget/GridLayout.java472
-rw-r--r--core/java/android/widget/MediaController.java1
-rw-r--r--core/java/android/widget/OverScroller.java8
-rw-r--r--core/java/android/widget/PopupMenu.java2
-rw-r--r--core/java/android/widget/PopupWindow.java17
-rw-r--r--core/java/android/widget/RelativeLayout.java5
-rw-r--r--core/java/android/widget/ShareActionProvider.java1
-rw-r--r--core/java/android/widget/TextView.java24
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuPresenter.java31
-rw-r--r--core/java/com/android/internal/view/menu/IconMenuPresenter.java4
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java33
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java9
-rw-r--r--core/java/com/android/server/NetworkManagementSocketTagger.java117
39 files changed, 827 insertions, 490 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2c2a493..0776e10 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -153,6 +153,7 @@ public final class ActivityThread {
final HashMap<IBinder, Service> mServices
= new HashMap<IBinder, Service>();
AppBindData mBoundApplication;
+ Profiler mProfiler;
Configuration mConfiguration;
Configuration mCompatConfiguration;
Configuration mResConfiguration;
@@ -364,10 +365,6 @@ public final class ActivityThread {
ApplicationInfo appInfo;
List<ProviderInfo> providers;
ComponentName instrumentationName;
- String profileFile;
- ParcelFileDescriptor profileFd;
- boolean autoStopProfiler;
- boolean profiling;
Bundle instrumentationArgs;
IInstrumentationWatcher instrumentationWatcher;
int debugMode;
@@ -375,10 +372,23 @@ public final class ActivityThread {
boolean persistent;
Configuration config;
CompatibilityInfo compatInfo;
- boolean handlingProfiling;
+
+ /** Initial values for {@link Profiler}. */
+ String initProfileFile;
+ ParcelFileDescriptor initProfileFd;
+ boolean initAutoStopProfiler;
+
public String toString() {
return "AppBindData{appInfo=" + appInfo + "}";
}
+ }
+
+ static final class Profiler {
+ String profileFile;
+ ParcelFileDescriptor profileFd;
+ boolean autoStopProfiler;
+ boolean profiling;
+ boolean handlingProfiling;
public void setProfiler(String file, ParcelFileDescriptor fd) {
if (profiling) {
if (fd != null) {
@@ -661,8 +671,6 @@ public final class ActivityThread {
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
- data.setProfiler(profileFile, profileFd);
- data.autoStopProfiler = false;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.debugMode = debugMode;
@@ -670,6 +678,9 @@ public final class ActivityThread {
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
+ data.initProfileFile = profileFile;
+ data.initProfileFd = profileFd;
+ data.initAutoStopProfiler = false;
queueOrSendMessage(H.BIND_APPLICATION, data);
}
@@ -1293,8 +1304,8 @@ public final class ActivityThread {
public final boolean queueIdle() {
ActivityClientRecord a = mNewActivities;
boolean stopProfiling = false;
- if (mBoundApplication != null && mBoundApplication.profileFd != null
- && mBoundApplication.autoStopProfiler) {
+ if (mBoundApplication != null && mProfiler.profileFd != null
+ && mProfiler.autoStopProfiler) {
stopProfiling = true;
}
if (a != null) {
@@ -1320,7 +1331,7 @@ public final class ActivityThread {
} while (a != null);
}
if (stopProfiling) {
- mBoundApplication.stopProfiling();
+ mProfiler.stopProfiling();
}
ensureJitEnabled();
return false;
@@ -1635,12 +1646,12 @@ public final class ActivityThread {
}
public boolean isProfiling() {
- return mBoundApplication != null && mBoundApplication.profileFile != null
- && mBoundApplication.profileFd == null;
+ return mProfiler != null && mProfiler.profileFile != null
+ && mProfiler.profileFd == null;
}
public String getProfileFilePath() {
- return mBoundApplication.profileFile;
+ return mProfiler.profileFile;
}
public Looper getLooper() {
@@ -1679,6 +1690,9 @@ public final class ActivityThread {
ContextImpl context = getSystemContext();
context.init(new LoadedApk(this, "android", context, info,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this);
+
+ // give ourselves a default profiler
+ mProfiler = new Profiler();
}
}
@@ -1947,9 +1961,9 @@ public final class ActivityThread {
unscheduleGcIdler();
if (r.profileFd != null) {
- mBoundApplication.setProfiler(r.profileFile, r.profileFd);
- mBoundApplication.startProfiling();
- mBoundApplication.autoStopProfiler = r.autoStopProfiler;
+ mProfiler.setProfiler(r.profileFile, r.profileFd);
+ mProfiler.startProfiling();
+ mProfiler.autoStopProfiler = r.autoStopProfiler;
}
if (localLOGV) Slog.v(
@@ -3570,10 +3584,10 @@ public final class ActivityThread {
case 1:
ViewDebug.startLooperProfiling(pcd.path, pcd.fd.getFileDescriptor());
break;
- default:
- mBoundApplication.setProfiler(pcd.path, pcd.fd);
- mBoundApplication.autoStopProfiler = false;
- mBoundApplication.startProfiling();
+ default:
+ mProfiler.setProfiler(pcd.path, pcd.fd);
+ mProfiler.autoStopProfiler = false;
+ mProfiler.startProfiling();
break;
}
} catch (RuntimeException e) {
@@ -3592,7 +3606,7 @@ public final class ActivityThread {
ViewDebug.stopLooperProfiling();
break;
default:
- mBoundApplication.stopProfiling();
+ mProfiler.stopProfiling();
break;
}
}
@@ -3685,6 +3699,11 @@ public final class ActivityThread {
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
+ mProfiler = new Profiler();
+ mProfiler.profileFile = data.initProfileFile;
+ mProfiler.profileFd = data.initProfileFd;
+ mProfiler.autoStopProfiler = data.initAutoStopProfiler;
+
// send up app name; do this *before* waiting for debugger
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName);
@@ -3699,8 +3718,8 @@ public final class ActivityThread {
}
}
- if (data.profileFd != null) {
- data.startProfiling();
+ if (mProfiler.profileFd != null) {
+ mProfiler.startProfiling();
}
// If the app is Honeycomb MR1 or earlier, switch its AsyncTask
@@ -3841,10 +3860,10 @@ public final class ActivityThread {
mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher);
- if (data.profileFile != null && !ii.handleProfiling
- && data.profileFd == null) {
- data.handlingProfiling = true;
- File file = new File(data.profileFile);
+ if (mProfiler.profileFile != null && !ii.handleProfiling
+ && mProfiler.profileFd == null) {
+ mProfiler.handlingProfiling = true;
+ File file = new File(mProfiler.profileFile);
file.getParentFile().mkdirs();
Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
}
@@ -3896,8 +3915,8 @@ public final class ActivityThread {
/*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
IActivityManager am = ActivityManagerNative.getDefault();
- if (mBoundApplication.profileFile != null && mBoundApplication.handlingProfiling
- && mBoundApplication.profileFd == null) {
+ if (mProfiler.profileFile != null && mProfiler.handlingProfiling
+ && mProfiler.profileFd == null) {
Debug.stopMethodTracing();
}
//Slog.i(TAG, "am: " + ActivityManagerNative.getDefault()
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 5c4cc87..3290b9d 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -338,7 +338,7 @@ public class SearchManager
/**
* Column name for suggestions cursor. <i>Optional.</i> This column may be
- * used to specify the time in (@link System#currentTimeMillis
+ * used to specify the time in {@link System#currentTimeMillis
* System.currentTImeMillis()} (wall time in UTC) when an item was last
* accessed within the results-providing application. If set, this may be
* used to show more-recently-used items first.
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index 10386f8..4fe54c0 100644
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -144,6 +144,8 @@ public class Keyboard {
/** Number of key widths from current touch point to search for nearest keys. */
private static float SEARCH_DISTANCE = 1.8f;
+ private ArrayList<Row> rows = new ArrayList<Row>();
+
/**
* Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
* Some of the key size defaults can be overridden per row from what the {@link Keyboard}
@@ -164,6 +166,9 @@ public class Keyboard {
public int defaultHorizontalGap;
/** Vertical gap following this row. */
public int verticalGap;
+
+ ArrayList<Key> mKeys = new ArrayList<Key>();
+
/**
* Edge flags for this row of keys. Possible values that can be assigned are
* {@link Keyboard#EDGE_TOP EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM EDGE_BOTTOM}
@@ -256,7 +261,7 @@ public class Keyboard {
public CharSequence text;
/** Popup characters */
public CharSequence popupCharacters;
-
+
/**
* Flags that specify the anchoring to edges of the keyboard for detecting touch events
* that are just out of the boundary of the key. This is a bit mask of
@@ -596,11 +601,44 @@ public class Keyboard {
column++;
x += key.width + key.gap;
mKeys.add(key);
+ row.mKeys.add(key);
if (x > mTotalWidth) {
mTotalWidth = x;
}
}
- mTotalHeight = y + mDefaultHeight;
+ mTotalHeight = y + mDefaultHeight;
+ rows.add(row);
+ }
+
+ final void resize(int newWidth, int newHeight) {
+ int numRows = rows.size();
+ for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) {
+ Row row = rows.get(rowIndex);
+ int numKeys = row.mKeys.size();
+ int totalGap = 0;
+ int totalWidth = 0;
+ for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) {
+ Key key = row.mKeys.get(keyIndex);
+ if (keyIndex > 0) {
+ totalGap += key.gap;
+ }
+ totalWidth += key.width;
+ }
+ if (totalGap + totalWidth > newWidth) {
+ int x = 0;
+ float scaleFactor = (float)(newWidth - totalGap) / totalWidth;
+ for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) {
+ Key key = row.mKeys.get(keyIndex);
+ key.width *= scaleFactor;
+ key.x = x;
+ x += key.width + key.gap;
+ }
+ }
+ }
+ mTotalWidth = newWidth;
+ // TODO: This does not adjust the vertical placement according to the new size.
+ // The main problem in the previous code was horizontal placement/size, but we should
+ // also recalculate the vertical sizes/positions when we get this resize call.
}
public List<Key> getKeys() {
@@ -749,7 +787,7 @@ public class Keyboard {
Row currentRow = null;
Resources res = context.getResources();
boolean skipRow = false;
-
+
try {
int event;
while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
@@ -759,6 +797,7 @@ public class Keyboard {
inRow = true;
x = 0;
currentRow = createRowFromXml(res, parser);
+ rows.add(currentRow);
skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode;
if (skipRow) {
skipToEndOfRow(parser);
@@ -781,6 +820,7 @@ public class Keyboard {
} else if (key.codes[0] == KEYCODE_ALT) {
mModifierKeys.add(key);
}
+ currentRow.mKeys.add(key);
} else if (TAG_KEYBOARD.equals(tag)) {
parseKeyboardAttributes(res, parser);
}
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 05444f6..1119c1e 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -376,6 +376,7 @@ public class KeyboardView extends View implements View.OnClickListener {
initGestureDetector();
}
+
private void initGestureDetector() {
mGestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
@@ -615,6 +616,9 @@ public class KeyboardView extends View implements View.OnClickListener {
@Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
+ if (mKeyboard != null) {
+ mKeyboard.resize(w, h);
+ }
// Release the buffer, if any and it will be reallocated on the next draw
mBuffer = null;
}
diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java
index 9b0a2d7..fa77bc5 100644
--- a/core/java/android/net/DhcpInfoInternal.java
+++ b/core/java/android/net/DhcpInfoInternal.java
@@ -24,6 +24,7 @@ import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
/**
* A simple object for retrieving the results of a DHCP request.
@@ -41,14 +42,18 @@ public class DhcpInfoInternal {
public String serverAddress;
public int leaseDuration;
- private Collection<RouteInfo> routes;
+ private Collection<RouteInfo> mRoutes;
public DhcpInfoInternal() {
- routes = new ArrayList<RouteInfo>();
+ mRoutes = new ArrayList<RouteInfo>();
}
public void addRoute(RouteInfo routeInfo) {
- routes.add(routeInfo);
+ mRoutes.add(routeInfo);
+ }
+
+ public Collection<RouteInfo> getRoutes() {
+ return Collections.unmodifiableCollection(mRoutes);
}
private int convertToInt(String addr) {
@@ -66,7 +71,7 @@ public class DhcpInfoInternal {
public DhcpInfo makeDhcpInfo() {
DhcpInfo info = new DhcpInfo();
info.ipAddress = convertToInt(ipAddress);
- for (RouteInfo route : routes) {
+ for (RouteInfo route : mRoutes) {
if (route.isDefaultRoute()) {
info.gateway = convertToInt(route.getGateway().getHostAddress());
break;
@@ -94,14 +99,14 @@ public class DhcpInfoInternal {
public LinkProperties makeLinkProperties() {
LinkProperties p = new LinkProperties();
p.addLinkAddress(makeLinkAddress());
- for (RouteInfo route : routes) {
+ for (RouteInfo route : mRoutes) {
p.addRoute(route);
}
+ //if empty, connectivity configures default DNS
if (TextUtils.isEmpty(dns1) == false) {
p.addDns(NetworkUtils.numericToInetAddress(dns1));
} else {
- p.addDns(NetworkUtils.numericToInetAddress(serverAddress));
- Log.d(TAG, "empty dns1, use dhcp server as dns1!");
+ Log.d(TAG, "makeLinkProperties with empty dns1!");
}
if (TextUtils.isEmpty(dns2) == false) {
p.addDns(NetworkUtils.numericToInetAddress(dns2));
@@ -111,11 +116,33 @@ public class DhcpInfoInternal {
return p;
}
+ /* Updates the DHCP fields that need to be retained from
+ * original DHCP request if the DHCP renewal shows them as
+ * being empty
+ */
+ public void updateFromDhcpRequest(DhcpInfoInternal orig) {
+ if (orig == null) return;
+
+ if (TextUtils.isEmpty(dns1)) {
+ dns1 = orig.dns1;
+ }
+
+ if (TextUtils.isEmpty(dns2)) {
+ dns2 = orig.dns2;
+ }
+
+ if (mRoutes.size() == 0) {
+ for (RouteInfo route : orig.getRoutes()) {
+ addRoute(route);
+ }
+ }
+ }
+
public String toString() {
String routeString = "";
- for (RouteInfo route : routes) routeString += route.toString() + " | ";
+ for (RouteInfo route : mRoutes) routeString += route.toString() + " | ";
return "addr: " + ipAddress + "/" + prefixLength +
- " routes: " + routeString +
+ " mRoutes: " + routeString +
" dns: " + dns1 + "," + dns2 +
" dhcpServer: " + serverAddress +
" leaseDuration: " + leaseDuration;
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index 445b2f7..79c9395 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -63,6 +63,9 @@ public class DhcpStateMachine extends StateMachine {
private PowerManager.WakeLock mDhcpRenewWakeLock;
private static final String WAKELOCK_TAG = "DHCP";
+ //Remember DHCP configuration from first request
+ private DhcpInfoInternal mDhcpInfo;
+
private static final int DHCP_RENEW = 0;
private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
@@ -335,9 +338,11 @@ public class DhcpStateMachine extends StateMachine {
if (dhcpAction == DhcpAction.START) {
Log.d(TAG, "DHCP request on " + mInterfaceName);
success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
+ mDhcpInfo = dhcpInfoInternal;
} else if (dhcpAction == DhcpAction.RENEW) {
Log.d(TAG, "DHCP renewal on " + mInterfaceName);
success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal);
+ dhcpInfoInternal.updateFromDhcpRequest(mDhcpInfo);
}
if (success) {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 5da3114..5f111eb 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -283,6 +283,17 @@ public final class MediaStore {
*/
public static final String IS_DRM = "is_drm";
+ /**
+ * The width of the image/video in pixels.
+ * @hide
+ */
+ public static final String WIDTH = "width";
+
+ /**
+ * The height of the image/video in pixels.
+ * @hide
+ */
+ public static final String HEIGHT = "height";
}
/**
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index 3f9b945..106a801 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -35,44 +35,39 @@ public class Touch {
* Y position.
*/
public static void scrollTo(TextView widget, Layout layout, int x, int y) {
- int padding = widget.getTotalPaddingTop() +
- widget.getTotalPaddingBottom();
- int top = layout.getLineForVertical(y);
- int bottom = layout.getLineForVertical(y + widget.getHeight() -
- padding);
+ final int verticalPadding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
+ final int top = layout.getLineForVertical(y);
+ final int bottom = layout.getLineForVertical(y + widget.getHeight() - verticalPadding);
int left = Integer.MAX_VALUE;
int right = 0;
- Alignment a = null;
- boolean ltr = true;
+ Alignment a = layout.getParagraphAlignment(top);
+ boolean ltr = layout.getParagraphDirection(top) > 0;
for (int i = top; i <= bottom; i++) {
left = (int) Math.min(left, layout.getLineLeft(i));
right = (int) Math.max(right, layout.getLineRight(i));
-
- if (a == null) {
- a = layout.getParagraphAlignment(i);
- ltr = layout.getParagraphDirection(i) > 0;
- }
}
- padding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight();
- int width = widget.getWidth();
- int diff = 0;
+ final int hoizontalPadding = widget.getTotalPaddingLeft() + widget.getTotalPaddingRight();
+ final int availableWidth = widget.getWidth() - hoizontalPadding;
+ final int actualWidth = right - left;
- // align_opposite does NOT mean align_right, we need the paragraph
- // direction to resolve it to left or right
- if (right - left < width - padding) {
+ if (actualWidth < availableWidth) {
if (a == Alignment.ALIGN_CENTER) {
- diff = (width - padding - (right - left)) / 2;
- } else if (ltr == (a == Alignment.ALIGN_OPPOSITE)) {
- diff = width - padding - (right - left);
+ x = left - ((availableWidth - actualWidth) / 2);
+ } else if ((ltr && (a == Alignment.ALIGN_OPPOSITE)) || (a == Alignment.ALIGN_RIGHT)) {
+ // align_opposite does NOT mean align_right, we need the paragraph
+ // direction to resolve it to left or right
+ x = left - (availableWidth - actualWidth);
+ } else {
+ x = left;
}
+ } else {
+ x = Math.min(x, right - availableWidth);
+ x = Math.max(x, left);
}
- x = Math.min(x, right - (width - padding) - diff);
- x = Math.max(x, left - diff);
-
widget.scrollTo(x, y);
}
diff --git a/core/java/android/view/ActionProvider.java b/core/java/android/view/ActionProvider.java
index 5601dc5..ed976ab 100644
--- a/core/java/android/view/ActionProvider.java
+++ b/core/java/android/view/ActionProvider.java
@@ -58,6 +58,7 @@ import android.content.Context;
* @see MenuItem#getActionProvider()
*/
public abstract class ActionProvider {
+ private SubUiVisibilityListener mSubUiVisibilityListener;
/**
* Creates a new instance.
@@ -138,4 +139,31 @@ public abstract class ActionProvider {
*/
public void onPrepareSubMenu(SubMenu subMenu) {
}
+
+ /**
+ * Notify the system that the visibility of an action view's sub-UI such as
+ * an anchored popup has changed. This will affect how other system
+ * visibility notifications occur.
+ *
+ * @hide Pending future API approval
+ */
+ public void subUiVisibilityChanged(boolean isVisible) {
+ if (mSubUiVisibilityListener != null) {
+ mSubUiVisibilityListener.onSubUiVisibilityChanged(isVisible);
+ }
+ }
+
+ /**
+ * @hide Internal use only
+ */
+ public void setSubUiVisibilityListener(SubUiVisibilityListener listener) {
+ mSubUiVisibilityListener = listener;
+ }
+
+ /**
+ * @hide Internal use only
+ */
+ public interface SubUiVisibilityListener {
+ public void onSubUiVisibilityChanged(boolean isVisible);
+ }
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0dc781f..55c821d 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -23,6 +23,7 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Point;
+import android.os.IRemoteCallback;
import android.view.IApplicationToken;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
@@ -162,15 +163,13 @@ interface IWindowManager
// These can only be called with the SET_ORIENTATION permission.
/**
- * Change the current screen rotation, constants as per
- * {@link android.view.Surface}.
- * @param rotation the intended rotation.
+ * Update the current screen rotation based on the current state of
+ * the world.
* @param alwaysSendConfiguration Flag to force a new configuration to
* be evaluated. This can be used when there are other parameters in
* configuration that are changing.
- * @param animFlags Animation flags as per {@link android.view.Surface}.
*/
- void setRotation(int rotation, boolean alwaysSendConfiguration, int animFlags);
+ void updateRotation(boolean alwaysSendConfiguration);
/**
* Retrieve the current screen orientation, constants as per
@@ -220,7 +219,7 @@ interface IWindowManager
void setPointerSpeed(int speed);
/**
- * Block until all windows the window manager knows about have been drawn.
+ * Block until the given window has been drawn to the screen.
*/
- void waitForAllDrawn();
+ void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 3880bc4..64d3d31 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -207,9 +207,6 @@ public class Surface implements Parcelable {
/** Enable dithering when compositing this surface @hide */
public static final int SURFACE_DITHER = 0x04;
-
- /** Disable the orientation animation @hide */
- public static final int FLAGS_ORIENTATION_ANIMATION_DISABLE = 0x000000001;
// The mSurfaceControl will only be present for Surfaces used by the window
// server or system processes. When this class is parceled we defer to the
@@ -393,7 +390,7 @@ public class Surface implements Parcelable {
* set the orientation of the given display.
* @param display
* @param orientation
- * @param flags
+ * @param flags Currently unused, set to 0.
* @hide
*/
public static native void setOrientation(int display, int orientation, int flags);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c7b59b8..b678c7d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -290,6 +290,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
/**
+ * When set, this ViewGroup will not dispatch onAttachedToWindow calls
+ * to children when adding new views. This is used to prevent multiple
+ * onAttached calls when a ViewGroup adds children in its own onAttached method.
+ */
+ private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
+
+ /**
* Indicates which types of drawing caches are to be kept in memory.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
@@ -2154,8 +2161,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
@Override
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
+ mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
super.dispatchAttachedToWindow(info, visibility);
+ mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
+
visibility |= mViewFlags & VISIBILITY_MASK;
+
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
@@ -3321,7 +3332,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
AttachInfo ai = mAttachInfo;
- if (ai != null) {
+ if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
boolean lastKeepOn = ai.mKeepScreenOn;
ai.mKeepScreenOn = false;
child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4611984..9cb4e5e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1054,7 +1054,6 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|| attachInfo.mSystemUiVisibility != oldVis
|| attachInfo.mHasSystemUiListeners) {
params = lp;
- windowAttributesChanges |= WindowManager.LayoutParams.BUFFER_CHANGED;
}
}
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index fb87e23..122865e 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -34,10 +34,12 @@ import android.media.ToneGenerator;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
+import android.os.RemoteException;
import android.os.Vibrator;
import android.provider.Settings;
import android.provider.Settings.System;
import android.util.Log;
+import android.view.WindowManager.LayoutParams;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -175,20 +177,8 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
View view = mView = inflater.inflate(R.layout.volume_adjust, null);
mView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
- // Dismiss the dialog if the user touches outside the visible area. This is not
- // handled by the usual dialog dismissing code because there is a region above
- // the panel (marginTop) that is still within the dialog.
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- int x = (int) event.getX();
- int y = (int) event.getY();
- if (x < mPanel.getLeft() || x > mPanel.getRight() || y < mPanel.getTop()
- || y > mPanel.getBottom()) {
- forceTimeout();
- return true;
- }
- }
resetTimeout();
- return true;
+ return false;
}
});
mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
@@ -196,7 +186,15 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
mMoreButton = (ImageView) mView.findViewById(R.id.expand_button);
mDivider = (ImageView) mView.findViewById(R.id.expand_button_divider);
- mDialog = new Dialog(context, R.style.Theme_Panel_Volume);
+ mDialog = new Dialog(context, R.style.Theme_Panel_Volume) {
+ public boolean onTouchEvent(MotionEvent event) {
+ if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ forceTimeout();
+ return true;
+ }
+ return false;
+ }
+ };
mDialog.setTitle("Volume control"); // No need to localize
mDialog.setContentView(mView);
mDialog.setOnDismissListener(new OnDismissListener() {
@@ -208,11 +206,17 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
// Change some window properties
Window window = mDialog.getWindow();
window.setGravity(Gravity.TOP);
- WindowManager.LayoutParams lp = window.getAttributes();
+ LayoutParams lp = window.getAttributes();
lp.token = null;
- lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+ // Offset from the top
+ lp.y = mContext.getResources().getDimensionPixelOffset(
+ com.android.internal.R.dimen.volume_panel_top);
+ lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
+ lp.width = LayoutParams.WRAP_CONTENT;
+ lp.height = LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);
- window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+ window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
mVibrator = new Vibrator();
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 980e454..1dbb083 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -375,12 +375,6 @@ public interface WindowManagerPolicy {
/** Screen turned off because of proximity sensor */
public final int OFF_BECAUSE_OF_PROX_SENSOR = 4;
- /**
- * Magic constant to {@link IWindowManager#setRotation} to not actually
- * modify the rotation.
- */
- public final int USE_LAST_ROTATION = -1000;
-
/** When not otherwise specified by the activity's screenOrientation, rotation should be
* determined by the system (that is, using sensors). */
public final int USER_ROTATION_FREE = 0;
@@ -772,15 +766,26 @@ public interface WindowManagerPolicy {
*/
public void screenTurnedOff(int why);
+ public interface ScreenOnListener {
+ void onScreenOn();
+ };
+
/**
- * Called after the screen turns on.
+ * Called when the power manager would like to turn the screen on.
+ * Must call back on the listener to tell it when the higher-level system
+ * is ready for the screen to go on (i.e. the lock screen is shown).
*/
- public void screenTurnedOn();
+ public void screenTurningOn(ScreenOnListener screenOnListener);
/**
- * Return whether the screen is currently on.
+ * Return whether the screen is about to turn on or is currently on.
*/
- public boolean isScreenOn();
+ public boolean isScreenOnEarly();
+
+ /**
+ * Return whether the screen is fully turned on.
+ */
+ public boolean isScreenOnFully();
/**
* Tell the policy that the lid switch has changed state.
@@ -845,22 +850,30 @@ public interface WindowManagerPolicy {
public boolean inKeyguardRestrictedKeyInputMode();
/**
- * Given an orientation constant
- * ({@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE
- * ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE} or
- * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_PORTRAIT
- * ActivityInfo.SCREEN_ORIENTATION_PORTRAIT}), return a surface
- * rotation.
+ * Given an orientation constant, returns the appropriate surface rotation,
+ * taking into account sensors, docking mode, rotation lock, and other factors.
+ *
+ * @param orientation An orientation constant, such as
+ * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
+ * @param lastRotation The most recently used rotation.
+ * @return The surface rotation to use.
*/
- public int rotationForOrientationLw(int orientation, int lastRotation,
- boolean displayEnabled);
-
+ public int rotationForOrientationLw(int orientation, int lastRotation);
+
/**
- * Return the currently locked screen rotation, if any. Return
- * Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180, or
- * Surface.ROTATION_270 if locked; return -1 if not locked.
+ * Given an orientation constant and a rotation, returns true if the rotation
+ * has compatible metrics to the requested orientation. For example, if
+ * the application requested landscape and got seascape, then the rotation
+ * has compatible metrics; if the application requested portrait and got landscape,
+ * then the rotation has incompatible metrics; if the application did not specify
+ * a preference, then anything goes.
+ *
+ * @param orientation An orientation constant, such as
+ * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
+ * @param rotation The rotation to check.
+ * @return True if the rotation is compatible with the requested orientation.
*/
- public int getLockedRotationLw();
+ public boolean rotationHasCompatibleMetricsLw(int orientation, int rotation);
/**
* Called when the system is mostly done booting to determine whether
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 76b47ca..726bf4a 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -118,14 +118,13 @@ public abstract class WindowOrientationListener {
/**
* Gets the current orientation.
- * @param lastRotation
- * @return
+ * @return The current rotation, or -1 if unknown.
*/
- public int getCurrentRotation(int lastRotation) {
+ public int getCurrentRotation() {
if (mEnabled) {
- return mSensorEventListener.getCurrentRotation(lastRotation);
+ return mSensorEventListener.getCurrentRotation();
}
- return lastRotation;
+ return -1;
}
/**
@@ -342,8 +341,8 @@ public abstract class WindowOrientationListener {
mOrientationListener = orientationListener;
}
- public int getCurrentRotation(int lastRotation) {
- return mRotation != ROTATION_UNKNOWN ? mRotation : lastRotation;
+ public int getCurrentRotation() {
+ return mRotation; // may be -1, if unknown
}
@Override
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
index 01587aa..b06c112 100644
--- a/core/java/android/view/textservice/TextServicesManager.java
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -223,7 +223,7 @@ public final class TextServicesManager {
try {
sService.setSpellCheckerEnabled(enabled);
} catch (RemoteException e) {
- Log.e(TAG, "Error in setSpellCheckerSubtype:" + e);
+ Log.e(TAG, "Error in setSpellCheckerEnabled:" + e);
}
}
@@ -234,7 +234,7 @@ public final class TextServicesManager {
try {
return sService.isSpellCheckerEnabled();
} catch (RemoteException e) {
- Log.e(TAG, "Error in setSpellCheckerSubtype:" + e);
+ Log.e(TAG, "Error in isSpellCheckerEnabled:" + e);
return false;
}
}
diff --git a/core/java/android/webkit/CookieSyncManager.java b/core/java/android/webkit/CookieSyncManager.java
index 313f755..a699800 100644
--- a/core/java/android/webkit/CookieSyncManager.java
+++ b/core/java/android/webkit/CookieSyncManager.java
@@ -88,6 +88,10 @@ public final class CookieSyncManager extends WebSyncManager {
*/
public static synchronized CookieSyncManager createInstance(
Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("Invalid context argument");
+ }
+
JniUtil.setContext(context);
Context appContext = context.getApplicationContext();
if (sRef == null) {
diff --git a/core/java/android/webkit/JniUtil.java b/core/java/android/webkit/JniUtil.java
index ef1641d..7759ff3 100644
--- a/core/java/android/webkit/JniUtil.java
+++ b/core/java/android/webkit/JniUtil.java
@@ -39,25 +39,21 @@ class JniUtil {
private static Boolean sUseChromiumHttpStack;
private static Context sContext;
- private static boolean initialized = false;
-
private static void checkInitialized() {
- if (!initialized) {
+ if (sContext == null) {
throw new IllegalStateException("Call CookieSyncManager::createInstance() or create a webview before using this class");
}
}
protected static synchronized void setContext(Context context) {
- if (initialized)
+ if (sContext != null) {
return;
+ }
sContext = context.getApplicationContext();
- initialized = true;
}
protected static synchronized Context getContext() {
- if (!initialized)
- return null;
return sContext;
}
@@ -68,8 +64,9 @@ class JniUtil {
private static synchronized String getDatabaseDirectory() {
checkInitialized();
- if (sDatabaseDirectory == null)
+ if (sDatabaseDirectory == null) {
sDatabaseDirectory = sContext.getDatabasePath("dummy").getParent();
+ }
return sDatabaseDirectory;
}
@@ -81,8 +78,9 @@ class JniUtil {
private static synchronized String getCacheDirectory() {
checkInitialized();
- if (sCacheDirectory == null)
+ if (sCacheDirectory == null) {
sCacheDirectory = sContext.getCacheDir().getAbsolutePath();
+ }
return sCacheDirectory;
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 600c899..47629c4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -644,7 +644,7 @@ public class WebView extends AbsoluteLayout
private Drawable mSelectHandleLeft;
private Drawable mSelectHandleRight;
- static final boolean USE_WEBKIT_RINGS = true;
+ static final boolean USE_WEBKIT_RINGS = false;
// the color used to highlight the touch rectangles
private static final int HIGHLIGHT_COLOR = 0x6633b5e5;
// the round corner for the highlight path
@@ -730,6 +730,7 @@ public class WebView extends AbsoluteLayout
static final int SELECT_AT = 135;
static final int SCREEN_ON = 136;
static final int ENTER_FULLSCREEN_VIDEO = 137;
+ static final int UPDATE_SELECTION = 138;
private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
private static final int LAST_PACKAGE_MSG_ID = SET_TOUCH_HIGHLIGHT_RECTS;
@@ -1054,6 +1055,10 @@ public class WebView extends AbsoluteLayout
super(context, attrs, defStyle);
checkThread();
+ if (context == null) {
+ throw new IllegalArgumentException("Invalid context argument");
+ }
+
// Used by the chrome stack to find application paths
JniUtil.setContext(context);
@@ -4062,8 +4067,11 @@ public class WebView extends AbsoluteLayout
// state.
// If mNativeClass is 0, we should not reach here, so we do not
// need to check it again.
+ boolean pressed = (mTouchMode == TOUCH_SHORTPRESS_START_MODE
+ || mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_SHORTPRESS_MODE);
nativeRecordButtons(hasFocus() && hasWindowFocus(),
- (mTouchMode == TOUCH_SHORTPRESS_START_MODE && !USE_WEBKIT_RINGS)
+ (pressed && !USE_WEBKIT_RINGS)
|| mTrackballDown || mGotCenterDown, false);
drawCoreAndCursorRing(canvas, mBackgroundColor,
mDrawCursorRing && drawRings);
@@ -4280,7 +4288,6 @@ public class WebView extends AbsoluteLayout
}
nativeSetExtendSelection();
mDrawSelectionPointer = false;
- mSelectionStarted = true;
mTouchMode = TOUCH_DRAG_MODE;
return true;
}
@@ -6532,6 +6539,8 @@ public class WebView extends AbsoluteLayout
mLastTouchTime = eventTime;
mVelocityTracker = VelocityTracker.obtain();
mSnapScrollMode = SNAP_NONE;
+ mPrivateHandler.sendEmptyMessageDelayed(UPDATE_SELECTION,
+ ViewConfiguration.getTapTimeout());
}
private void startDrag() {
@@ -7161,6 +7170,14 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Return the overview scale of the WebView
+ * @return The overview scale.
+ */
+ float getZoomOverviewScale() {
+ return mZoomManager.getZoomOverviewScale();
+ }
+
+ /**
* @return TRUE if the WebView can be zoomed in.
*/
public boolean canZoomIn() {
@@ -7194,10 +7211,15 @@ public class WebView extends AbsoluteLayout
return mZoomManager.zoomOut();
}
+ /**
+ * This selects the best clickable target at mLastTouchX and mLastTouchY
+ * and calls showCursorTimed on the native side
+ */
private void updateSelection() {
if (mNativeClass == 0) {
return;
}
+ mPrivateHandler.removeMessages(UPDATE_SELECTION);
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContentX(mLastTouchX + mScrollX);
int contentY = viewToContentY(mLastTouchY + mScrollY);
@@ -7297,6 +7319,7 @@ public class WebView extends AbsoluteLayout
return;
}
mTouchMode = TOUCH_DONE_MODE;
+ updateSelection();
switchOutDrawHistory();
// mLastTouchX and mLastTouchY are the point in the current viewport
int contentX = viewToContentX(mLastTouchX + mScrollX);
@@ -8187,6 +8210,14 @@ public class WebView extends AbsoluteLayout
SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
break;
}
+ case UPDATE_SELECTION: {
+ if (mTouchMode == TOUCH_INIT_MODE
+ || mTouchMode == TOUCH_SHORTPRESS_MODE
+ || mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
+ updateSelection();
+ }
+ break;
+ }
case SWITCH_TO_SHORTPRESS: {
mInitialHitTestResult = null; // set by updateSelection()
if (mTouchMode == TOUCH_INIT_MODE) {
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 48359d4..470e843 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2512,10 +2512,13 @@ public final class WebViewCore {
// called by JNI
private void restoreScale(float scale, float textWrapScale) {
if (mBrowserFrame.firstLayoutDone() == false) {
- final float defaultScale = mWebView.getDefaultZoomScale();
- mRestoredScale = (scale <= 0.0) ? defaultScale : scale;
+ // If restored scale and textWrapScale are 0, set them to
+ // overview and reading level scale respectively.
+ mRestoredScale = (scale <= 0.0)
+ ? mWebView.getZoomOverviewScale() : scale;
if (mSettings.getUseWideViewPort()) {
- mRestoredTextWrapScale = (textWrapScale <= 0.0) ? defaultScale : textWrapScale;
+ mRestoredTextWrapScale = (textWrapScale <= 0.0)
+ ? mWebView.getReadingLevelScale() : textWrapScale;
}
}
}
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 7ca6aeb..7f526e7 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -1128,12 +1128,6 @@ class ZoomManager {
mTextWrapScale = Math.max(mTextWrapScale, overviewScale);
}
reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
- } else {
- // In case of restored scale, treat defaultScale as overview since
- // it usually means the previous scale is not saved.
- if (scale == mDefaultScale && settings.getLoadWithOverviewMode()) {
- scale = overviewScale;
- }
}
mInitialZoomOverview = settings.getLoadWithOverviewMode() &&
!exceedsMinScaleIncrement(scale, overviewScale);
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 312303d..c6e63c3 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -16,6 +16,8 @@
package android.widget;
+import com.android.internal.R;
+
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -23,19 +25,16 @@ import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
-import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.ActionProvider;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
-import com.android.internal.R;
-
/**
* This class is a view for choosing an activity for handling a given {@link Intent}.
* <p>
@@ -107,6 +106,11 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
private final int mListPopupMaxWidth;
/**
+ * The ActionProvider hosting this view, if applicable.
+ */
+ ActionProvider mProvider;
+
+ /**
* Observer for the model data.
*/
private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
@@ -131,6 +135,9 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
getListPopupWindow().dismiss();
} else {
getListPopupWindow().show();
+ if (mProvider != null) {
+ mProvider.subUiVisibilityChanged(true);
+ }
}
}
}
@@ -262,6 +269,14 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
}
/**
+ * Set the provider hosting this view, if applicable.
+ * @hide Internal use only
+ */
+ public void setProvider(ActionProvider provider) {
+ mProvider = provider;
+ }
+
+ /**
* Shows the popup window with activities.
*
* @return True if the popup was shown, false if already showing.
@@ -289,9 +304,13 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
mAdapter.setMaxActivityCount(maxActivityCount);
+ final boolean defaultActivityButtonShown =
+ mDefaultActivityButton.getVisibility() == VISIBLE;
+
final int activityCount = mAdapter.getActivityCount();
+ final int maxActivityCountOffset = defaultActivityButtonShown ? 1 : 0;
if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED
- && activityCount > maxActivityCount + 1) {
+ && activityCount > maxActivityCount + maxActivityCountOffset) {
mAdapter.setShowFooterView(true);
} else {
mAdapter.setShowFooterView(false);
@@ -299,14 +318,17 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
ListPopupWindow popupWindow = getListPopupWindow();
if (!popupWindow.isShowing()) {
- if (mIsSelectingDefaultActivity) {
- mAdapter.setShowDefaultActivity(true);
+ if (mIsSelectingDefaultActivity || !defaultActivityButtonShown) {
+ mAdapter.setShowDefaultActivity(true, defaultActivityButtonShown);
} else {
- mAdapter.setShowDefaultActivity(false);
+ mAdapter.setShowDefaultActivity(false, false);
}
final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth);
popupWindow.setContentWidth(contentWidth);
popupWindow.show();
+ if (mProvider != null) {
+ mProvider.subUiVisibilityChanged(true);
+ }
}
}
@@ -476,8 +498,10 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
mAdapter.getDataModel().setDefaultActivity(position);
}
} else {
- // The first item in the model is default action => adjust index
- Intent launchIntent = mAdapter.getDataModel().chooseActivity(position + 1);
+ // If the default target is not shown in the list, the first
+ // item in the model is default action => adjust index
+ position = mAdapter.getShowDefaultActivity() ? position : position + 1;
+ Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
if (launchIntent != null) {
mContext.startActivity(launchIntent);
}
@@ -523,6 +547,9 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
// PopUpWindow.OnDismissListener#onDismiss
public void onDismiss() {
notifyOnDismissListener();
+ if (mProvider != null) {
+ mProvider.subUiVisibilityChanged(false);
+ }
}
private void notifyOnDismissListener() {
@@ -553,6 +580,8 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
private boolean mShowDefaultActivity;
+ private boolean mHighlightDefaultActivity;
+
private boolean mShowFooterView;
public void setDataModel(ActivityChooserModel dataModel) {
@@ -640,7 +669,7 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
TextView titleView = (TextView) convertView.findViewById(R.id.title);
titleView.setText(activity.loadLabel(packageManager));
// Highlight the default.
- if (mShowDefaultActivity && position == 0) {
+ if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
convertView.setActivated(true);
} else {
convertView.setActivated(false);
@@ -709,11 +738,18 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
return mDataModel;
}
- public void setShowDefaultActivity(boolean showDefaultActivity) {
- if (mShowDefaultActivity != showDefaultActivity) {
+ public void setShowDefaultActivity(boolean showDefaultActivity,
+ boolean highlightDefaultActivity) {
+ if (mShowDefaultActivity != showDefaultActivity
+ || mHighlightDefaultActivity != highlightDefaultActivity) {
mShowDefaultActivity = showDefaultActivity;
+ mHighlightDefaultActivity = highlightDefaultActivity;
notifyDataSetChanged();
}
}
+
+ public boolean getShowDefaultActivity() {
+ return mShowDefaultActivity;
+ }
}
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 72db8e8..5392c2e 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -277,10 +277,11 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
* called, false otherwise is returned.
*/
public boolean performItemClick(View view, int position, long id) {
- view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
-
if (mOnItemClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
+ if (view != null) {
+ view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+ }
mOnItemClickListener.onItemClick(this, view, position, id);
return true;
}
@@ -338,8 +339,10 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
*/
public interface OnItemSelectedListener {
/**
- * Callback method to be invoked when an item in this view has been
- * selected.
+ * <p>Callback method to be invoked when an item in this view has been
+ * selected. This callback is invoked only when the newly selected
+ * position is different from the previously selected position or if
+ * there was no selected item.</p>
*
* Impelmenters can call getItemAtPosition(position) if they need to access the
* data associated with the selected item.
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 27610b9..07523e3 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
@@ -38,6 +36,8 @@ import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
+import com.android.internal.R;
+
/**
* <p>An editable text view that shows completion suggestions automatically
@@ -744,7 +744,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
if (mFilter != null) {
mPopupCanBeUpdated = true;
performFiltering(getText(), mLastKeyCode);
- buildImeCompletions();
}
} else {
// drop down is automatically dismissed when enough characters
@@ -837,10 +836,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
@Override
public void onCommitCompletion(CompletionInfo completion) {
if (isPopupShowing()) {
- mBlockCompletion = true;
- replaceText(completion.getText());
- mBlockCompletion = false;
-
mPopup.performItemClick(completion.getPosition());
}
}
@@ -938,7 +933,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
*/
final boolean dropDownAlwaysVisible = mPopup.isDropDownAlwaysVisible();
- if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter()) {
+ final boolean enoughToFilter = enoughToFilter();
+ if ((count > 0 || dropDownAlwaysVisible) && enoughToFilter) {
if (hasFocus() && hasWindowFocus() && mPopupCanBeUpdated) {
showDropDown();
}
@@ -1049,6 +1045,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
* <p>Displays the drop down on screen.</p>
*/
public void showDropDown() {
+ buildImeCompletions();
+
if (mPopup.getAnchorView() == null) {
if (mDropDownAnchorId != View.NO_ID) {
mPopup.setAnchorView(getRootView().findViewById(mDropDownAnchorId));
@@ -1064,7 +1062,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
mPopup.show();
mPopup.getListView().setOverScrollMode(View.OVER_SCROLL_ALWAYS);
}
-
+
/**
* Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is
* false, we allow outside touch to dismiss the dropdown. If this is set to true, then we
@@ -1075,7 +1073,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) {
mPopup.setForceIgnoreOutsideTouch(forceIgnoreOutsideTouch);
}
-
+
private void buildImeCompletions() {
final ListAdapter adapter = mAdapter;
if (adapter != null) {
@@ -1090,8 +1088,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
realCount++;
Object item = adapter.getItem(i);
long id = adapter.getItemId(i);
- completions[i] = new CompletionInfo(id, i,
- convertSelectionToString(item));
+ completions[i] = new CompletionInfo(id, i, convertSelectionToString(item));
}
}
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 1b713c3..9cbe8db 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -339,10 +339,8 @@ public class CalendarView extends FrameLayout {
// initialization based on locale
setCurrentLocale(Locale.getDefault());
- TypedValue calendarViewStyle = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.calendarViewStyle, calendarViewStyle, true);
- TypedArray attributesArray = context.obtainStyledAttributes(calendarViewStyle.resourceId,
- R.styleable.CalendarView);
+ TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.CalendarView,
+ R.attr.calendarViewStyle, 0);
mShowWeekNumber = attributesArray.getBoolean(R.styleable.CalendarView_showWeekNumber,
DEFAULT_SHOW_WEEK_NUMBER);
mFirstDayOfWeek = attributesArray.getInt(R.styleable.CalendarView_firstDayOfWeek,
@@ -355,6 +353,9 @@ public class CalendarView extends FrameLayout {
if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, mMaxDate)) {
parseDate(DEFAULT_MAX_DATE, mMaxDate);
}
+ if (mMaxDate.before(mMinDate)) {
+ throw new IllegalArgumentException("Max date cannot be before min date.");
+ }
mShownWeekCount = attributesArray.getInt(R.styleable.CalendarView_shownWeekCount,
DEFAULT_SHOWN_WEEK_COUNT);
mSelectedWeekBackgroundColor = attributesArray.getColor(
@@ -407,9 +408,16 @@ public class CalendarView extends FrameLayout {
setUpListView();
setUpAdapter();
- // go to today now
+ // go to today or whichever is close to today min or max date
mTempDate.setTimeInMillis(System.currentTimeMillis());
- goTo(mTempDate, false, true, true);
+ if (mTempDate.before(mMinDate)) {
+ goTo(mMinDate, false, true, true);
+ } else if (mMaxDate.before(mTempDate)) {
+ goTo(mMaxDate, false, true, true);
+ } else {
+ goTo(mTempDate, false, true, true);
+ }
+
invalidate();
}
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 390002b..ba69288 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -87,19 +87,26 @@ import static java.lang.Math.min;
* layout parameters. When the
* {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins}
* property is set, default margins around children are automatically
- * allocated based on the child's visual characteristics. Each of the
- * margins so defined may be independently overridden by an assignment
+ * allocated based on the prevailing UI style guide for the platform.
+ * Each of the margins so defined may be independently overridden by an assignment
* to the appropriate layout parameter.
+ * Default values will generally produce a reasonable spacing between components
+ * but values may change between different releases of the platform.
*
* <h4>Excess Space Distribution</h4>
*
+ * GridLayout's distribution of excess space is based on <em>priority</em>
+ * rather than <em>weight</em>.
+ * <p>
* A child's ability to stretch is inferred from the alignment properties of
* its row and column groups (which are typically set by setting the
* {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters).
* If alignment was defined along a given axis then the component
- * is taken as flexible in along that axis. If no alignment was set,
- * the component is instead assumed to be inflexible. Multiple components in
- * the same row or column group are considered to act in <em>parallel</em>. Such a
+ * is taken as <em>flexible</em> in that direction. If no alignment was set,
+ * the component is instead assumed to be <em>inflexible</em>.
+ * <p>
+ * Multiple components in the same row or column group are
+ * considered to act in <em>parallel</em>. Such a
* group is flexible only if <em>all</em> of the components
* within it are flexible. Row and column groups that sit either side of a common boundary
* are instead considered to act in <em>series</em>. The composite group made of these two
@@ -109,6 +116,23 @@ import static java.lang.Math.min;
* gravity. To prevent a column from stretching, ensure that one of the components
* in the column does not define a gravity.
* <p>
+ * When the principle of flexibility does not provide complete disambiguation,
+ * GridLayout's algorithms favour rows and columns that are closer to its <em>right</em>
+ * and <em>bottom</em> edges.
+ *
+ * <h5>Limitations</h5>
+ *
+ * GridLayout does not provide support for the principle of <em>weight</em>, as defined in
+ * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible
+ * to configure a GridLayout to distribute excess space in non-trivial proportions between
+ * multiple rows or columns.
+ * <p>
+ * Some common use-cases may nevertheless be accommodated as follows.
+ * To place equal amounts of space around a component in a cell group;
+ * use {@link #CENTER} alignment (or {@link LayoutParams#setGravity(int) gravity}).
+ * For complete control over excess space distribution in a row or column;
+ * use a {@link LinearLayout} subview to hold the components in the associated cell group.
+ * When using either of these techniques, bear in mind that cell groups may be defined to overlap.
* <p>
* See {@link GridLayout.LayoutParams} for a full description of the
* layout parameters used by GridLayout.
@@ -180,9 +204,11 @@ public class GridLayout extends ViewGroup {
// Misc constants
- private static final String TAG = GridLayout.class.getName();
- private static boolean DEBUG = false;
- private static final int PRF = 1;
+ static final String TAG = GridLayout.class.getName();
+ static final boolean DEBUG = false;
+ static final int PRF = 1;
+ static final int MAX_SIZE = 100000;
+ static final int DEFAULT_CONTAINER_MARGIN = 0;
// Defaults
@@ -191,8 +217,6 @@ public class GridLayout extends ViewGroup {
private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
private static final boolean DEFAULT_ORDER_PRESERVED = true;
private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
- private static final int DEFAULT_CONTAINER_MARGIN = 0;
- private static final int MAX_SIZE = 100000;
// TypedArray indices
@@ -206,13 +230,13 @@ public class GridLayout extends ViewGroup {
// Instance variables
- private final Axis mHorizontalAxis = new Axis(true);
- private final Axis mVerticalAxis = new Axis(false);
- private boolean mLayoutParamsValid = false;
- private int mOrientation = DEFAULT_ORIENTATION;
- private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
- private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
- private int mDefaultGap;
+ final Axis horizontalAxis = new Axis(true);
+ final Axis verticalAxis = new Axis(false);
+ boolean layoutParamsValid = false;
+ int orientation = DEFAULT_ORIENTATION;
+ boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
+ int alignmentMode = DEFAULT_ALIGNMENT_MODE;
+ int defaultGap;
// Constructors
@@ -224,7 +248,7 @@ public class GridLayout extends ViewGroup {
if (DEBUG) {
setWillNotDraw(false);
}
- mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
+ defaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
try {
setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
@@ -266,13 +290,12 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_orientation
*/
public int getOrientation() {
- return mOrientation;
+ return orientation;
}
/**
- * The orientation property does not affect layout. Orientation is used
- * only to generate default row/column indices when they are not specified
- * by a component's layout parameters.
+ * Orientation is used only to generate default row/column indices when
+ * they are not specified by a component's layout parameters.
* <p>
* The default value of this property is {@link #HORIZONTAL}.
*
@@ -283,8 +306,9 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_orientation
*/
public void setOrientation(int orientation) {
- if (mOrientation != orientation) {
- mOrientation = orientation;
+ if (this.orientation != orientation) {
+ this.orientation = orientation;
+ invalidateStructure();
requestLayout();
}
}
@@ -302,13 +326,12 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_rowCount
*/
public int getRowCount() {
- return mVerticalAxis.getCount();
+ return verticalAxis.getCount();
}
/**
- * The rowCount property does not affect layout. RowCount is used
- * only to generate default row/column indices when they are not specified
- * by a component's layout parameters.
+ * RowCount is used only to generate default row/column indices when
+ * they are not specified by a component's layout parameters.
*
* @param rowCount the number of rows
*
@@ -318,7 +341,9 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_rowCount
*/
public void setRowCount(int rowCount) {
- mVerticalAxis.setCount(rowCount);
+ verticalAxis.setCount(rowCount);
+ invalidateStructure();
+ requestLayout();
}
/**
@@ -334,13 +359,12 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_columnCount
*/
public int getColumnCount() {
- return mHorizontalAxis.getCount();
+ return horizontalAxis.getCount();
}
/**
- * The columnCount property does not affect layout. ColumnCount is used
- * only to generate default column/column indices when they are not specified
- * by a component's layout parameters.
+ * ColumnCount is used only to generate default column/column indices when
+ * they are not specified by a component's layout parameters.
*
* @param columnCount the number of columns.
*
@@ -350,7 +374,9 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_columnCount
*/
public void setColumnCount(int columnCount) {
- mHorizontalAxis.setCount(columnCount);
+ horizontalAxis.setCount(columnCount);
+ invalidateStructure();
+ requestLayout();
}
/**
@@ -364,7 +390,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_useDefaultMargins
*/
public boolean getUseDefaultMargins() {
- return mUseDefaultMargins;
+ return useDefaultMargins;
}
/**
@@ -394,7 +420,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_useDefaultMargins
*/
public void setUseDefaultMargins(boolean useDefaultMargins) {
- mUseDefaultMargins = useDefaultMargins;
+ this.useDefaultMargins = useDefaultMargins;
requestLayout();
}
@@ -411,7 +437,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_alignmentMode
*/
public int getAlignmentMode() {
- return mAlignmentMode;
+ return alignmentMode;
}
/**
@@ -430,7 +456,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_alignmentMode
*/
public void setAlignmentMode(int alignmentMode) {
- mAlignmentMode = alignmentMode;
+ this.alignmentMode = alignmentMode;
requestLayout();
}
@@ -445,7 +471,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_rowOrderPreserved
*/
public boolean isRowOrderPreserved() {
- return mVerticalAxis.isOrderPreserved();
+ return verticalAxis.isOrderPreserved();
}
/**
@@ -465,7 +491,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_rowOrderPreserved
*/
public void setRowOrderPreserved(boolean rowOrderPreserved) {
- mVerticalAxis.setOrderPreserved(rowOrderPreserved);
+ verticalAxis.setOrderPreserved(rowOrderPreserved);
invalidateStructure();
requestLayout();
}
@@ -481,7 +507,7 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_columnOrderPreserved
*/
public boolean isColumnOrderPreserved() {
- return mHorizontalAxis.isOrderPreserved();
+ return horizontalAxis.isOrderPreserved();
}
/**
@@ -501,14 +527,14 @@ public class GridLayout extends ViewGroup {
* @attr ref android.R.styleable#GridLayout_columnOrderPreserved
*/
public void setColumnOrderPreserved(boolean columnOrderPreserved) {
- mHorizontalAxis.setOrderPreserved(columnOrderPreserved);
+ horizontalAxis.setOrderPreserved(columnOrderPreserved);
invalidateStructure();
requestLayout();
}
// Static utility methods
- private static int max2(int[] a, int valueIfEmpty) {
+ static int max2(int[] a, int valueIfEmpty) {
int result = valueIfEmpty;
for (int i = 0, N = a.length; i < N; i++) {
result = Math.max(result, a[i]);
@@ -517,14 +543,14 @@ public class GridLayout extends ViewGroup {
}
@SuppressWarnings("unchecked")
- private static <T> T[] append(T[] a, T[] b) {
+ static <T> T[] append(T[] a, T[] b) {
T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
- private static Alignment getAlignment(int gravity, boolean horizontal) {
+ static Alignment getAlignment(int gravity, boolean horizontal) {
int mask = horizontal ? HORIZONTAL_GRAVITY_MASK : VERTICAL_GRAVITY_MASK;
int shift = horizontal ? AXIS_X_SHIFT : AXIS_Y_SHIFT;
int flags = (gravity & mask) >> shift;
@@ -547,7 +573,7 @@ public class GridLayout extends ViewGroup {
if (c.getClass() == Space.class) {
return 0;
}
- return mDefaultGap / 2;
+ return defaultGap / 2;
}
private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
@@ -555,18 +581,18 @@ public class GridLayout extends ViewGroup {
}
private int getDefaultMarginValue(View c, LayoutParams p, boolean horizontal, boolean leading) {
- if (!mUseDefaultMargins) {
+ if (!useDefaultMargins) {
return 0;
}
Spec spec = horizontal ? p.columnSpec : p.rowSpec;
- Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
+ Axis axis = horizontal ? horizontalAxis : verticalAxis;
Interval span = spec.span;
boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
return getDefaultMargin(c, isAtEdge, horizontal, leading);
}
- private int getMargin1(View view, boolean horizontal, boolean leading) {
+ int getMargin1(View view, boolean horizontal, boolean leading) {
LayoutParams lp = getLayoutParams(view);
int margin = horizontal ?
(leading ? lp.leftMargin : lp.rightMargin) :
@@ -575,10 +601,10 @@ public class GridLayout extends ViewGroup {
}
private int getMargin(View view, boolean horizontal, boolean leading) {
- if (mAlignmentMode == ALIGN_MARGINS) {
+ if (alignmentMode == ALIGN_MARGINS) {
return getMargin1(view, horizontal, leading);
} else {
- Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
+ Axis axis = horizontal ? horizontalAxis : verticalAxis;
int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
LayoutParams lp = getLayoutParams(view);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
@@ -591,10 +617,6 @@ public class GridLayout extends ViewGroup {
return getMargin(child, horizontal, true) + getMargin(child, horizontal, false);
}
- private static int valueIfDefined(int value, int defaultValue) {
- return (value != UNDEFINED) ? value : defaultValue;
- }
-
private static boolean fits(int[] a, int value, int start, int end) {
if (end > a.length) {
return false;
@@ -629,9 +651,9 @@ public class GridLayout extends ViewGroup {
// install default indices for cells that don't define them
private void validateLayoutParams() {
- final boolean horizontal = (mOrientation == HORIZONTAL);
- final int axisCount = horizontal ? mHorizontalAxis.count : mVerticalAxis.count;
- final int count = valueIfDefined(axisCount, 0);
+ final boolean horizontal = (orientation == HORIZONTAL);
+ final Axis axis = horizontal ? horizontalAxis : verticalAxis;
+ final int count = (axis.definedCount != UNDEFINED) ? axis.definedCount : 0;
int major = 0;
int minor = 0;
@@ -640,15 +662,17 @@ public class GridLayout extends ViewGroup {
for (int i = 0, N = getChildCount(); i < N; i++) {
LayoutParams lp = getLayoutParams1(getChildAt(i));
- final Interval majorRange = (horizontal ? lp.rowSpec : lp.columnSpec).span;
- final boolean majorWasDefined = (majorRange.min != UNDEFINED);
+ final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec;
+ final Interval majorRange = majorSpec.span;
+ final boolean majorWasDefined = majorSpec.startDefined;
final int majorSpan = majorRange.size();
if (majorWasDefined) {
major = majorRange.min;
}
- final Interval minorRange = (horizontal ? lp.columnSpec : lp.rowSpec).span;
- final boolean minorWasDefined = (minorRange.min != UNDEFINED);
+ final Spec minorSpec = horizontal ? lp.columnSpec : lp.rowSpec;
+ final Interval minorRange = minorSpec.span;
+ final boolean minorWasDefined = minorSpec.startDefined;
final int minorSpan = clip(minorRange, minorWasDefined, count);
if (minorWasDefined) {
minor = minorRange.min;
@@ -685,9 +709,9 @@ public class GridLayout extends ViewGroup {
}
private void invalidateStructure() {
- mLayoutParamsValid = false;
- mHorizontalAxis.invalidateStructure();
- mVerticalAxis.invalidateStructure();
+ layoutParamsValid = false;
+ horizontalAxis.invalidateStructure();
+ verticalAxis.invalidateStructure();
// This can end up being done twice. Better twice than not at all.
invalidateValues();
}
@@ -695,9 +719,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 (mHorizontalAxis != null && mVerticalAxis != null) {
- mHorizontalAxis.invalidateValues();
- mVerticalAxis.invalidateValues();
+ if (horizontalAxis != null && verticalAxis != null) {
+ horizontalAxis.invalidateValues();
+ verticalAxis.invalidateValues();
}
}
@@ -705,10 +729,10 @@ public class GridLayout extends ViewGroup {
return (LayoutParams) c.getLayoutParams();
}
- private LayoutParams getLayoutParams(View c) {
- if (!mLayoutParamsValid) {
+ final LayoutParams getLayoutParams(View c) {
+ if (!layoutParamsValid) {
validateLayoutParams();
- mLayoutParamsValid = true;
+ layoutParamsValid = true;
}
return getLayoutParams1(c);
}
@@ -752,7 +776,7 @@ public class GridLayout extends ViewGroup {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.argb(50, 255, 255, 255));
- int[] xs = mHorizontalAxis.locations;
+ int[] xs = horizontalAxis.locations;
if (xs != null) {
for (int i = 0, length = xs.length; i < length; i++) {
int x = xs[i];
@@ -760,7 +784,7 @@ public class GridLayout extends ViewGroup {
}
}
- int[] ys = mVerticalAxis.locations;
+ int[] ys = verticalAxis.locations;
if (ys != null) {
for (int i = 0, length = ys.length; i < length; i++) {
int y = ys[i];
@@ -822,7 +846,7 @@ public class GridLayout extends ViewGroup {
// Measurement
- private boolean isGone(View c) {
+ final boolean isGone(View c) {
return c.getVisibility() == View.GONE;
}
@@ -847,8 +871,8 @@ public class GridLayout extends ViewGroup {
protected void onMeasure(int widthSpec, int heightSpec) {
measureChildrenWithMargins(widthSpec, heightSpec);
- int width = getPaddingLeft() + mHorizontalAxis.getMeasure(widthSpec) + getPaddingRight();
- int height = getPaddingTop() + mVerticalAxis.getMeasure(heightSpec) + getPaddingBottom();
+ int width = getPaddingLeft() + horizontalAxis.getMeasure(widthSpec) + getPaddingRight();
+ int height = getPaddingTop() + verticalAxis.getMeasure(heightSpec) + getPaddingBottom();
int measuredWidth = Math.max(width, getSuggestedMinimumWidth());
int measuredHeight = Math.max(height, getSuggestedMinimumHeight());
@@ -866,7 +890,7 @@ public class GridLayout extends ViewGroup {
return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
}
- private int getMeasurementIncludingMargin(View c, boolean horizontal) {
+ final int getMeasurementIncludingMargin(View c, boolean horizontal) {
if (isGone(c)) {
return 0;
}
@@ -879,7 +903,7 @@ public class GridLayout extends ViewGroup {
invalidateValues();
}
- private Alignment getAlignment(Alignment alignment, boolean horizontal) {
+ final Alignment getAlignment(Alignment alignment, boolean horizontal) {
return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
(horizontal ? LEFT : BASELINE);
}
@@ -908,11 +932,11 @@ public class GridLayout extends ViewGroup {
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
- mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
- mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
+ horizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
+ verticalAxis.layout(targetHeight - paddingTop - paddingBottom);
- int[] hLocations = mHorizontalAxis.getLocations();
- int[] vLocations = mVerticalAxis.getLocations();
+ int[] hLocations = horizontalAxis.getLocations();
+ int[] vLocations = verticalAxis.getLocations();
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
@@ -941,8 +965,8 @@ public class GridLayout extends ViewGroup {
int dx, dy;
- Bounds colBounds = mHorizontalAxis.getGroupBounds().getValue(i);
- Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i);
+ Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i);
+ Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i);
// Gravity offsets: the location of the alignment group relative to its cell group.
//noinspection NullableProblems
@@ -990,7 +1014,7 @@ public class GridLayout extends ViewGroup {
distinguished by the "horizontal" flag which is true for the horizontal axis and false
for the vertical one.
*/
- private class Axis {
+ final class Axis {
private static final int MIN_VALUE = -1000000;
private static final int NEW = 0;
@@ -999,9 +1023,8 @@ public class GridLayout extends ViewGroup {
public final boolean horizontal;
- public int count = UNDEFINED;
- public boolean countValid = false;
- public boolean countWasExplicitySet = false;
+ public int definedCount = UNDEFINED;
+ private int inferredCount = UNDEFINED;
PackedMap<Spec, Bounds> groupBounds;
public boolean groupBoundsValid = false;
@@ -1024,7 +1047,7 @@ public class GridLayout extends ViewGroup {
public int[] locations;
public boolean locationsValid = false;
- private boolean mOrderPreserved = DEFAULT_ORDER_PRESERVED;
+ boolean orderPreserved = DEFAULT_ORDER_PRESERVED;
private MutableInt parentMin = new MutableInt(0);
private MutableInt parentMax = new MutableInt(-MAX_SIZE);
@@ -1046,25 +1069,27 @@ public class GridLayout extends ViewGroup {
return count == -1 ? UNDEFINED : count;
}
- public int getCount() {
- if (!countValid) {
- count = max(0, maxIndex()); // if there are no cells, the count is zero
- countValid = true;
+ private int getInferredCount() {
+ if (inferredCount == UNDEFINED) {
+ inferredCount = max(0, maxIndex()); // if there are no cells, actual count is zero
}
- return count;
+ return inferredCount;
+ }
+
+ public int getCount() {
+ return max(definedCount, getInferredCount());
}
public void setCount(int count) {
- this.count = count;
- this.countWasExplicitySet = count != UNDEFINED;
+ this.definedCount = count;
}
public boolean isOrderPreserved() {
- return mOrderPreserved;
+ return orderPreserved;
}
public void setOrderPreserved(boolean orderPreserved) {
- mOrderPreserved = orderPreserved;
+ this.orderPreserved = orderPreserved;
invalidateStructure();
}
@@ -1093,7 +1118,7 @@ public class GridLayout extends ViewGroup {
}
}
- private PackedMap<Spec, Bounds> getGroupBounds() {
+ public PackedMap<Spec, Bounds> getGroupBounds() {
if (groupBounds == null) {
groupBounds = createGroupBounds();
}
@@ -1183,7 +1208,7 @@ public class GridLayout extends ViewGroup {
// Group arcs by their first vertex, returning an array of arrays.
// This is linear in the number of arcs.
- private Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
+ Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
int N = getCount() + 1; // the number of vertices
Arc[][] result = new Arc[N][];
int[] sizes = new int[N];
@@ -1262,7 +1287,7 @@ public class GridLayout extends ViewGroup {
addComponentSizes(maxs, getBackwardLinks());
// Add ordering constraints to prevent row/col sizes from going negative
- if (mOrderPreserved) {
+ if (orderPreserved) {
// Add a constraint for every row/col
for (int i = 0; i < getCount(); i++) {
include(mins, new Interval(i, i + 1), new MutableInt(0));
@@ -1315,6 +1340,48 @@ public class GridLayout extends ViewGroup {
return false;
}
+ private void init(int[] locations) {
+ Arrays.fill(locations, MIN_VALUE);
+ locations[0] = 0;
+ }
+
+ private String arcsToString(List<Arc> arcs) {
+ String var = horizontal ? "c" : "r";
+ StringBuilder result = new StringBuilder();
+ boolean first = false;
+ for(Arc arc : arcs) {
+ if (!first) {
+ first = true;
+ } else {
+ result =result.append(", ");
+ }
+ int src = arc.span.min;
+ int dst = arc.span.max;
+ int value = arc.value.value;
+ result.append((src < dst) ?
+ var + dst + " - " + var + src + " > " + value :
+ var + src + " - " + var + dst + " < " + -value);
+
+ }
+ return result.toString();
+ }
+
+ private void logError(String axisName, Arc[] arcs, boolean[] culprits0) {
+ List<Arc> culprits = new ArrayList<Arc>();
+ List<Arc> removed = new ArrayList<Arc>();
+ for (int c = 0; c < arcs.length; c++) {
+ Arc arc = arcs[c];
+ if (culprits0[c]) {
+ culprits.add(arc);
+ }
+ if (!arc.valid) {
+ removed.add(arc);
+ }
+ }
+ Log.d(TAG, axisName + " constraints: " + arcsToString(culprits) + " are inconsistent; "
+ + "permanently removing: " + arcsToString(removed) + ". ");
+ }
+
/*
Bellman-Ford variant - modified to reduce typical running time from O(N^2) to O(N)
@@ -1350,51 +1417,54 @@ public class GridLayout extends ViewGroup {
completes in O(N) steps with very low constants.
*/
private void solve(Arc[] arcs, int[] locations) {
- String axis = horizontal ? "horizontal" : "vertical";
+ String axisName = horizontal ? "horizontal" : "vertical";
int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
+ boolean[] originalCulprits = null;
- // We take one extra pass over traditional Bellman-Ford (and omit their final step)
- for (int i = 0; i < N; i++) {
- boolean changed = false;
- for (int j = 0, length = arcs.length; j < length; j++) {
- changed |= relax(locations, arcs[j]);
- }
- if (!changed) {
- if (DEBUG) {
- Log.v(TAG, axis + " iteration completed in " + (1 + i) + " steps of " + N);
+ for (int p = 0; p < arcs.length; p++) {
+ init(locations);
+
+ // We take one extra pass over traditional Bellman-Ford (and omit their final step)
+ for (int i = 0; i < N; i++) {
+ boolean changed = false;
+ for (int j = 0, length = arcs.length; j < length; j++) {
+ changed |= relax(locations, arcs[j]);
+ }
+ if (!changed) {
+ if (originalCulprits != null) {
+ logError(axisName, arcs, originalCulprits);
+ }
+ if (DEBUG) {
+ Log.v(TAG, axisName + " iteration completed in " +
+ (1 + i) + " steps of " + N);
+ }
+ return;
}
- return;
}
- }
- Log.d(TAG, "The " + axis + " constraints contained a contradiction. Resolving... ");
- Log.d(TAG, Arrays.toString(arcs));
+ boolean[] culprits = new boolean[arcs.length];
+ for (int i = 0; i < N; i++) {
+ for (int j = 0, length = arcs.length; j < length; j++) {
+ culprits[j] |= relax(locations, arcs[j]);
+ }
+ }
- boolean[] culprits = new boolean[arcs.length];
- for (int i = 0; i < N; i++) {
- for (int j = 0, length = arcs.length; j < length; j++) {
- culprits[j] |= relax(locations, arcs[j]);
+ if (p == 0) {
+ originalCulprits = culprits;
}
- }
- for (int i = 0; i < culprits.length; i++) {
- if (culprits[i]) {
- Arc arc = arcs[i];
- // Only remove max values, min values alone cannot be inconsistent
- if (arc.span.min < arc.span.max) {
- continue;
+
+ for (int i = 0; i < arcs.length; i++) {
+ if (culprits[i]) {
+ Arc arc = arcs[i];
+ // Only remove max values, min values alone cannot be inconsistent
+ if (arc.span.min < arc.span.max) {
+ continue;
+ }
+ arc.valid = false;
+ break;
}
- Log.d(TAG, "Removing: " + arc);
- arc.valid = false;
- break;
}
}
- solve1(arcs, locations);
- }
-
- private void solve1(Arc[] arcs, int[] a) {
- Arrays.fill(a, MIN_VALUE);
- a[0] = 0;
- solve(arcs, a);
}
private void computeMargins(boolean leading) {
@@ -1410,7 +1480,9 @@ public class GridLayout extends ViewGroup {
}
}
- private int[] getLeadingMargins() {
+ // External entry points
+
+ public int[] getLeadingMargins() {
if (leadingMargins == null) {
leadingMargins = new int[getCount() + 1];
}
@@ -1421,7 +1493,7 @@ public class GridLayout extends ViewGroup {
return leadingMargins;
}
- private int[] getTrailingMargins() {
+ public int[] getTrailingMargins() {
if (trailingMargins == null) {
trailingMargins = new int[getCount() + 1];
}
@@ -1433,10 +1505,10 @@ public class GridLayout extends ViewGroup {
}
private void computeLocations(int[] a) {
- solve1(getArcs(), a);
+ solve(getArcs(), a);
}
- private int[] getLocations() {
+ public int[] getLocations() {
if (locations == null) {
int N = getCount() + 1;
locations = new int[N];
@@ -1448,8 +1520,6 @@ public class GridLayout extends ViewGroup {
return locations;
}
- // External entry points
-
private int size(int[] locations) {
return max2(locations, 0) - locations[0];
}
@@ -1465,7 +1535,7 @@ public class GridLayout extends ViewGroup {
return size(getLocations());
}
- private int getMeasure(int measureSpec) {
+ public int getMeasure(int measureSpec) {
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
@@ -1485,13 +1555,13 @@ public class GridLayout extends ViewGroup {
}
}
- private void layout(int size) {
+ public void layout(int size) {
setParentConstraints(size, size);
getLocations();
}
- private void invalidateStructure() {
- countValid = false;
+ public void invalidateStructure() {
+ inferredCount = UNDEFINED;
groupBounds = null;
forwardLinks = null;
@@ -1506,7 +1576,7 @@ public class GridLayout extends ViewGroup {
invalidateValues();
}
- private void invalidateValues() {
+ public void invalidateValues() {
groupBoundsValid = false;
forwardLinksValid = false;
backwardLinksValid = false;
@@ -1536,9 +1606,22 @@ public class GridLayout extends ViewGroup {
* both aspects of alignment within the cell group. It is also possible to specify a child's
* alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
* method.
- * <p>
- * See {@link GridLayout} for a description of the conventions used by GridLayout
- * in reference to grid indices.
+ *
+ * <h4>WRAP_CONTENT and MATCH_PARENT</h4>
+ *
+ * Because the default values of the {@link #width} and {@link #height}
+ * properties are both {@link #WRAP_CONTENT}, this value never needs to be explicitly
+ * declared in the layout parameters of GridLayout's children. In addition,
+ * GridLayout does not distinguish the special size value {@link #MATCH_PARENT} from
+ * {@link #WRAP_CONTENT}. A component's ability to expand to the size of the parent is
+ * instead controlled by the principle of <em>flexibility</em>,
+ * as discussed in {@link GridLayout}.
+ *
+ * <h4>Summary</h4>
+ *
+ * You should not need to use either of the special size values:
+ * {@code WRAP_CONTENT} or {@code MATCH_PARENT} when configuring the children of
+ * a GridLayout.
*
* <h4>Default values</h4>
*
@@ -1561,12 +1644,17 @@ public class GridLayout extends ViewGroup {
* {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
* {@code false}; otherwise {@link #UNDEFINED}, to
* indicate that a default value should be computed on demand. </li>
- * <li>{@link #rowSpec}{@code .span} = {@code [0, 1]} </li>
- * <li>{@link #rowSpec}{@code .alignment} = {@link #BASELINE} </li>
- * <li>{@link #columnSpec}{@code .span} = {@code [0, 1]} </li>
- * <li>{@link #columnSpec}{@code .alignment} = {@link #LEFT} </li>
+ * <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li>
+ * <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li>
+ * <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
+ * <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
+ * <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
+ * <li>{@link #columnSpec}<code>.alignment</code> = {@link #LEFT} </li>
* </ul>
*
+ * See {@link GridLayout} for a more complete description of the conventions
+ * used by GridLayout in the interpretation of the properties of this class.
+ *
* @attr ref android.R.styleable#GridLayout_Layout_layout_row
* @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
* @attr ref android.R.styleable#GridLayout_Layout_layout_column
@@ -1606,15 +1694,16 @@ public class GridLayout extends ViewGroup {
// Instance variables
/**
- * The spec that specifies the vertical characteristics of the cell group
+ * The spec that defines the vertical characteristics of the cell group
* described by these layout parameters.
*/
- public Spec rowSpec;
+ public Spec rowSpec = Spec.UNDEFINED;
+
/**
- * The spec that specifies the horizontal characteristics of the cell group
+ * The spec that defines the horizontal characteristics of the cell group
* described by these layout parameters.
*/
- public Spec columnSpec;
+ public Spec columnSpec = Spec.UNDEFINED;
// Constructors
@@ -1646,7 +1735,7 @@ public class GridLayout extends ViewGroup {
* Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
*/
public LayoutParams() {
- this(spec(UNDEFINED), spec(UNDEFINED));
+ this(Spec.UNDEFINED, Spec.UNDEFINED);
}
// Copying constructors
@@ -1670,8 +1759,8 @@ public class GridLayout extends ViewGroup {
*/
public LayoutParams(LayoutParams that) {
super(that);
- this.rowSpec = new Spec(that.rowSpec);
- this.columnSpec = new Spec(that.columnSpec);
+ this.rowSpec = that.rowSpec;
+ this.columnSpec = that.columnSpec;
}
// AttributeSet constructors
@@ -1750,11 +1839,11 @@ public class GridLayout extends ViewGroup {
this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
}
- private void setRowSpecSpan(Interval span) {
+ final void setRowSpecSpan(Interval span) {
rowSpec = rowSpec.copyWriteSpan(span);
}
- private void setColumnSpecSpan(Interval span) {
+ final void setColumnSpecSpan(Interval span) {
columnSpec = columnSpec.copyWriteSpan(span);
}
}
@@ -1763,7 +1852,7 @@ public class GridLayout extends ViewGroup {
In place of a HashMap from span to Int, use an array of key/value pairs - stored in Arcs.
Add the mutables completesCycle flag to avoid creating another hash table for detecting cycles.
*/
- private static class Arc {
+ final static class Arc {
public final Interval span;
public final MutableInt value;
public boolean valid = true;
@@ -1781,18 +1870,18 @@ public class GridLayout extends ViewGroup {
// A mutable Integer - used to avoid heap allocation during the layout operation
- private static class MutableInt {
+ final static class MutableInt {
public int value;
- private MutableInt() {
+ public MutableInt() {
reset();
}
- private MutableInt(int value) {
+ public MutableInt(int value) {
this.value = value;
}
- private void reset() {
+ public void reset() {
value = Integer.MIN_VALUE;
}
@@ -1802,7 +1891,7 @@ public class GridLayout extends ViewGroup {
}
}
- private static class Assoc<K, V> extends ArrayList<Pair<K, V>> {
+ final static class Assoc<K, V> extends ArrayList<Pair<K, V>> {
private final Class<K> keyType;
private final Class<V> valueType;
@@ -1811,7 +1900,7 @@ public class GridLayout extends ViewGroup {
this.valueType = valueType;
}
- private static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) {
+ public static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) {
return new Assoc<K, V>(keyType, valueType);
}
@@ -1847,7 +1936,7 @@ public class GridLayout extends ViewGroup {
rather than using (and storing) an implementation of Map<Key, ?>.
*/
@SuppressWarnings(value = "unchecked")
- private static class PackedMap<K, V> {
+ final static class PackedMap<K, V> {
public final int[] index;
public final K[] keys;
public final V[] values;
@@ -1859,7 +1948,7 @@ public class GridLayout extends ViewGroup {
this.values = compact(values, index);
}
- private V getValue(int i) {
+ public V getValue(int i) {
return values[index[i]];
}
@@ -1907,7 +1996,7 @@ public class GridLayout extends ViewGroup {
group to Bounds and to loop through all Views in the group taking the maximum
of the values for each View.
*/
- private static class Bounds {
+ static class Bounds {
public int before;
public int after;
public int flexibility; // we're flexible iff all included specs are flexible
@@ -1969,7 +2058,7 @@ public class GridLayout extends ViewGroup {
* Intervals are often written as {@code [min, max]} and represent the set of values
* {@code x} such that {@code min <= x < max}.
*/
- static class Interval {
+ final static class Interval {
/**
* The minimum value.
*/
@@ -1995,11 +2084,11 @@ public class GridLayout extends ViewGroup {
this.max = max;
}
- private int size() {
+ int size() {
return max - min;
}
- private Interval inverse() {
+ Interval inverse() {
return new Interval(max, min);
}
@@ -2062,32 +2151,31 @@ public class GridLayout extends ViewGroup {
* For column groups, this specifies the horizontal alignment.
*/
public static class Spec {
+ static final Spec UNDEFINED = spec(GridLayout.UNDEFINED);
+
+ final boolean startDefined;
final Interval span;
final Alignment alignment;
- private Spec(Interval span, Alignment alignment) {
+ private Spec(boolean startDefined, Interval span, Alignment alignment) {
+ this.startDefined = startDefined;
this.span = span;
this.alignment = alignment;
}
- /* Copying constructor */
- private Spec(Spec that) {
- this(that.span, that.alignment);
- }
-
- private Spec(int start, int size, Alignment alignment) {
- this(new Interval(start, start + size), alignment);
+ private Spec(boolean startDefined, int start, int size, Alignment alignment) {
+ this(startDefined, new Interval(start, start + size), alignment);
}
- private Spec copyWriteSpan(Interval span) {
- return new Spec(span, alignment);
+ final Spec copyWriteSpan(Interval span) {
+ return new Spec(startDefined, span, alignment);
}
- private Spec copyWriteAlignment(Alignment alignment) {
- return new Spec(span, alignment);
+ final Spec copyWriteAlignment(Alignment alignment) {
+ return new Spec(startDefined, span, alignment);
}
- int getFlexibility() {
+ final int getFlexibility() {
return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
}
@@ -2143,7 +2231,7 @@ public class GridLayout extends ViewGroup {
* @param alignment the alignment
*/
public static Spec spec(int start, int size, Alignment alignment) {
- return new Spec(start, size, alignment);
+ return new Spec(start != UNDEFINED, start, size, alignment);
}
/**
@@ -2246,7 +2334,7 @@ public class GridLayout extends ViewGroup {
}
}
- private static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
+ static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
public int getAlignmentValue(View view, int viewSize) {
return UNDEFINED;
}
@@ -2367,7 +2455,7 @@ public class GridLayout extends ViewGroup {
}
};
- private static boolean canStretch(int flexibility) {
+ static boolean canStretch(int flexibility) {
return (flexibility & CAN_STRETCH) != 0;
}
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 690164c..a63b8c8 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -299,6 +299,7 @@ public class MediaController extends FrameLayout {
p.format = PixelFormat.TRANSLUCENT;
p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
p.token = null;
p.windowAnimations = 0; // android.R.style.DropDownAnimationDown;
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index e571998..6aee5a0 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -584,10 +584,10 @@ public class OverScroller {
// A device specific coefficient adjusted to physical values.
private static float PHYSICAL_COEF;
- private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9));
- private static final float INFLEXION = 0.4f; // Tension lines cross at (INFLEXION, 1)
- private static final float START_TENSION = 1.0f;
- private static final float END_TENSION = 0.6666f;
+ private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
+ private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
+ private static final float START_TENSION = 0.5f;
+ private static final float END_TENSION = 1.0f;
private static final float P1 = START_TENSION * INFLEXION;
private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 17512d8..6a6d767 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -157,6 +157,8 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
* @hide
*/
public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ if (subMenu == null) return false;
+
if (!subMenu.hasVisibleItems()) {
return true;
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 4d45c2f..aac20c4 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -796,6 +796,21 @@ public class PopupWindow {
* @param y the popup's y location offset
*/
public void showAtLocation(View parent, int gravity, int x, int y) {
+ showAtLocation(parent.getWindowToken(), gravity, x, y);
+ }
+
+ /**
+ * Display the content view in a popup window at the specified location.
+ *
+ * @param token Window token to use for creating the new window
+ * @param gravity the gravity which controls the placement of the popup window
+ * @param x the popup's x location offset
+ * @param y the popup's y location offset
+ *
+ * @hide Internal use only. Applications should use
+ * {@link #showAtLocation(View, int, int, int)} instead.
+ */
+ public void showAtLocation(IBinder token, int gravity, int x, int y) {
if (isShowing() || mContentView == null) {
return;
}
@@ -805,7 +820,7 @@ public class PopupWindow {
mIsShowing = true;
mIsDropdown = false;
- WindowManager.LayoutParams p = createPopupLayout(parent.getWindowToken());
+ WindowManager.LayoutParams p = createPopupLayout(token);
p.windowAnimations = computeAnimationResource();
preparePopup(p);
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 6edfd59..12a93ac 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -212,6 +212,11 @@ public class RelativeLayout extends ViewGroup {
* Describes how the child views are positioned. Defaults to
* <code>Gravity.LEFT | Gravity.TOP</code>.
*
+ * <p>Note that since RelativeLayout considers the positioning of each child
+ * relative to one another to be significant, setting gravity will affect
+ * the positioning of all children as a single unit within the parent.
+ * This happens after children have been relatively positioned.</p>
+ *
* @param gravity See {@link android.view.Gravity}
*
* @see #setHorizontalGravity(int)
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index 6e29024..3627890 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -169,6 +169,7 @@ public class ShareActionProvider extends ActionProvider {
mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
+ activityChooserView.setProvider(this);
return activityChooserView;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d680f36..8db6592 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8944,13 +8944,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final boolean isPassword = hasPasswordTransformationMethod();
if (!isPassword) {
- CharSequence text = getText();
- if (TextUtils.isEmpty(text)) {
- text = getHint();
- }
- if (TextUtils.isEmpty(text)) {
- text = getContentDescription();
- }
+ CharSequence text = getTextForAccessibility();
if (!TextUtils.isEmpty(text)) {
event.getText().add(text);
}
@@ -8977,7 +8971,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final boolean isPassword = hasPasswordTransformationMethod();
if (!isPassword) {
- info.setText(getText());
+ info.setText(getTextForAccessibility());
}
info.setPassword(isPassword);
}
@@ -8993,6 +8987,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
super.sendAccessibilityEvent(eventType);
}
+ /**
+ * Gets the text reported for accessibility purposes. It is the
+ * text if not empty or the hint.
+ *
+ * @return The accessibility text.
+ */
+ private CharSequence getTextForAccessibility() {
+ CharSequence text = getText();
+ if (TextUtils.isEmpty(text)) {
+ text = getHint();
+ }
+ return text;
+ }
+
void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
int fromIndex, int removedCount, int addedCount) {
AccessibilityEvent event =
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index fba6a5a..0db1ccc 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -24,6 +24,7 @@ import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseBooleanArray;
+import android.view.ActionProvider;
import android.view.MenuItem;
import android.view.SoundEffectConstants;
import android.view.View;
@@ -40,7 +41,8 @@ import java.util.ArrayList;
/**
* MenuPresenter for building action menus as seen in the action bar and action modes.
*/
-public class ActionMenuPresenter extends BaseMenuPresenter {
+public class ActionMenuPresenter extends BaseMenuPresenter
+ implements ActionProvider.SubUiVisibilityListener {
private static final String TAG = "ActionMenuPresenter";
private View mOverflowButton;
@@ -187,6 +189,17 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
public void updateMenuView(boolean cleared) {
super.updateMenuView(cleared);
+ if (mMenu != null) {
+ final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems();
+ final int count = actionItems.size();
+ for (int i = 0; i < count; i++) {
+ final ActionProvider provider = actionItems.get(i).getActionProvider();
+ if (provider != null) {
+ provider.setSubUiVisibilityListener(this);
+ }
+ }
+ }
+
final boolean hasOverflow = mReserveOverflow && mMenu != null &&
mMenu.getNonActionItems().size() > 0;
if (hasOverflow) {
@@ -483,6 +496,16 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
}
}
+ @Override
+ public void onSubUiVisibilityChanged(boolean isVisible) {
+ if (isVisible) {
+ // Not a submenu, but treat it like one.
+ super.onSubMenuSelected(null);
+ } else {
+ mMenu.close(false);
+ }
+ }
+
private static class SavedState implements Parcelable {
public int openSubMenuId;
@@ -590,7 +613,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
@Override
public void onDismiss() {
super.onDismiss();
- mSubMenu.close();
mActionButtonPopup = null;
mOpenSubMenuId = 0;
}
@@ -600,12 +622,17 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
@Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ if (subMenu == null) return false;
+
mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
return false;
}
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ if (menu instanceof SubMenuBuilder) {
+ ((SubMenuBuilder) menu).getRootMenu().close(false);
+ }
}
}
diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
index d1b1dae..24ddad6 100644
--- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
@@ -187,7 +187,9 @@ public class IconMenuPresenter extends BaseMenuPresenter {
@Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
- mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
+ if (subMenu != null) {
+ mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
+ }
return false;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e3a4df9..19dc42b 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -756,24 +756,36 @@ public class LockPatternUtils {
}
/**
- * @return Whether the lock password is enabled.
+ * @return Whether the lock password is enabled, or if it is set as a backup for biometric weak
*/
public boolean isLockPasswordEnabled() {
long mode = getLong(PASSWORD_TYPE_KEY, 0);
- return savedPasswordExists() &&
- (mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
- || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
- || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
- || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+ long backupMode = getLong(PASSWORD_TYPE_ALTERNATE_KEY, 0);
+ final boolean passwordEnabled = mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
+ || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+ final boolean backupEnabled = backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
+ || backupMode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
+ || backupMode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
+ || backupMode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+
+ return savedPasswordExists() && (passwordEnabled ||
+ (isBiometricEnabled() && backupEnabled));
}
/**
- * @return Whether the lock pattern is enabled.
+ * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
*/
public boolean isLockPatternEnabled() {
+ final boolean backupEnabled =
+ getLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
+ == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+
return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED)
- && getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
- == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+ && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
+ == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
+ (isBiometricEnabled() && backupEnabled));
}
/**
@@ -923,8 +935,7 @@ public class LockPatternUtils {
|| mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
- || isPassword && savedPasswordExists()
- || usingBiometricWeak() && isBiometricEnabled();
+ || isPassword && savedPasswordExists();
return secure;
}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index c03f91c..1b5112f 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -114,6 +114,13 @@ public class MultiWaveView extends View {
}
};
+ private AnimatorListener mResetListenerWithPing = new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animator) {
+ ping();
+ switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
+ }
+ };
+
private AnimatorUpdateListener mUpdateListener = new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
invalidateGlobalRegion(mHandleDrawable);
@@ -421,7 +428,7 @@ public class MultiWaveView extends View {
"x", mWaveCenterX,
"y", mWaveCenterY,
"onUpdate", mUpdateListener,
- "onComplete", mResetListener);
+ "onComplete", mResetListenerWithPing);
}
setGrabbedState(OnTriggerListener.NO_HANDLE);
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 9f6ab31..8445ad1 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -75,30 +75,20 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x"
+ Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid);
}
- try {
- // TODO: skip tagging when options would be no-op
- tagSocketFd(fd, options.statsTag, options.statsUid);
- } catch (IOException e) {
- throw new SocketException("Problem tagging socket", e);
- }
+ // TODO: skip tagging when options would be no-op
+ tagSocketFd(fd, options.statsTag, options.statsUid);
}
- private void tagSocketFd(FileDescriptor fd, int tag, int uid) throws IOException {
- final int fdNum = fd.getInt$();
- if (fdNum == -1 || (tag == -1 && uid == -1)) return;
-
- String cmd = "t " + fdNum;
- if (tag == -1) {
- // Case where just the uid needs adjusting. But probably the caller
- // will want to track his own name here, just in case.
- cmd += " 0";
- } else {
- cmd += " " + tagToKernel(tag);
- }
- if (uid != -1) {
- cmd += " " + uid;
+ private void tagSocketFd(FileDescriptor fd, int tag, int uid) {
+ int errno;
+ if (tag == -1 && uid == -1) return;
+
+ errno = native_tagSocketFd(fd, tag, uid);
+ if (errno < 0) {
+ Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", "
+ + tag + ", " +
+ + uid + ") failed with errno" + errno);
}
- internalModuleCtrl(cmd);
}
@Override
@@ -106,19 +96,18 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
if (LOGD) {
Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
}
- try {
- unTagSocketFd(fd);
- } catch (IOException e) {
- throw new SocketException("Problem untagging socket", e);
- }
+ unTagSocketFd(fd);
}
- private void unTagSocketFd(FileDescriptor fd) throws IOException {
- int fdNum = fd.getInt$();
+ private void unTagSocketFd(FileDescriptor fd) {
final SocketTags options = threadSocketTags.get();
- if (fdNum == -1 || (options.statsTag == -1 && options.statsUid == -1)) return;
- String cmd = "u " + fdNum;
- internalModuleCtrl(cmd);
+ int errno;
+ if (options.statsTag == -1 && options.statsUid == -1) return;
+
+ errno = native_untagSocketFd(fd);
+ if (errno < 0) {
+ Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno);
+ }
}
public static class SocketTags {
@@ -127,69 +116,20 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
}
public static void setKernelCounterSet(int uid, int counterSet) {
- final StringBuilder command = new StringBuilder();
- command.append("s ").append(counterSet).append(" ").append(uid);
- try {
- internalModuleCtrl(command.toString());
- } catch (IOException e) {
- Slog.w(TAG, "problem changing counter set for uid " + uid + " : " + e);
+ int errno = native_setCounterSet(counterSet, uid);
+ if (errno < 0) {
+ Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno " + errno);
}
}
public static void resetKernelUidStats(int uid) {
- final StringBuilder command = new StringBuilder();
- command.append("d 0 ").append(uid);
- try {
- internalModuleCtrl(command.toString());
- } catch (IOException e) {
- Slog.w(TAG, "problem clearing counters for uid " + uid + " : " + e);
+ int errno = native_deleteTagData(0, uid);
+ if (errno < 0) {
+ Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno);
}
}
/**
- * Sends commands to the kernel netfilter module.
- *
- * @param cmd command string for the qtaguid netfilter module. May not be null.
- * <p>Supports:
- * <ul><li>tag a socket:<br>
- * <code>t <i>sock_fd</i> <i>acct_tag</i> [<i>uid_in_case_caller_is_acting_on_behalf_of</i>]</code><br>
- * <code>*_tag</code> defaults to default_policy_tag_from_uid(uid_of_caller)<br>
- * <code>acct_tag</code> is either 0 or greater that 2^32.<br>
- * <code>uid_*</code> is only settable by privileged UIDs (DownloadManager,...)
- * </li>
- * <li>untag a socket, preserving counters:<br>
- * <code>u <i>sock_fd</i></code>
- * </li></ul>
- * <p>Notes:<br>
- * <ul><li><i>sock_fd</i> is withing the callers process space.</li>
- * <li><i>*_tag</i> are 64bit values</li></ul>
- *
- */
- private static void internalModuleCtrl(String cmd) throws IOException {
- if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
-
- // TODO: migrate to native library for tagging commands
- FileOutputStream procOut = null;
- try {
- procOut = new FileOutputStream("/proc/net/xt_qtaguid/ctrl");
- procOut.write(cmd.getBytes(Charsets.US_ASCII));
- } finally {
- IoUtils.closeQuietly(procOut);
- }
- }
-
- /**
- * Convert {@link Integer} tag to {@code /proc/} format. Assumes unsigned
- * base-10 format like {@code 2147483647}. Currently strips signed bit to
- * avoid using {@link BigInteger}.
- */
- public static String tagToKernel(int tag) {
- // TODO: eventually write in hex, since that's what proc exports
- // TODO: migrate to direct integer instead of odd shifting
- return Long.toString((((long) tag) << 32) & 0x7FFFFFFF00000000L);
- }
-
- /**
* Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming
* format like {@code 0x7fffffff00000000}.
*/
@@ -197,4 +137,9 @@ public final class NetworkManagementSocketTagger extends SocketTagger {
// TODO: migrate to direct integer instead of odd shifting
return (int) (Long.decode(string) >> 32);
}
+
+ private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid);
+ private static native int native_untagSocketFd(FileDescriptor fd);
+ private static native int native_setCounterSet(int uid, int counterSetNum);
+ private static native int native_deleteTagData(int tag, int uid);
}