summaryrefslogtreecommitdiffstats
path: root/core/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/com')
-rw-r--r--core/java/com/android/internal/net/NetworkStatsFactory.java66
-rw-r--r--core/java/com/android/internal/textservice/ISpellCheckerSession.aidl1
-rw-r--r--core/java/com/android/internal/util/ProcFileReader.java199
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuItemView.java26
-rw-r--r--core/java/com/android/internal/view/menu/BaseMenuPresenter.java7
-rw-r--r--core/java/com/android/internal/view/menu/ExpandedMenuView.java5
-rw-r--r--core/java/com/android/internal/view/menu/ListMenuItemView.java21
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java3
-rw-r--r--core/java/com/android/internal/widget/DigitalClock.java5
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java17
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java2
-rw-r--r--core/java/com/android/internal/widget/WaveView.java90
12 files changed, 364 insertions, 78 deletions
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index ee3f23b..41993c4 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -25,12 +25,14 @@ import android.net.NetworkStats;
import android.os.SystemClock;
import android.util.Slog;
+import com.android.internal.util.ProcFileReader;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
@@ -107,6 +109,7 @@ public class NetworkStatsFactory {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
final NetworkStats.Entry entry = new NetworkStats.Entry();
+ // TODO: transition to ProcFileReader
// TODO: read directly from proc once headers are added
final ArrayList<String> keys = Lists.newArrayList(KEY_IFACE, KEY_ACTIVE, KEY_SNAP_RX_BYTES,
KEY_SNAP_RX_PACKETS, KEY_SNAP_TX_BYTES, KEY_SNAP_TX_PACKETS, KEY_RX_BYTES,
@@ -257,71 +260,58 @@ public class NetworkStatsFactory {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
final NetworkStats.Entry entry = new NetworkStats.Entry();
- // TODO: remove knownLines check once 5087722 verified
- final HashSet<String> knownLines = Sets.newHashSet();
- // TODO: remove lastIdx check once 5270106 verified
- int lastIdx;
+ int idx = 1;
+ int lastIdx = 1;
- final ArrayList<String> keys = Lists.newArrayList();
- final ArrayList<String> values = Lists.newArrayList();
- final HashMap<String, String> parsed = Maps.newHashMap();
-
- BufferedReader reader = null;
- String line = null;
+ ProcFileReader reader = null;
try {
- reader = new BufferedReader(new FileReader(mStatsXtUid));
-
- // parse first line as header
- line = reader.readLine();
- splitLine(line, keys);
- lastIdx = 1;
-
- // parse remaining lines
- while ((line = reader.readLine()) != null) {
- splitLine(line, values);
- parseLine(keys, values, parsed);
+ // open and consume header line
+ reader = new ProcFileReader(new FileInputStream(mStatsXtUid));
+ reader.finishLine();
- if (!knownLines.add(line)) {
- throw new IllegalStateException("duplicate proc entry: " + line);
- }
-
- final int idx = getParsedInt(parsed, KEY_IDX);
+ while (reader.hasMoreData()) {
+ idx = reader.nextInt();
if (idx != lastIdx + 1) {
throw new IllegalStateException(
"inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
}
lastIdx = idx;
- entry.iface = parsed.get(KEY_IFACE);
- entry.uid = getParsedInt(parsed, KEY_UID);
- entry.set = getParsedInt(parsed, KEY_COUNTER_SET);
- entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
- entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
- entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
- entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
- entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
+ entry.iface = reader.nextString();
+ entry.tag = kernelToTag(reader.nextString());
+ entry.uid = reader.nextInt();
+ entry.set = reader.nextInt();
+ entry.rxBytes = reader.nextLong();
+ entry.rxPackets = reader.nextLong();
+ entry.txBytes = reader.nextLong();
+ entry.txPackets = reader.nextLong();
if (limitUid == UID_ALL || limitUid == entry.uid) {
stats.addValues(entry);
}
+
+ reader.finishLine();
}
} catch (NullPointerException e) {
- throw new IllegalStateException("problem parsing line: " + line, e);
+ throw new IllegalStateException("problem parsing idx " + idx, e);
} catch (NumberFormatException e) {
- throw new IllegalStateException("problem parsing line: " + line, e);
+ throw new IllegalStateException("problem parsing idx " + idx, e);
} catch (IOException e) {
- throw new IllegalStateException("problem parsing line: " + line, e);
+ throw new IllegalStateException("problem parsing idx " + idx, e);
} finally {
IoUtils.closeQuietly(reader);
}
+
return stats;
}
+ @Deprecated
private static int getParsedInt(HashMap<String, String> parsed, String key) {
final String value = parsed.get(key);
return value != null ? Integer.parseInt(value) : 0;
}
+ @Deprecated
private static long getParsedLong(HashMap<String, String> parsed, String key) {
final String value = parsed.get(key);
return value != null ? Long.parseLong(value) : 0;
@@ -330,6 +320,7 @@ public class NetworkStatsFactory {
/**
* Split given line into {@link ArrayList}.
*/
+ @Deprecated
private static void splitLine(String line, ArrayList<String> outSplit) {
outSplit.clear();
@@ -343,6 +334,7 @@ public class NetworkStatsFactory {
* Zip the two given {@link ArrayList} as key and value pairs into
* {@link HashMap}.
*/
+ @Deprecated
private static void parseLine(
ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
outParsed.clear();
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
index 5a00603..3c61968 100644
--- a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
@@ -25,4 +25,5 @@ oneway interface ISpellCheckerSession {
void onGetSuggestionsMultiple(
in TextInfo[] textInfos, int suggestionsLimit, boolean multipleWords);
void onCancel();
+ void onClose();
}
diff --git a/core/java/com/android/internal/util/ProcFileReader.java b/core/java/com/android/internal/util/ProcFileReader.java
new file mode 100644
index 0000000..72e1f0f
--- /dev/null
+++ b/core/java/com/android/internal/util/ProcFileReader.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charsets;
+
+/**
+ * Reader that specializes in parsing {@code /proc/} files quickly. Walks
+ * through the stream using a single space {@code ' '} as token separator, and
+ * requires each line boundary to be explicitly acknowledged using
+ * {@link #finishLine()}. Assumes {@link Charsets#US_ASCII} encoding.
+ * <p>
+ * Currently doesn't support formats based on {@code \0}, tabs, or repeated
+ * delimiters.
+ */
+public class ProcFileReader implements Closeable {
+ private final InputStream mStream;
+ private final byte[] mBuffer;
+
+ /** Write pointer in {@link #mBuffer}. */
+ private int mTail;
+ /** Flag when last read token finished current line. */
+ private boolean mLineFinished;
+
+ public ProcFileReader(InputStream stream) throws IOException {
+ this(stream, 4096);
+ }
+
+ public ProcFileReader(InputStream stream, int bufferSize) throws IOException {
+ mStream = stream;
+ mBuffer = new byte[bufferSize];
+
+ // read enough to answer hasMoreData
+ fillBuf();
+ }
+
+ /**
+ * Read more data from {@link #mStream} into internal buffer.
+ */
+ private int fillBuf() throws IOException {
+ final int length = mBuffer.length - mTail;
+ if (length == 0) {
+ throw new IOException("attempting to fill already-full buffer");
+ }
+
+ final int read = mStream.read(mBuffer, mTail, length);
+ if (read != -1) {
+ mTail += read;
+ }
+ return read;
+ }
+
+ /**
+ * Consume number of bytes from beginning of internal buffer. If consuming
+ * all remaining bytes, will attempt to {@link #fillBuf()}.
+ */
+ private void consumeBuf(int count) throws IOException {
+ // TODO: consider moving to read pointer, but for now traceview says
+ // these copies aren't a bottleneck.
+ System.arraycopy(mBuffer, count, mBuffer, 0, mTail - count);
+ mTail -= count;
+ if (mTail == 0) {
+ fillBuf();
+ }
+ }
+
+ /**
+ * Find buffer index of next token delimiter, usually space or newline. Will
+ * fill buffer as needed.
+ */
+ private int nextTokenIndex() throws IOException {
+ if (mLineFinished) {
+ throw new IOException("no tokens remaining on current line");
+ }
+
+ int i = 0;
+ do {
+ // scan forward for token boundary
+ for (; i < mTail; i++) {
+ final byte b = mBuffer[i];
+ if (b == '\n') {
+ mLineFinished = true;
+ return i;
+ }
+ if (b == ' ') {
+ return i;
+ }
+ }
+ } while (fillBuf() > 0);
+
+ throw new IOException("end of stream while looking for token boundary");
+ }
+
+ /**
+ * Check if stream has more data to be parsed.
+ */
+ public boolean hasMoreData() {
+ return mTail > 0;
+ }
+
+ /**
+ * Finish current line, skipping any remaining data.
+ */
+ public void finishLine() throws IOException {
+ // last token already finished line; reset silently
+ if (mLineFinished) {
+ mLineFinished = false;
+ return;
+ }
+
+ int i = 0;
+ do {
+ // scan forward for line boundary and consume
+ for (; i < mTail; i++) {
+ if (mBuffer[i] == '\n') {
+ consumeBuf(i + 1);
+ return;
+ }
+ }
+ } while (fillBuf() > 0);
+
+ throw new IOException("end of stream while looking for line boundary");
+ }
+
+ /**
+ * Parse and return next token as {@link String}.
+ */
+ public String nextString() throws IOException {
+ final int tokenIndex = nextTokenIndex();
+ final String s = new String(mBuffer, 0, tokenIndex, Charsets.US_ASCII);
+ consumeBuf(tokenIndex + 1);
+ return s;
+ }
+
+ /**
+ * Parse and return next token as base-10 encoded {@code long}.
+ */
+ public long nextLong() throws IOException {
+ final int tokenIndex = nextTokenIndex();
+ final boolean negative = mBuffer[0] == '-';
+
+ // TODO: refactor into something like IntegralToString
+ long result = 0;
+ for (int i = negative ? 1 : 0; i < tokenIndex; i++) {
+ final int digit = mBuffer[i] - '0';
+ if (digit < 0 || digit > 9) {
+ throw invalidLong(tokenIndex);
+ }
+
+ // always parse as negative number and apply sign later; this
+ // correctly handles MIN_VALUE which is "larger" than MAX_VALUE.
+ final long next = result * 10 - digit;
+ if (next > result) {
+ throw invalidLong(tokenIndex);
+ }
+ result = next;
+ }
+
+ consumeBuf(tokenIndex + 1);
+ return negative ? result : -result;
+ }
+
+ private NumberFormatException invalidLong(int tokenIndex) {
+ return new NumberFormatException(
+ "invalid long: " + new String(mBuffer, 0, tokenIndex, Charsets.US_ASCII));
+ }
+
+ /**
+ * Parse and return next token as base-10 encoded {@code int}.
+ */
+ public int nextInt() throws IOException {
+ final long value = nextLong();
+ if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
+ throw new NumberFormatException("parsed value larger than integer");
+ }
+ return (int) value;
+ }
+
+ public void close() throws IOException {
+ mStream.close();
+ }
+}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index e245960..a10d241 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -18,6 +18,7 @@ package com.android.internal.view.menu;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
@@ -46,8 +47,8 @@ public class ActionMenuItemView extends LinearLayout
private ImageButton mImageButton;
private Button mTextButton;
private boolean mAllowTextWithIcon;
- private boolean mShowTextAllCaps;
private boolean mExpandedFormat;
+ private int mMinWidth;
public ActionMenuItemView(Context context) {
this(context, null);
@@ -62,7 +63,11 @@ public class ActionMenuItemView extends LinearLayout
final Resources res = context.getResources();
mAllowTextWithIcon = res.getBoolean(
com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
- mShowTextAllCaps = res.getBoolean(com.android.internal.R.bool.config_actionMenuItemAllCaps);
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.ActionMenuItemView, 0, 0);
+ mMinWidth = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.ActionMenuItemView_minWidth, 0);
+ a.recycle();
}
@Override
@@ -228,4 +233,21 @@ public class ActionMenuItemView extends LinearLayout
cheatSheet.show();
return true;
}
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int specSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int oldMeasuredWidth = getMeasuredWidth();
+ final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, mMinWidth)
+ : mMinWidth;
+
+ if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) {
+ // Remeasure at exactly the minimum width.
+ super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
+ heightMeasureSpec);
+ }
+ }
}
diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
index 1e06b5a..db0d6dd 100644
--- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
@@ -91,7 +91,14 @@ public abstract class BaseMenuPresenter implements MenuPresenter {
MenuItemImpl item = visibleItems.get(i);
if (shouldIncludeItem(childIndex, item)) {
final View convertView = parent.getChildAt(childIndex);
+ final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
+ ((MenuView.ItemView) convertView).getItemData() : null;
final View itemView = getItemView(item, convertView, parent);
+ if (item != oldItem) {
+ // Don't let old states linger with new data.
+ itemView.setPressed(false);
+ itemView.jumpDrawablesToCurrentState();
+ }
if (itemView != convertView) {
addItemView(itemView, childIndex);
}
diff --git a/core/java/com/android/internal/view/menu/ExpandedMenuView.java b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
index 723ece4..47058ad 100644
--- a/core/java/com/android/internal/view/menu/ExpandedMenuView.java
+++ b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
@@ -63,11 +63,6 @@ public final class ExpandedMenuView extends ListView implements ItemInvoker, Men
setChildrenDrawingCacheEnabled(false);
}
- @Override
- protected boolean recycleOnMeasure() {
- return false;
- }
-
public boolean invokeItem(MenuItemImpl item) {
return mMenu.performItemAction(item, 0);
}
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index a1e16d4..df579c6 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -34,6 +34,7 @@ import android.widget.TextView;
* The item view for each item in the ListView-based MenuViews.
*/
public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
+ private static final String TAG = "ListMenuItemView";
private MenuItemImpl mItemData;
private ImageView mIconView;
@@ -121,27 +122,25 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
}
public void setCheckable(boolean checkable) {
-
if (!checkable && mRadioButton == null && mCheckBox == null) {
return;
}
- if (mRadioButton == null) {
- insertRadioButton();
- }
- if (mCheckBox == null) {
- insertCheckBox();
- }
-
// Depending on whether its exclusive check or not, the checkbox or
// radio button will be the one in use (and the other will be otherCompoundButton)
final CompoundButton compoundButton;
final CompoundButton otherCompoundButton;
if (mItemData.isExclusiveCheckable()) {
+ if (mRadioButton == null) {
+ insertRadioButton();
+ }
compoundButton = mRadioButton;
otherCompoundButton = mCheckBox;
} else {
+ if (mCheckBox == null) {
+ insertCheckBox();
+ }
compoundButton = mCheckBox;
otherCompoundButton = mRadioButton;
}
@@ -155,12 +154,12 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
}
// Make sure the other compound button isn't visible
- if (otherCompoundButton.getVisibility() != GONE) {
+ if (otherCompoundButton != null && otherCompoundButton.getVisibility() != GONE) {
otherCompoundButton.setVisibility(GONE);
}
} else {
- mCheckBox.setVisibility(GONE);
- mRadioButton.setVisibility(GONE);
+ if (mCheckBox != null) mCheckBox.setVisibility(GONE);
+ if (mRadioButton != null) mRadioButton.setVisibility(GONE);
}
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index e131242..b689f53 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -518,6 +518,7 @@ public class ActionBarView extends AbsActionBarView {
public void setHomeButtonEnabled(boolean enable) {
mHomeLayout.setEnabled(enable);
+ mHomeLayout.setFocusable(enable);
// Make sure the home button has an accurate content description for accessibility.
if (!enable) {
mHomeLayout.setContentDescription(null);
@@ -536,7 +537,7 @@ public class ActionBarView extends AbsActionBarView {
if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
- final int vis = showHome ? VISIBLE : GONE;
+ final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE;
mHomeLayout.setVisibility(vis);
if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index 18a4794..daefc9a 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -106,7 +106,8 @@ public class DigitalClock extends RelativeLayout {
private String mAmString, mPmString;
AmPm(View parent, Typeface tf) {
- mAmPmTextView = (TextView) parent.findViewById(R.id.am_pm);
+ // No longer used, uncomment if we decide to use AM/PM indicator again
+ // mAmPmTextView = (TextView) parent.findViewById(R.id.am_pm);
if (mAmPmTextView != null && tf != null) {
mAmPmTextView.setTypeface(tf);
}
@@ -168,6 +169,8 @@ public class DigitalClock extends RelativeLayout {
/* The time display consists of two tones. That's why we have two overlapping text views. */
mTimeDisplayBackground = (TextView) findViewById(R.id.timeDisplayBackground);
mTimeDisplayBackground.setTypeface(sBackgroundFont);
+ mTimeDisplayBackground.setVisibility(View.INVISIBLE);
+
mTimeDisplayForeground = (TextView) findViewById(R.id.timeDisplayForeground);
mTimeDisplayForeground.setTypeface(sForegroundFont);
mAmPm = new AmPm(this, null);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 17b8acf..89f9d4e 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -25,14 +25,11 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.hardware.Camera;
-import android.hardware.Camera.CameraInfo;
import android.os.FileObserver;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.storage.IMountService;
import android.provider.Settings;
import android.security.KeyStore;
@@ -41,7 +38,6 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
-import android.widget.TextView;
import java.io.File;
import java.io.FileNotFoundException;
@@ -968,6 +964,11 @@ public class LockPatternUtils {
com.android.internal.R.bool.config_enable_puk_unlock_screen);
}
+ public boolean isEmergencyCallEnabledWhileSimLocked() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
+ }
+
/**
* @return A formatted string of the next alarm (for showing on the lock screen),
* or null if there is no next alarm.
@@ -1031,12 +1032,10 @@ public class LockPatternUtils {
* {@link TelephonyManager#CALL_STATE_IDLE}
* {@link TelephonyManager#CALL_STATE_RINGING}
* {@link TelephonyManager#CALL_STATE_OFFHOOK}
- * @param showIfCapable indicates whether the button should be shown if emergency calls are
- * possible on the device
+ * @param shown indicates whether the given screen wants the emergency button to show at all
*/
- public void updateEmergencyCallButtonState(Button button, int phoneState,
- boolean showIfCapable) {
- if (isEmergencyCallCapable() && showIfCapable) {
+ public void updateEmergencyCallButtonState(Button button, int phoneState, boolean shown) {
+ if (isEmergencyCallCapable() && shown) {
button.setVisibility(View.VISIBLE);
} else {
button.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index a2fc6e2..0d9cf9a 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -463,7 +463,7 @@ public class LockPatternView extends View {
result = desired;
break;
case MeasureSpec.AT_MOST:
- result = Math.min(specSize, desired);
+ result = Math.max(specSize, desired);
break;
case MeasureSpec.EXACTLY:
default:
diff --git a/core/java/com/android/internal/widget/WaveView.java b/core/java/com/android/internal/widget/WaveView.java
index 288865f..2d89234 100644
--- a/core/java/com/android/internal/widget/WaveView.java
+++ b/core/java/com/android/internal/widget/WaveView.java
@@ -26,10 +26,13 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.os.Vibrator;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import com.android.internal.R;
@@ -64,6 +67,18 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen
private static final long DELAY_INCREMENT2 = 12; // increment per wave while not tracking
private static final long WAVE_DELAY = WAVE_DURATION / WAVE_COUNT; // initial propagation delay
+ /**
+ * The scale by which to multiply the unlock handle width to compute the radius
+ * in which it can be grabbed when accessibility is disabled.
+ */
+ private static final float GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_DISABLED = 0.5f;
+
+ /**
+ * The scale by which to multiply the unlock handle width to compute the radius
+ * in which it can be grabbed when accessibility is enabled (more generous).
+ */
+ private static final float GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_ENABLED = 1.0f;
+
private Vibrator mVibrator;
private OnTriggerListener mOnTriggerListener;
private ArrayList<DrawableHolder> mDrawables = new ArrayList<DrawableHolder>(3);
@@ -451,6 +466,27 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen
};
@Override
+ public boolean onHoverEvent(MotionEvent event) {
+ if (AccessibilityManager.getInstance(mContext).isTouchExplorationEnabled()) {
+ final int action = event.getAction();
+ switch (action) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ event.setAction(MotionEvent.ACTION_DOWN);
+ break;
+ case MotionEvent.ACTION_HOVER_MOVE:
+ event.setAction(MotionEvent.ACTION_MOVE);
+ break;
+ case MotionEvent.ACTION_HOVER_EXIT:
+ event.setAction(MotionEvent.ACTION_UP);
+ break;
+ }
+ onTouchEvent(event);
+ event.setAction(action);
+ }
+ return super.onHoverEvent(event);
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getAction();
mMouseX = event.getX();
@@ -460,21 +496,12 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen
case MotionEvent.ACTION_DOWN:
removeCallbacks(mLockTimerActions);
mFingerDown = true;
- setGrabbedState(OnTriggerListener.CENTER_HANDLE);
- {
- float x = mMouseX - mUnlockHalo.getX();
- float y = mMouseY - mUnlockHalo.getY();
- float dist = (float) Math.hypot(x, y);
- if (dist < mUnlockHalo.getWidth()*0.5f) {
- if (mLockState == STATE_READY) {
- mLockState = STATE_START_ATTEMPT;
- }
- }
- }
+ tryTransitionToStartAttemptState(event);
handled = true;
break;
case MotionEvent.ACTION_MOVE:
+ tryTransitionToStartAttemptState(event);
handled = true;
break;
@@ -502,6 +529,47 @@ public class WaveView extends View implements ValueAnimator.AnimatorUpdateListen
}
/**
+ * Tries to transition to start attempt state.
+ *
+ * @param event A motion event.
+ */
+ private void tryTransitionToStartAttemptState(MotionEvent event) {
+ final float dx = event.getX() - mUnlockHalo.getX();
+ final float dy = event.getY() - mUnlockHalo.getY();
+ float dist = (float) Math.hypot(dx, dy);
+ if (dist <= getScaledGrabHandleRadius()) {
+ setGrabbedState(OnTriggerListener.CENTER_HANDLE);
+ if (mLockState == STATE_READY) {
+ mLockState = STATE_START_ATTEMPT;
+ if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ announceUnlockHandle();
+ }
+ }
+ }
+ }
+
+ /**
+ * @return The radius in which the handle is grabbed scaled based on
+ * whether accessibility is enabled.
+ */
+ private float getScaledGrabHandleRadius() {
+ if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ return GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_ENABLED * mUnlockHalo.getWidth();
+ } else {
+ return GRAB_HANDLE_RADIUS_SCALE_ACCESSIBILITY_DISABLED * mUnlockHalo.getWidth();
+ }
+ }
+
+ /**
+ * Announces the unlock handle if accessibility is enabled.
+ */
+ private void announceUnlockHandle() {
+ setContentDescription(mContext.getString(R.string.description_target_unlock_tablet));
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ setContentDescription(null);
+ }
+
+ /**
* Triggers haptic feedback.
*/
private synchronized void vibrate(long duration) {