diff options
48 files changed, 1335 insertions, 515 deletions
diff --git a/api/current.txt b/api/current.txt index 2514efd..a71c866 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1828,6 +1828,7 @@ package android.accessibilityservice { method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; field public static final int DEFAULT = 1; // 0x1 + field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff field public static final int FEEDBACK_AUDIBLE = 4; // 0x4 field public static final int FEEDBACK_GENERIC = 16; // 0x10 field public static final int FEEDBACK_HAPTIC = 2; // 0x2 @@ -16710,7 +16711,7 @@ package android.provider { field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype"; field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname"; field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version"; - field public static final java.lang.String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested"; + field public static final java.lang.String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled"; field public static final java.lang.String TTS_DEFAULT_COUNTRY = "tts_default_country"; field public static final java.lang.String TTS_DEFAULT_LANG = "tts_default_lang"; field public static final java.lang.String TTS_DEFAULT_PITCH = "tts_default_pitch"; @@ -17951,7 +17952,7 @@ package android.service.textservice { method public abstract android.view.textservice.SuggestionsInfo getSuggestions(android.view.textservice.TextInfo, int, java.lang.String); method public android.view.textservice.SuggestionsInfo[] getSuggestionsMultiple(android.view.textservice.TextInfo[], java.lang.String, int, boolean); method public final android.os.IBinder onBind(android.content.Intent); - field public static final java.lang.String SERVICE_INTERFACE; + field public static final java.lang.String SERVICE_INTERFACE = "android.service.textservice.SpellCheckerService"; } public class SpellCheckerSession { @@ -22232,6 +22233,7 @@ package android.view { method public final android.view.View findViewWithTag(java.lang.Object); method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence); method protected boolean fitSystemWindows(android.graphics.Rect); + method public boolean fitsSystemWindows(); method public android.view.View focusSearch(int); method public void forceLayout(); method public float getAlpha(); @@ -22473,6 +22475,7 @@ package android.view { method public void setEnabled(boolean); method public void setFadingEdgeLength(int); method public void setFilterTouchesWhenObscured(boolean); + method public void setFitsSystemWindows(boolean); method public void setFocusable(boolean); method public void setFocusableInTouchMode(boolean); method public void setHapticFeedbackEnabled(boolean); @@ -24055,6 +24058,8 @@ package android.view.textservice { method public android.content.ComponentName getComponent(); method public java.lang.String getId(); method public java.lang.String getPackageName(); + method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); + method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } @@ -26196,7 +26201,7 @@ package android.widget { method public int timePassed(); } - public class SearchView extends android.widget.LinearLayout { + public class SearchView extends android.widget.LinearLayout implements android.view.CollapsibleActionView { ctor public SearchView(android.content.Context); ctor public SearchView(android.content.Context, android.util.AttributeSet); method public java.lang.CharSequence getQuery(); @@ -26205,6 +26210,8 @@ package android.widget { method public boolean isIconified(); method public boolean isQueryRefinementEnabled(); method public boolean isSubmitButtonEnabled(); + method public void onActionViewCollapsed(); + method public void onActionViewExpanded(); method public void setIconified(boolean); method public void setIconifiedByDefault(boolean); method public void setMaxWidth(int); diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index a09607a..41a3eac 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -75,6 +75,17 @@ public class AccessibilityServiceInfo implements Parcelable { public static final int FEEDBACK_GENERIC = 0x0000010; /** + * Mask for all feedback types. + * + * @see #FEEDBACK_SPOKEN + * @see #FEEDBACK_HAPTIC + * @see #FEEDBACK_AUDIBLE + * @see #FEEDBACK_VISUAL + * @see #FEEDBACK_GENERIC + */ + public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF; + + /** * If an {@link AccessibilityService} is the default for a given type. * Default service is invoked only if no package specific one exists. In case of * more than one package specific service only the earlier registered is notified. diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java index d4e5cc1..b32664e 100644 --- a/core/java/android/content/pm/Signature.java +++ b/core/java/android/content/pm/Signature.java @@ -45,16 +45,23 @@ public class Signature implements Parcelable { * {@link #toChars} or {@link #toCharsString()}. */ public Signature(String text) { - final int N = text.length()/2; - byte[] sig = new byte[N]; - for (int i=0; i<N; i++) { - char c = text.charAt(i*2); - byte b = (byte)( - (c >= 'a' ? (c - 'a' + 10) : (c - '0'))<<4); - c = text.charAt(i*2 + 1); - b |= (byte)(c >= 'a' ? (c - 'a' + 10) : (c - '0')); - sig[i] = b; + final byte[] input = text.getBytes(); + final int N = input.length; + final byte[] sig = new byte[N / 2]; + int sigIndex = 0; + + for (int i = 0; i < N;) { + int b; + + final int hi = input[i++]; + b = (hi >= 'a' ? (hi - 'a' + 10) : (hi - '0')) << 4; + + final int lo = input[i++]; + b |= (lo >= 'a' ? (lo - 'a' + 10) : (lo - '0')) & 0x0F; + + sig[sigIndex++] = (byte) (b & 0xFF); } + mSignature = sig; } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 382fcf3..e23d6f3 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -184,6 +184,16 @@ public class CallLog { public static final String VOICEMAIL_URI = "voicemail_uri"; /** + * Whether this item has been read or otherwise consumed by the user. + * <p> + * Unlike the {@link #NEW} field, which requires the user to have acknowledged the + * existence of the entry, this implies the user has interacted with the entry. + * <P>Type: INTEGER (boolean)</P> + * @hide + */ + public static final String IS_READ = "is_read"; + + /** * Adds a call to the call log. * * @param ci the CallerInfo object to get the target contact from. Can be null diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 4a719ec..a0f1eec 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -6514,6 +6514,32 @@ public final class ContactsContract { public static final String SUMMARY_COUNT = "summ_count"; /** + * A boolean query parameter that can be used with {@link Groups#CONTENT_SUMMARY_URI}. + * It will additionally return {@link #SUMMARY_GROUP_COUNT_PER_ACCOUNT}. + * + * @hide + */ + public static final String PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT = + "return_group_count_per_account"; + + /** + * The total number of groups of the account that a group belongs to. + * This column is available only when the parameter + * {@link #PARAM_RETURN_GROUP_COUNT_PER_ACCOUNT} is specified in + * {@link Groups#CONTENT_SUMMARY_URI}. + * + * For example, when the account "A" has two groups "group1" and "group2", and the account + * "B" has a group "group3", the rows for "group1" and "group2" return "2" and the row for + * "group3" returns "1" for this column. + * + * Note: This counts only non-favorites, non-auto-add, and not deleted groups. + * + * Type: INTEGER + * @hide + */ + public static final String SUMMARY_GROUP_COUNT_PER_ACCOUNT = "group_count_per_account"; + + /** * The total number of {@link Contacts} that have both * {@link CommonDataKinds.GroupMembership} in this group, and also have phone numbers. * Read-only value that is only present when querying diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1cd46de..cd4e32e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2688,11 +2688,9 @@ public final class Settings { public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled"; /** - * If touch exploration is requested. Touch exploration is enabled if it is - * requested by this setting, accessibility is enabled and there is at least - * one enabled accessibility serivce that provides spoken feedback. + * If touch exploration is enabled. */ - public static final String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested"; + public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled"; /** * List of the enabled accessibility providers. @@ -3935,6 +3933,10 @@ public final class Settings { /** Timeout in milliseconds to wait for NTP server. {@hide} */ public static final String NTP_TIMEOUT = "ntp_timeout"; + /** Autofill server address (Used in WebView/browser). {@hide} */ + public static final String WEB_AUTOFILL_QUERY_URL = + "web_autofill_query_url"; + /** * @hide */ diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java index 2ad7395..2e5a495 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -128,6 +128,12 @@ public class VoicemailContract { */ public static final String NEW = Calls.NEW; /** + * Whether this item has been read or otherwise consumed by the user. + * <P>Type: INTEGER (boolean)</P> + * @hide + */ + public static final String IS_READ = Calls.IS_READ; + /** * The mail box state of the voicemail. This field is currently not used by the system. * <P> Possible values: {@link #STATE_INBOX}, {@link #STATE_DELETED}, * {@link #STATE_UNDELETED}. diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java new file mode 100644 index 0000000..ae91465 --- /dev/null +++ b/core/java/android/server/BluetoothAdapterStateMachine.java @@ -0,0 +1,513 @@ +/* + * 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 android.server; + +import android.bluetooth.BluetoothAdapter; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.Message; +import android.provider.Settings; +import android.util.Log; + +import com.android.internal.util.IState; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; + +import java.io.PrintWriter; + +/** + * Bluetooth Adapter StateMachine + * All the states are at the same level, ie, no hierarchy. + * (BluetootOn) + * | ^ + * TURN_OFF | | BECOME_PAIRABLE + * AIRPLANE_MODE_ON | | + * V | + * (Switching) + * | ^ + * BECOME_NON_PAIRABLE& | | TURN_ON(_CONTINUE)/TURN_ON_FOR_PRIVILEGED + * ALL_DEVICES_DISCONNECTED | | + * V | + * (HotOff) + * / ^ + * / | SERVICE_RECORD_LOADED + * | | + * TURN_COLD | (Warmup) + * \ ^ + * \ | TURN_HOT/TURN_ON + * | | AIRPLANE_MODE_OFF(when Bluetooth was on before) + * V | + * (PowerOff) <----- initial state + * + */ +final class BluetoothAdapterStateMachine extends StateMachine { + private static final String TAG = "BluetoothAdapterStateMachine"; + private static final boolean DBG = false; + + // Message(what) to take an action + // + // We get this message when user tries to turn on BT + public static final int USER_TURN_ON = 1; + // We get this message when user tries to turn off BT + public static final int USER_TURN_OFF = 2; + + // Message(what) to report a event that the state machine need to respond to + // + // Event indicates sevice records have been loaded + public static final int SERVICE_RECORD_LOADED = 51; + // Event indicates all the remote Bluetooth devices has been disconnected + public static final int ALL_DEVICES_DISCONNECTED = 52; + // Event indicates the Bluetooth is connectable + public static final int BECOME_PAIRABLE = 53; + // Event indicates the Bluetooth is non-connectable. + public static final int BECOME_NON_PAIRABLE = 54; + // Event indicates airplane mode is turned on + public static final int AIRPLANE_MODE_ON = 55; + // Event indicates airplane mode is turned off + public static final int AIRPLANE_MODE_OFF = 56; + + // private internal messages + // + // Turn on Bluetooth Module, Load firmware, and do all the preparation + // needed to get the Bluetooth Module ready but keep it not discoverable + // and not connectable. This way the Bluetooth Module can be quickly + // switched on if needed + private static final int TURN_HOT = 101; + // USER_TURN_ON is changed to TURN_ON_CONTINUE after we broadcast the + // state change intent so that we will not broadcast the intent again in + // other state + private static final int TURN_ON_CONTINUE = 102; + // Unload firmware, turning off Bluetooth module power + private static final int TURN_COLD = 103; + // For NFC, turn on bluetooth for certain process + private static final int TURN_ON_FOR_PRIVILEGED = 104; + + private Context mContext; + private BluetoothService mBluetoothService; + private BluetoothEventLoop mEventLoop; + + private BluetoothOn mBluetoothOn; + private Switching mSwitching; + private HotOff mHotOff; + private WarmUp mWarmUp; + private PowerOff mPowerOff; + + // this is the BluetoothAdapter state that reported externally + private int mPublicState; + + BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService, + BluetoothAdapter bluetoothAdapter) { + super(TAG); + mContext = context; + mBluetoothService = bluetoothService; + mEventLoop = new BluetoothEventLoop(context, bluetoothAdapter, bluetoothService, this); + + mBluetoothOn = new BluetoothOn(); + mSwitching = new Switching(); + mHotOff = new HotOff(); + mWarmUp = new WarmUp(); + mPowerOff = new PowerOff(); + + addState(mBluetoothOn); + addState(mSwitching); + addState(mHotOff); + addState(mWarmUp); + addState(mPowerOff); + setInitialState(mPowerOff); + mPublicState = BluetoothAdapter.STATE_OFF; + + if (mContext.getResources().getBoolean + (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { + sendMessage(TURN_HOT); + } + } + + /** + * Bluetooth module's power is off, firmware is not loaded. + */ + private class PowerOff extends State { + private boolean mPersistSwitchOn = false; + + @Override + public void enter() { + if (DBG) log("Enter PowerOff: " + mPersistSwitchOn); + mPersistSwitchOn = false; + } + @Override + public boolean processMessage(Message message) { + if (DBG) log("PowerOff process message: " + message.what); + + boolean retValue = HANDLED; + switch(message.what) { + case USER_TURN_ON: + // starts turning on BT module, broadcast this out + transitionTo(mWarmUp); + broadcastState(BluetoothAdapter.STATE_TURNING_ON); + if (prepareBluetooth()) { + // this is user request, save the setting + if ((Boolean) message.obj) { + mPersistSwitchOn = true; + } + // We will continue turn the BT on all the way to the BluetoothOn state + deferMessage(obtainMessage(TURN_ON_CONTINUE)); + } else { + Log.e(TAG, "failed to prepare bluetooth, abort turning on"); + transitionTo(mPowerOff); + broadcastState(BluetoothAdapter.STATE_OFF); + } + break; + case TURN_HOT: + if (prepareBluetooth()) { + transitionTo(mWarmUp); + } + break; + case AIRPLANE_MODE_OFF: + if (getBluetoothPersistedSetting()) { + // starts turning on BT module, broadcast this out + transitionTo(mWarmUp); + broadcastState(BluetoothAdapter.STATE_TURNING_ON); + if (prepareBluetooth()) { + // We will continue turn the BT on all the way to the BluetoothOn state + deferMessage(obtainMessage(TURN_ON_CONTINUE)); + transitionTo(mWarmUp); + } else { + Log.e(TAG, "failed to prepare bluetooth, abort turning on"); + transitionTo(mPowerOff); + broadcastState(BluetoothAdapter.STATE_OFF); + } + } + break; + case AIRPLANE_MODE_ON: // ignore + case USER_TURN_OFF: // ignore + break; + default: + return NOT_HANDLED; + } + return retValue; + } + + /** + * Turn on Bluetooth Module, Load firmware, and do all the preparation + * needed to get the Bluetooth Module ready but keep it not discoverable + * and not connectable. + * The last step of this method sets up the local service record DB. + * There will be a event reporting the status of the SDP setup. + */ + private boolean prepareBluetooth() { + if (mBluetoothService.enableNative() != 0) { + return false; + } + + // try to start event loop, give 2 attempts + int retryCount = 2; + boolean eventLoopStarted = false; + while ((retryCount-- > 0) && !eventLoopStarted) { + mEventLoop.start(); + // it may take a moment for the other thread to do its + // thing. Check periodically for a while. + int pollCount = 5; + while ((pollCount-- > 0) && !eventLoopStarted) { + if (mEventLoop.isEventLoopRunning()) { + eventLoopStarted = true; + break; + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + break; + } + } + } + + if (!eventLoopStarted) { + mBluetoothService.disableNative(); + return false; + } + + // get BluetoothService ready + if (!mBluetoothService.prepareBluetooth()) { + mEventLoop.stop(); + mBluetoothService.disableNative(); + return false; + } + + return true; + } + } + + /** + * Turning on Bluetooth module's power, loading firmware, starting + * event loop thread to listen on Bluetooth module event changes. + */ + private class WarmUp extends State { + + @Override + public void enter() { + if (DBG) log("Enter WarmUp"); + } + + @Override + public boolean processMessage(Message message) { + if (DBG) log("WarmUp process message: " + message.what); + + boolean retValue = HANDLED; + switch(message.what) { + case SERVICE_RECORD_LOADED: + transitionTo(mHotOff); + break; + case USER_TURN_ON: // handle this at HotOff state + case TURN_ON_CONTINUE: // Once in HotOff state, continue turn bluetooth + // on to the BluetoothOn state + case AIRPLANE_MODE_ON: + case AIRPLANE_MODE_OFF: + deferMessage(message); + break; + case USER_TURN_OFF: // ignore + break; + default: + return NOT_HANDLED; + } + return retValue; + } + + } + + /** + * Bluetooth Module has powered, firmware loaded, event loop started, + * SDP loaded, but the modules stays non-discoverable and + * non-connectable. + */ + private class HotOff extends State { + private boolean mPersistSwitchOn = false; + + @Override + public void enter() { + if (DBG) log("Enter HotOff: " + mPersistSwitchOn); + mPersistSwitchOn = false; + } + + @Override + public boolean processMessage(Message message) { + if (DBG) log("HotOff process message: " + message.what); + + boolean retValue = HANDLED; + switch(message.what) { + case USER_TURN_ON: + if ((Boolean) message.obj) { + mPersistSwitchOn = true; + } + // let it fall to TURN_ON_CONTINUE: + case TURN_ON_CONTINUE: + mBluetoothService.switchConnectable(true); + transitionTo(mSwitching); + broadcastState(BluetoothAdapter.STATE_TURNING_ON); + break; + case AIRPLANE_MODE_ON: + case TURN_COLD: + mBluetoothService.shutoffBluetooth(); + mEventLoop.stop(); + transitionTo(mPowerOff); + // ASSERT no support of config_bluetooth_adapter_quick_switch + broadcastState(BluetoothAdapter.STATE_OFF); + break; + case AIRPLANE_MODE_OFF: + if (getBluetoothPersistedSetting()) { + mBluetoothService.switchConnectable(true); + transitionTo(mSwitching); + broadcastState(BluetoothAdapter.STATE_TURNING_ON); + } + break; + case USER_TURN_OFF: // ignore + break; + default: + return NOT_HANDLED; + } + return retValue; + } + + } + + private class Switching extends State { + + @Override + public void enter() { + int what = getCurrentMessage().what; + if (DBG) log("Enter Switching: " + what); + } + @Override + public boolean processMessage(Message message) { + if (DBG) log("Switching process message: " + message.what); + + boolean retValue = HANDLED; + switch(message.what) { + case BECOME_PAIRABLE: + if (mPowerOff.mPersistSwitchOn || mHotOff.mPersistSwitchOn) { + persistSwitchSetting(true); + mPowerOff.mPersistSwitchOn = mHotOff.mPersistSwitchOn = false; + } + String[] propVal = {"Pairable", mBluetoothService.getProperty("Pairable")}; + mEventLoop.onPropertyChanged(propVal); + + // run bluetooth now that it's turned on + mBluetoothService.runBluetooth(); + transitionTo(mBluetoothOn); + broadcastState(BluetoothAdapter.STATE_ON); + break; + case BECOME_NON_PAIRABLE: + if (mBluetoothService.getAdapterConnectionState() == + BluetoothAdapter.STATE_DISCONNECTED) { + transitionTo(mHotOff); + finishSwitchingOff(); + } + break; + case ALL_DEVICES_DISCONNECTED: + if (mBluetoothService.getScanMode() == BluetoothAdapter.SCAN_MODE_NONE) { + transitionTo(mHotOff); + finishSwitchingOff(); + } + break; + case USER_TURN_ON: + case AIRPLANE_MODE_OFF: + case AIRPLANE_MODE_ON: + case USER_TURN_OFF: + deferMessage(message); + break; + default: + return NOT_HANDLED; + } + return retValue; + } + + private void finishSwitchingOff() { + if (mBluetoothOn.mPersistBluetoothOff) { + persistSwitchSetting(false); + mBluetoothOn.mPersistBluetoothOff = false; + } + mBluetoothService.finishDisable(); + if (mContext.getResources().getBoolean + (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) { + broadcastState(BluetoothAdapter.STATE_OFF); + } else { + deferMessage(obtainMessage(TURN_COLD)); + } + } + } + + private class BluetoothOn extends State { + private boolean mPersistBluetoothOff = false; + + @Override + public void enter() { + if (DBG) log("Enter BluetoothOn: " + mPersistBluetoothOff); + mPersistBluetoothOff = false; + } + @Override + public boolean processMessage(Message message) { + if (DBG) log("BluetoothOn process message: " + message.what); + + boolean retValue = HANDLED; + switch(message.what) { + case USER_TURN_OFF: + if ((Boolean) message.obj) { + mPersistBluetoothOff = true; + } + // let it fall through to AIRPLANE_MODE_ON + case AIRPLANE_MODE_ON: + transitionTo(mSwitching); + broadcastState(BluetoothAdapter.STATE_TURNING_OFF); + mBluetoothService.switchConnectable(false); + mBluetoothService.disconnectDevices(); + // we turn all the way to PowerOff with AIRPLANE_MODE_ON + if (message.what == AIRPLANE_MODE_ON) { + deferMessage(obtainMessage(AIRPLANE_MODE_ON)); + } + break; + case AIRPLANE_MODE_OFF: // ignore + case USER_TURN_ON: // ignore + break; + default: + return NOT_HANDLED; + } + return retValue; + } + + } + + /** + * Return the public BluetoothAdapter state + */ + int getBluetoothAdapterState() { + return mPublicState; + } + + BluetoothEventLoop getBluetoothEventLoop() { + return mEventLoop; + } + + private void persistSwitchSetting(boolean setOn) { + long origCallerIdentityToken = Binder.clearCallingIdentity(); + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.BLUETOOTH_ON, + setOn ? 1 : 0); + Binder.restoreCallingIdentity(origCallerIdentityToken); + } + + private boolean getBluetoothPersistedSetting() { + ContentResolver contentResolver = mContext.getContentResolver(); + return (Settings.Secure.getInt(contentResolver, + Settings.Secure.BLUETOOTH_ON, 0) > 0); + } + + private void broadcastState(int newState) { + + if (DBG) log("Bluetooth state " + mPublicState + " -> " + newState); + if (mPublicState == newState) { + return; + } + + Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); + intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mPublicState); + intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + mPublicState = newState; + + mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM); + } + + private void dump(PrintWriter pw) { + IState currentState = getCurrentState(); + if (currentState == mPowerOff) { + pw.println("Bluetooth OFF - power down\n"); + } else if (currentState == mWarmUp) { + pw.println("Bluetooth OFF - warm up\n"); + } else if (currentState == mHotOff) { + pw.println("Bluetooth OFF - hot but off\n"); + } else if (currentState == mSwitching) { + pw.println("Bluetooth Switching\n"); + } else if (currentState == mBluetoothOn) { + pw.println("Bluetooth ON\n"); + } else { + pw.println("ERROR: Bluetooth UNKNOWN STATE "); + } + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +} diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index f345a6a..107a2a9 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -52,6 +52,7 @@ class BluetoothEventLoop { private final HashMap<String, Integer> mAuthorizationAgentRequestData; private final BluetoothService mBluetoothService; private final BluetoothAdapter mAdapter; + private final BluetoothAdapterStateMachine mBluetoothState; private BluetoothA2dp mA2dp; private BluetoothInputDevice mInputDevice; private final Context mContext; @@ -107,9 +108,11 @@ class BluetoothEventLoop { private static native void classInitNative(); /* package */ BluetoothEventLoop(Context context, BluetoothAdapter adapter, - BluetoothService bluetoothService) { + BluetoothService bluetoothService, + BluetoothAdapterStateMachine bluetoothState) { mBluetoothService = bluetoothService; mContext = context; + mBluetoothState = bluetoothState; mPasskeyAgentRequestData = new HashMap<String, Integer>(); mAuthorizationAgentRequestData = new HashMap<String, Integer>(); mAdapter = adapter; @@ -299,8 +302,8 @@ class BluetoothEventLoop { /** * Called by native code on a PropertyChanged signal from - * org.bluez.Adapter. This method is also called from Java at - * {@link BluetoothService.EnableThread#run()} to set the "Pairable" + * org.bluez.Adapter. This method is also called from + * {@link BluetoothAdapterStateMachine} to set the "Pairable" * property when Bluetooth is enabled. * * @param propValues a string array containing the key and one or more @@ -334,6 +337,15 @@ class BluetoothEventLoop { return; adapterProperties.setProperty(name, propValues[1]); + + if (name.equals("Pairable")) { + if (pairable.equals("true")) { + mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECOME_PAIRABLE); + } else { + mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECOME_NON_PAIRABLE); + } + } + int mode = BluetoothService.bluezStringToScanMode( pairable.equals("true"), discoverable.equals("true")); diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index d68d8ba..34f1971 100755 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -91,7 +91,7 @@ public class BluetoothService extends IBluetooth.Stub { private BluetoothPan mPan; private boolean mIsAirplaneSensitive; private boolean mIsAirplaneToggleable; - private int mBluetoothState; + private BluetoothAdapterStateMachine mBluetoothState; private boolean mRestart = false; // need to call enable() after disable() private boolean mIsDiscovering; private int[] mAdapterSdpHandles; @@ -111,9 +111,8 @@ public class BluetoothService extends IBluetooth.Stub { private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address"; private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings"; - private static final int MESSAGE_FINISH_DISABLE = 1; - private static final int MESSAGE_UUID_INTENT = 2; - private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3; + private static final int MESSAGE_UUID_INTENT = 1; + private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 2; // The time (in millisecs) to delay the pairing attempt after the first // auto pairing attempt fails. We use an exponential delay with @@ -206,7 +205,6 @@ public class BluetoothService extends IBluetooth.Stub { disableNative(); } - mBluetoothState = BluetoothAdapter.STATE_OFF; mIsDiscovering = false; mBondState = new BluetoothBondState(context, this); @@ -306,7 +304,9 @@ public class BluetoothService extends IBluetooth.Stub { public synchronized void initAfterRegistration() { mAdapter = BluetoothAdapter.getDefaultAdapter(); - mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this); + mBluetoothState = new BluetoothAdapterStateMachine(mContext, this, mAdapter); + mBluetoothState.start(); + mEventLoop = mBluetoothState.getBluetoothEventLoop(); } public synchronized void initAfterA2dpRegistration() { @@ -329,16 +329,16 @@ public class BluetoothService extends IBluetooth.Stub { } private boolean isEnabledInternal() { - return mBluetoothState == BluetoothAdapter.STATE_ON; + return (getBluetoothStateInternal() == BluetoothAdapter.STATE_ON); } public int getBluetoothState() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - return mBluetoothState; + return getBluetoothStateInternal(); } int getBluetoothStateInternal() { - return mBluetoothState; + return mBluetoothState.getBluetoothAdapterState(); } /** @@ -356,7 +356,9 @@ public class BluetoothService extends IBluetooth.Stub { public synchronized boolean disable(boolean saveSetting) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); - switch (mBluetoothState) { + int adapterState = getBluetoothStateInternal(); + + switch (adapterState) { case BluetoothAdapter.STATE_OFF: return true; case BluetoothAdapter.STATE_ON: @@ -364,27 +366,12 @@ public class BluetoothService extends IBluetooth.Stub { default: return false; } - if (mEnableThread != null && mEnableThread.isAlive()) { - return false; - } - - setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF); - - if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles); - setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE, - BluetoothPanProfileHandler.NAP_BRIDGE); - - // Allow 3 seconds for profiles to gracefully disconnect - // TODO: Introduce a callback mechanism so that each profile can notify - // BluetoothService when it is done shutting down - disconnectDevices(); - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000); + mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_OFF, saveSetting); return true; } - private synchronized void disconnectDevices() { + synchronized void disconnectDevices() { // Disconnect devices handled by BluetoothService. for (BluetoothDevice device: getConnectedInputDevices()) { disconnectInputDevice(device); @@ -395,14 +382,11 @@ public class BluetoothService extends IBluetooth.Stub { } } - private synchronized void finishDisable(boolean saveSetting) { - if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) { - return; - } - mEventLoop.stop(); - tearDownNativeDataNative(); - disableNative(); - + /** + * The Bluetooth has been turned off, but hot. Do bonding, profile, + * and internal cleanup + */ + synchronized void finishDisable() { // mark in progress bondings as cancelled for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) { mBondState.setBondState(address, BluetoothDevice.BOND_NONE, @@ -430,12 +414,6 @@ public class BluetoothService extends IBluetooth.Stub { mAdapterUuids = null; mAdapterSdpHandles = null; - if (saveSetting) { - persistBluetoothOnSetting(false); - } - - setBluetoothState(BluetoothAdapter.STATE_OFF); - // Log bluetooth off to battery stats. long ident = Binder.clearCallingIdentity(); try { @@ -451,6 +429,18 @@ public class BluetoothService extends IBluetooth.Stub { } } + /** + * power off Bluetooth + */ + synchronized void shutoffBluetooth() { + tearDownNativeDataNative(); + disableNative(); + if (mRestart) { + mRestart = false; + enable(); + } + } + /** Bring up BT and persist BT on in settings */ public boolean enable() { return enable(true); @@ -471,21 +461,29 @@ public class BluetoothService extends IBluetooth.Stub { if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { return false; } - if (mBluetoothState != BluetoothAdapter.STATE_OFF) { - return false; - } - if (mEnableThread != null && mEnableThread.isAlive()) { + mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting); + return true; + } + + /** + * Turn on Bluetooth Module, Load firmware, and do all the preparation + * needed to get the Bluetooth Module ready but keep it not discoverable + * and not connectable. + */ + /* package */ synchronized boolean prepareBluetooth() { + if (!setupNativeDataNative()) { return false; } - setBluetoothState(BluetoothAdapter.STATE_TURNING_ON); - mEnableThread = new EnableThread(saveSetting); - mEnableThread.start(); + mIsDiscovering = false; + + switchConnectable(false); + updateSdpRecords(); return true; } /** Forcibly restart Bluetooth if it is on */ /* package */ synchronized void restart() { - if (mBluetoothState != BluetoothAdapter.STATE_ON) { + if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) { return; } mRestart = true; @@ -494,30 +492,10 @@ public class BluetoothService extends IBluetooth.Stub { } } - private synchronized void setBluetoothState(int state) { - if (state == mBluetoothState) { - return; - } - - if (DBG) Log.d(TAG, "Bluetooth state " + mBluetoothState + " -> " + state); - - Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); - intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState); - intent.putExtra(BluetoothAdapter.EXTRA_STATE, state); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - - mBluetoothState = state; - - mContext.sendBroadcast(intent, BLUETOOTH_PERM); - } - private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MESSAGE_FINISH_DISABLE: - finishDisable(msg.arg1 != 0); - break; case MESSAGE_UUID_INTENT: String address = (String)msg.obj; if (address != null) { @@ -545,65 +523,6 @@ public class BluetoothService extends IBluetooth.Stub { } }; - private EnableThread mEnableThread; - - private class EnableThread extends Thread { - private final boolean mSaveSetting; - public EnableThread(boolean saveSetting) { - mSaveSetting = saveSetting; - } - public void run() { - boolean res = (enableNative() == 0); - if (res) { - int retryCount = 2; - boolean running = false; - while ((retryCount-- > 0) && !running) { - mEventLoop.start(); - // it may take a moment for the other thread to do its - // thing. Check periodically for a while. - int pollCount = 5; - while ((pollCount-- > 0) && !running) { - if (mEventLoop.isEventLoopRunning()) { - running = true; - break; - } - try { - Thread.sleep(100); - } catch (InterruptedException e) {} - } - } - if (!running) { - Log.e(TAG, "bt EnableThread giving up"); - res = false; - disableNative(); - } - } - - if (res) { - if (!setupNativeDataNative()) { - return; - } - if (mSaveSetting) { - persistBluetoothOnSetting(true); - } - - mIsDiscovering = false; - mBondState.readAutoPairingData(); - mBondState.initBondState(); - initProfileState(); - - // This should be the last step of the the enable thread. - // Because this adds SDP records which asynchronously - // broadcasts the Bluetooth On State in updateBluetoothState. - // So we want all internal state setup before this. - updateSdpRecords(); - } else { - setBluetoothState(BluetoothAdapter.STATE_OFF); - } - mEnableThread = null; - } - } - private synchronized void addReservedSdpRecords(final ArrayList<ParcelUuid> uuids) { //Register SDP records. int[] svcIdentifiers = new int[uuids.size()]; @@ -650,38 +569,37 @@ public class BluetoothService extends IBluetooth.Stub { * for adapter comes in with UUID property. * @param uuidsThe uuids of adapter as reported by Bluez. */ - synchronized void updateBluetoothState(String uuids) { - if (mBluetoothState == BluetoothAdapter.STATE_TURNING_ON) { - ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids); - - if (mAdapterUuids != null && - BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) { - setBluetoothState(BluetoothAdapter.STATE_ON); - autoConnect(); - String[] propVal = {"Pairable", getProperty("Pairable")}; - mEventLoop.onPropertyChanged(propVal); - - // Log bluetooth on to battery stats. - long ident = Binder.clearCallingIdentity(); - try { - mBatteryStats.noteBluetoothOn(); - } catch (RemoteException e) { - } finally { - Binder.restoreCallingIdentity(ident); - } + /*package*/ synchronized void updateBluetoothState(String uuids) { + ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids); - if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) { - disable(false); - } - } + if (mAdapterUuids != null && + BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) { + mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED); } } - private void persistBluetoothOnSetting(boolean bluetoothOn) { - long origCallerIdentityToken = Binder.clearCallingIdentity(); - Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON, - bluetoothOn ? 1 : 0); - Binder.restoreCallingIdentity(origCallerIdentityToken); + /** + * This method is called immediately after Bluetooth module is turned on. + * It starts auto-connection and places bluetooth on sign onto the battery + * stats + */ + /*package*/ void runBluetooth() { + mIsDiscovering = false; + mBondState.readAutoPairingData(); + mBondState.initBondState(); + initProfileState(); + + autoConnect(); + + // Log bluetooth on to battery stats. + long ident = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteBluetoothOn(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } finally { + Binder.restoreCallingIdentity(ident); + } } /*package*/ synchronized boolean attemptAutoPair(String address) { @@ -818,6 +736,26 @@ public class BluetoothService extends IBluetooth.Stub { public synchronized boolean setScanMode(int mode, int duration) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS, "Need WRITE_SECURE_SETTINGS permission"); + return setScanMode(mode, duration, true); + } + + /** + * @param on true set the local Bluetooth module to be connectable + * but not dicoverable + * false set the local Bluetooth module to be not connectable + * and not dicoverable + */ + /*package*/ synchronized void switchConnectable(boolean on) { + if (on) { + // 0 is a dummy value, does not apply for SCAN_MODE_CONNECTABLE + setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, 0, false); + } else { + // 0 is a dummy value, does not apply for SCAN_MODE_NONE + setScanMode(BluetoothAdapter.SCAN_MODE_NONE, 0, false); + } + } + + private synchronized boolean setScanMode(int mode, int duration, boolean allowOnlyInOnState) { boolean pairable; boolean discoverable; @@ -839,9 +777,15 @@ public class BluetoothService extends IBluetooth.Stub { Log.w(TAG, "Requested invalid scan mode " + mode); return false; } - setPropertyBoolean("Pairable", pairable); - setPropertyBoolean("Discoverable", discoverable); + if (allowOnlyInOnState) { + setPropertyBoolean("Pairable", pairable); + setPropertyBoolean("Discoverable", discoverable); + } else { + // allowed to set the property through native layer directly + setAdapterPropertyBooleanNative("Pairable", pairable ? 1 : 0); + setAdapterPropertyBooleanNative("Discoverable", discoverable ? 1 : 0); + } return true; } @@ -1569,14 +1513,10 @@ public class BluetoothService extends IBluetooth.Stub { ContentResolver resolver = context.getContentResolver(); // Query the airplane mode from Settings.System just to make sure that // some random app is not sending this intent and disabling bluetooth - boolean enabled = !isAirplaneModeOn(); - // If bluetooth is currently expected to be on, then enable or disable bluetooth - if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) { - if (enabled) { - enable(false); - } else { - disable(false); - } + if (isAirplaneModeOn()) { + mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_ON); + } else { + mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_OFF); } } else if (Intent.ACTION_DOCK_EVENT.equals(action)) { int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, @@ -1650,8 +1590,7 @@ public class BluetoothService extends IBluetooth.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - dumpBluetoothState(pw); - if (mBluetoothState != BluetoothAdapter.STATE_ON) { + if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) { return; } @@ -1840,25 +1779,6 @@ public class BluetoothService extends IBluetooth.Stub { } } - private void dumpBluetoothState(PrintWriter pw) { - switch(mBluetoothState) { - case BluetoothAdapter.STATE_OFF: - pw.println("Bluetooth OFF\n"); - break; - case BluetoothAdapter.STATE_TURNING_ON: - pw.println("Bluetooth TURNING ON\n"); - break; - case BluetoothAdapter.STATE_TURNING_OFF: - pw.println("Bluetooth TURNING OFF\n"); - break; - case BluetoothAdapter.STATE_ON: - pw.println("Bluetooth ON\n"); - break; - default: - pw.println("Bluetooth UNKNOWN STATE " + mBluetoothState); - } - } - private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { @@ -2389,7 +2309,7 @@ public class BluetoothService extends IBluetooth.Stub { public synchronized void sendConnectionStateChange(BluetoothDevice device, int state, int prevState) { // Since this is a binder call check if Bluetooth is on still - if (mBluetoothState == BluetoothAdapter.STATE_OFF) return; + if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return; if (updateCountersAndCheckForConnectionStateChange(state, prevState)) { if (!validateProfileConnectionState(state) || @@ -2405,6 +2325,10 @@ public class BluetoothService extends IBluetooth.Stub { mAdapterConnectionState = state; + if (state == BluetoothProfile.STATE_DISCONNECTED) { + mBluetoothState.sendMessage(BluetoothAdapterStateMachine.ALL_DEVICES_DISCONNECTED); + } + Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, @@ -2598,8 +2522,8 @@ public class BluetoothService extends IBluetooth.Stub { /*package*/ native String getAdapterPathNative(); private native int isEnabledNative(); - private native int enableNative(); - private native int disableNative(); + /*package*/ native int enableNative(); + /*package*/ native int disableNative(); /*package*/ native Object[] getAdapterPropertiesNative(); private native Object[] getDevicePropertiesNative(String objectPath); diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java index 6ac99ca..270f512 100644 --- a/core/java/android/service/textservice/SpellCheckerService.java +++ b/core/java/android/service/textservice/SpellCheckerService.java @@ -36,7 +36,8 @@ import java.lang.ref.WeakReference; */ public abstract class SpellCheckerService extends Service { private static final String TAG = SpellCheckerService.class.getSimpleName(); - public static final String SERVICE_INTERFACE = SpellCheckerService.class.getName(); + public static final String SERVICE_INTERFACE = + "android.service.textservice.SpellCheckerService"; private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this); diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index c913bb3..836867b 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -161,6 +161,9 @@ public class Surface implements Parcelable { */ 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 + // mSurfaceControl to do the parceling. Otherwise we parcel the mNativeSurface. @SuppressWarnings("unused") private int mSurfaceControl; @SuppressWarnings("unused") @@ -202,6 +205,19 @@ public class Surface implements Parcelable { native private static void nativeClassInit(); static { nativeClassInit(); } + /** + * Create Surface from a SurfaceTexture. + * + * @param surfaceTexture The {@link SurfaceTexture} that is updated by this Surface. + * @hide + */ + public Surface(SurfaceTexture surfaceTexture) { + if (DEBUG_RELEASE) { + mCreationStack = new Exception(); + } + mCanvas = new CompatibleCanvas(); + initFromSurfaceTexture(surfaceTexture); + } /** * create a surface @@ -505,5 +521,7 @@ public class Surface implements Parcelable { private native void init(Parcel source); + private native void initFromSurfaceTexture(SurfaceTexture surfaceTexture); + private native int getIdentity(); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index c68b01c..dbb19e4 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4280,6 +4280,36 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit } /** + * Set whether or not this view should account for system screen decorations + * such as the status bar and inset its content. This allows this view to be + * positioned in absolute screen coordinates and remain visible to the user. + * + * <p>This should only be used by top-level window decor views. + * + * @param fitSystemWindows true to inset content for system screen decorations, false for + * default behavior. + * + * @attr ref android.R.styleable#View_fitsSystemWindows + */ + public void setFitsSystemWindows(boolean fitSystemWindows) { + setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); + } + + /** + * Check for the FITS_SYSTEM_WINDOWS flag. If this method returns true, this view + * will account for system screen decorations such as the status bar and inset its + * content. This allows the view to be positioned in absolute screen coordinates + * and remain visible to the user. + * + * @return true if this view will adjust its content bounds for system screen decorations. + * + * @attr ref android.R.styleable#View_fitsSystemWindows + */ + public boolean fitsSystemWindows() { + return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; + } + + /** * Returns the visibility status for this view. * * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 83c73cb..a80c2a7 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -67,13 +67,17 @@ public final class AccessibilityManager { private static final String LOG_TAG = "AccessibilityManager"; + /** @hide */ + public static final int STATE_FLAG_ACCESSIBILITY_ENABLED = 0x00000001; + + /** @hide */ + public static final int STATE_FLAG_TOUCH_EXPLORATION_ENABLED = 0x00000002; + static final Object sInstanceSync = new Object(); private static AccessibilityManager sInstance; - private static final int DO_SET_ACCESSIBILITY_ENABLED = 10; - - private static final int DO_SET_TOUCH_EXPLORATION_ENABLED = 20; + private static final int DO_SET_STATE = 10; final IAccessibilityManager mService; @@ -100,13 +104,8 @@ public final class AccessibilityManager { } final IAccessibilityManagerClient.Stub mClient = new IAccessibilityManagerClient.Stub() { - public void setEnabled(boolean enabled) { - mHandler.obtainMessage(DO_SET_ACCESSIBILITY_ENABLED, enabled ? 1 : 0, 0).sendToTarget(); - } - - public void setTouchExplorationEnabled(boolean enabled) { - mHandler.obtainMessage(DO_SET_TOUCH_EXPLORATION_ENABLED, - enabled ? 1 : 0, 0).sendToTarget(); + public void setState(int state) { + mHandler.obtainMessage(DO_SET_STATE, state, 0).sendToTarget(); } }; @@ -119,14 +118,8 @@ public final class AccessibilityManager { @Override public void handleMessage(Message message) { switch (message.what) { - case DO_SET_ACCESSIBILITY_ENABLED : - final boolean isAccessibilityEnabled = (message.arg1 == 1); - setAccessibilityState(isAccessibilityEnabled); - return; - case DO_SET_TOUCH_EXPLORATION_ENABLED : - synchronized (mHandler) { - mIsTouchExplorationEnabled = (message.arg1 == 1); - } + case DO_SET_STATE : + setState(message.arg1); return; default : Log.w(LOG_TAG, "Unknown message type: " + message.what); @@ -163,8 +156,8 @@ public final class AccessibilityManager { mService = service; try { - final boolean isEnabled = mService.addClient(mClient); - setAccessibilityState(isEnabled); + final int stateFlags = mService.addClient(mClient); + setState(stateFlags); } catch (RemoteException re) { Log.e(LOG_TAG, "AccessibilityManagerService is dead", re); } @@ -341,6 +334,17 @@ public final class AccessibilityManager { } /** + * Sets the current state. + * + * @param stateFlags The state flags. + */ + private void setState(int stateFlags) { + final boolean accessibilityEnabled = (stateFlags & STATE_FLAG_ACCESSIBILITY_ENABLED) != 0; + setAccessibilityState(accessibilityEnabled); + mIsTouchExplorationEnabled = (stateFlags & STATE_FLAG_TOUCH_EXPLORATION_ENABLED) != 0; + } + + /** * Sets the enabled state. * * @param isEnabled The accessibility state. diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 0e04471..6469b35 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -294,14 +294,14 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Gets the unique id identifying this node's parent. + * Gets the parent. * <p> * <strong>Note:</strong> It is a client responsibility to recycle the * received info by calling {@link AccessibilityNodeInfo#recycle()} * to avoid creating of multiple instances. * </p> * - * @return The node's patent id. + * @return The parent. */ public AccessibilityNodeInfo getParent() { enforceSealed(); diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index b14f02a..c621ff6 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -34,7 +34,7 @@ import android.view.IWindow; */ interface IAccessibilityManager { - boolean addClient(IAccessibilityManagerClient client); + int addClient(IAccessibilityManagerClient client); boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent); diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl index 4e69692..5e7e813 100644 --- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl @@ -24,7 +24,5 @@ package android.view.accessibility; */ oneway interface IAccessibilityManagerClient { - void setEnabled(boolean enabled); - - void setTouchExplorationEnabled(boolean enabled); + void setState(int stateFlags); } diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java index 1205adf..d88a39f 100644 --- a/core/java/android/view/textservice/SpellCheckerInfo.java +++ b/core/java/android/view/textservice/SpellCheckerInfo.java @@ -18,8 +18,10 @@ package android.view.textservice; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; @@ -103,6 +105,24 @@ public final class SpellCheckerInfo implements Parcelable { }; /** + * Load the user-displayed label for this spell checker. + * + * @param pm Supply a PackageManager used to load the spell checker's resources. + */ + public CharSequence loadLabel(PackageManager pm) { + return mService.loadLabel(pm); + } + + /** + * Load the user-displayed icon for this spell checker. + * + * @param pm Supply a PackageManager used to load the spell checker's resources. + */ + public Drawable loadIcon(PackageManager pm) { + return mService.loadIcon(pm); + } + + /** * Used to make this class parcelable. */ @Override diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java index 9749416..229b414 100644 --- a/core/java/android/view/textservice/TextServicesManager.java +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -97,4 +97,27 @@ public final class TextServicesManager { } return session; } + + /** + * @hide + */ + public SpellCheckerInfo[] getEnabledSpellCheckers() { + try { + return sService.getEnabledSpellCheckers(); + } catch (RemoteException e) { + return null; + } + } + + /** + * @hide + */ + public SpellCheckerInfo getCurrentSpellChecker() { + try { + // Passing null as a locale for ICS + return sService.getCurrentSpellChecker(null); + } catch (RemoteException e) { + return null; + } + } } diff --git a/core/java/android/webkit/JniUtil.java b/core/java/android/webkit/JniUtil.java index bb4d192..620973e 100644 --- a/core/java/android/webkit/JniUtil.java +++ b/core/java/android/webkit/JniUtil.java @@ -18,6 +18,7 @@ package android.webkit; import android.content.Context; import android.net.Uri; +import android.provider.Settings; import android.util.Log; import java.io.InputStream; @@ -38,7 +39,7 @@ class JniUtil { private static boolean initialized = false; - private static void checkIntialized() { + private static void checkInitialized() { if (!initialized) { throw new IllegalStateException("Call CookieSyncManager::createInstance() or create a webview before using this class"); } @@ -63,7 +64,7 @@ class JniUtil { * @return String The application's database directory */ private static synchronized String getDatabaseDirectory() { - checkIntialized(); + checkInitialized(); if (sDatabaseDirectory == null) sDatabaseDirectory = sContext.getDatabasePath("dummy").getParent(); @@ -76,7 +77,7 @@ class JniUtil { * @return String The application's cache directory */ private static synchronized String getCacheDirectory() { - checkIntialized(); + checkInitialized(); if (sCacheDirectory == null) sCacheDirectory = sContext.getCacheDir().getAbsolutePath(); @@ -166,5 +167,13 @@ class JniUtil { return sUseChromiumHttpStack; } + private static synchronized String getAutofillQueryUrl() { + checkInitialized(); + // If the device has not checked in it won't have pulled down the system setting for the + // Autofill Url. In that case we will not make autofill server requests. + return Settings.Secure.getString(sContext.getContentResolver(), + Settings.Secure.WEB_AUTOFILL_QUERY_URL); + } + private static native boolean nativeUseChromiumHttpStack(); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 6a3b2ff..e24ab58 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -4701,6 +4701,7 @@ public class WebView extends AbsoluteLayout private Message mUpdateMessage; private boolean mAutoFillable; private boolean mAutoComplete; + private WebSettings mWebSettings; public RequestFormData(String name, String url, Message msg, boolean autoFillable, boolean autoComplete) { @@ -4709,6 +4710,7 @@ public class WebView extends AbsoluteLayout mUpdateMessage = msg; mAutoFillable = autoFillable; mAutoComplete = autoComplete; + mWebSettings = getSettings(); } public void run() { @@ -4718,8 +4720,7 @@ public class WebView extends AbsoluteLayout // Note that code inside the adapter click handler in WebTextView depends // on the AutoFill item being at the top of the drop down list. If you change // the order, make sure to do it there too! - WebSettings settings = getSettings(); - if (settings != null && settings.getAutoFillProfile() != null) { + if (mWebSettings != null && mWebSettings.getAutoFillProfile() != null) { pastEntries.add(getResources().getText( com.android.internal.R.string.autofill_this_form).toString() + " " + diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 563fc26..36927ca 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -91,6 +91,7 @@ public class PopupWindow { private boolean mLayoutInScreen; private boolean mClipToScreen; private boolean mAllowScrollingAnchorParent = true; + private boolean mLayoutInsetDecor = false; private OnTouchListener mTouchInterceptor; @@ -658,6 +659,22 @@ public class PopupWindow { } /** + * Allows the popup window to force the flag + * {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}, overriding default behavior. + * This will cause the popup to inset its content to account for system windows overlaying + * the screen, such as the status bar. + * + * <p>This will often be combined with {@link #setLayoutInScreenEnabled(boolean)}. + * + * @param enabled true if the popup's views should inset content to account for system windows, + * the way that decor views behave for full-screen windows. + * @hide + */ + public void setLayoutInsetDecor(boolean enabled) { + mLayoutInsetDecor = enabled; + } + + /** * Set the layout type for this window. Should be one of the TYPE constants defined in * {@link WindowManager.LayoutParams}. * @@ -942,6 +959,7 @@ public class PopupWindow { if (mContext != null) { p.packageName = mContext.getPackageName(); } + mPopupView.setFitsSystemWindows(mLayoutInsetDecor); mWindowManager.addView(mPopupView, p); } @@ -1012,6 +1030,9 @@ public class PopupWindow { if (mLayoutInScreen) { curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; } + if (mLayoutInsetDecor) { + curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; + } return curFlags; } diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index b2d1a1e..55b73df 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -45,6 +45,7 @@ import android.text.style.ImageSpan; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; +import android.view.CollapsibleActionView; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -58,18 +59,30 @@ import com.android.internal.R; import java.util.WeakHashMap; /** - * A widget that provides a user interface for the user to enter a search query and submit a - * request to a search provider. Shows a list of query suggestions or results, if - * available, and allows the user to pick a suggestion or result to launch into. + * A widget that provides a user interface for the user to enter a search query and submit a request + * to a search provider. Shows a list of query suggestions or results, if available, and allows the + * user to pick a suggestion or result to launch into. * - * <p>For more information, see the <a href="{@docRoot}guide/topics/search/index.html">Search</a> - * documentation.<p> + * <p> + * When the SearchView is used in an ActionBar as an action view for a collapsible menu item, it + * needs to be set to iconified by default using {@link #setIconifiedByDefault(boolean) + * setIconifiedByDefault(true)}. This is the default, so nothing needs to be done. + * </p> + * <p> + * If you want the search field to always be visible, then call setIconifiedByDefault(false). + * </p> * + * <p> + * For more information, see the <a href="{@docRoot}guide/topics/search/index.html">Search</a> + * documentation. + * <p> + * + * @see android.view.MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW * @attr ref android.R.styleable#SearchView_iconifiedByDefault * @attr ref android.R.styleable#SearchView_maxWidth * @attr ref android.R.styleable#SearchView_queryHint */ -public class SearchView extends LinearLayout { +public class SearchView extends LinearLayout implements CollapsibleActionView { private static final boolean DBG = false; private static final String LOG_TAG = "SearchView"; @@ -100,6 +113,7 @@ public class SearchView extends LinearLayout { private int mMaxWidth; private boolean mVoiceButtonEnabled; private CharSequence mUserQuery; + private boolean mExpandedInActionView; private SearchableInfo mSearchable; private Bundle mAppSearchData; @@ -623,7 +637,7 @@ public class SearchView extends LinearLayout { final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText()); // Should we show the close button? It is not shown if there's no focus, // field is not iconified by default and there is no text in it. - final boolean showClose = hasText || mIconifiedByDefault; + final boolean showClose = hasText || (mIconifiedByDefault && !mExpandedInActionView); mCloseButton.setVisibility(showClose ? VISIBLE : INVISIBLE); mCloseButton.getDrawable().setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET); } @@ -1022,6 +1036,25 @@ public class SearchView extends LinearLayout { super.onAttachedToWindow(); } + /** + * {@inheritDoc} + */ + @Override + public void onActionViewCollapsed() { + mQueryTextView.setText(""); + setIconified(true); + mExpandedInActionView = false; + } + + /** + * {@inheritDoc} + */ + @Override + public void onActionViewExpanded() { + mExpandedInActionView = true; + setIconified(false); + } + private void adjustDropDownSizeAndPosition() { if (mDropDownAnchor.getWidth() > 1) { Resources res = getContext().getResources(); diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index b7565f3..0c80a11 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -34,6 +34,7 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; +import android.view.accessibility.AccessibilityEvent; import com.android.internal.R; @@ -360,6 +361,13 @@ public class Switch extends CompoundButton { } } + @Override + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout; + event.getText().add(switchText.getText()); + } + private Layout makeLayout(CharSequence text) { return new StaticLayout(text, mTextPaint, (int) Math.ceil(Layout.getDesiredWidth(text, mTextPaint)), diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl index ad0c1ff..2a045e3 100644 --- a/core/java/com/android/internal/textservice/ITextServicesManager.aidl +++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl @@ -32,4 +32,5 @@ interface ITextServicesManager { in ITextServicesSessionListener tsListener, in ISpellCheckerSessionListener scListener); oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener); + SpellCheckerInfo[] getEnabledSpellCheckers(); } diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 0dc9293..4c1ca31 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -22,6 +22,7 @@ #include "android/graphics/GraphicsJNI.h" #include <binder/IMemory.h> +#include <gui/SurfaceTexture.h> #include <surfaceflinger/SurfaceComposerClient.h> #include <surfaceflinger/Surface.h> #include <ui/Region.h> @@ -38,6 +39,7 @@ #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_view_Surface.h> +#include <android_runtime/android_graphics_SurfaceTexture.h> #include <utils/misc.h> @@ -244,6 +246,19 @@ static void Surface_init( setSurfaceControl(env, clazz, surface); } +static void Surface_initFromSurfaceTexture( + JNIEnv* env, jobject clazz, jobject jst) +{ + sp<ISurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, jst)); + sp<Surface> surface(new Surface(st)); + if (surface == NULL) { + jniThrowException(env, OutOfResourcesException, NULL); + return; + } + setSurfaceControl(env, clazz, NULL); + setSurface(env, clazz, surface); +} + static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel) { Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel); @@ -761,10 +776,26 @@ static void Surface_writeToParcel( return; } + // The Java instance may have a SurfaceControl (in the case of the + // WindowManager or a system app). In that case, we defer to the + // SurfaceControl to send its ISurface. Otherwise, if the Surface is + // available we let it parcel itself. Finally, if the Surface is also + // NULL we fall back to using the SurfaceControl path which sends an + // empty surface; this matches legacy behavior. const sp<SurfaceControl>& control(getSurfaceControl(env, clazz)); - SurfaceControl::writeSurfaceToParcel(control, parcel); + if (control != NULL) { + SurfaceControl::writeSurfaceToParcel(control, parcel); + } else { + sp<Surface> surface(Surface_getSurface(env, clazz)); + if (surface != NULL) { + Surface::writeToParcel(surface, parcel); + } else { + SurfaceControl::writeSurfaceToParcel(NULL, parcel); + } + } if (flags & PARCELABLE_WRITE_RETURN_VALUE) { - setSurfaceControl(env, clazz, 0); + setSurfaceControl(env, clazz, NULL); + setSurface(env, clazz, NULL); } } @@ -784,6 +815,7 @@ static JNINativeMethod gSurfaceMethods[] = { {"nativeClassInit", "()V", (void*)nativeClassInit }, {"init", "(Landroid/view/SurfaceSession;ILjava/lang/String;IIIII)V", (void*)Surface_init }, {"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel }, + {"initFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)V", (void*)Surface_initFromSurfaceTexture }, {"getIdentity", "()I", (void*)Surface_getIdentity }, {"destroy", "()V", (void*)Surface_destroy }, {"release", "()V", (void*)Surface_release }, diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 7d7aea9..b5fc55e 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2278,6 +2278,8 @@ <flag name="feedbackVisual" value="0x00000008" /> <!-- Provides {@link android.accessibilityservice.AccessibilityServiceInfo#FEEDBACK_GENERIC} feedback. --> <flag name="feedbackGeneric" value="0x00000010" /> + <!-- Provides {@link android.accessibilityservice.AccessibilityServiceInfo#FEEDBACK_ALL_MASK} feedback. --> + <flag name="feedbackAllMask" value="0xffffffff" /> </attr> <!-- The minimal period in milliseconds between two accessibility events of the same type are sent to this serivce. This setting can be changed at runtime by calling diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 2b2f356..65dce49 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -469,6 +469,10 @@ speech --> <bool name="config_bluetooth_wide_band_speech">true</bool> + <!-- Boolean indicating if current platform supports quick switch-on/off of + Bluetooth Module --> + <bool name="config_bluetooth_adapter_quick_switch">true</bool> + <!-- The default data-use polling period. --> <integer name="config_datause_polling_period_sec">600</integer> diff --git a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java index bbf1696..4814c61 100644 --- a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java +++ b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java @@ -65,13 +65,13 @@ public class RecycleAccessibilityEventTest extends TestCase { assertEquals(0, first.getText().size()); assertFalse(first.isChecked()); assertNull(first.getContentDescription()); - assertEquals(0, first.getItemCount()); + assertEquals(-1, first.getItemCount()); assertEquals(AccessibilityEvent.INVALID_POSITION, first.getCurrentItemIndex()); assertFalse(first.isEnabled()); assertFalse(first.isPassword()); - assertEquals(0, first.getFromIndex()); - assertEquals(0, first.getAddedCount()); - assertEquals(0, first.getRemovedCount()); + assertEquals(-1, first.getFromIndex()); + assertEquals(-1, first.getAddedCount()); + assertEquals(-1, first.getRemovedCount()); // get another event from the pool (this must be the recycled first) AccessibilityEvent second = AccessibilityEvent.obtain(); diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 134c208..2a8e725 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -211,7 +211,6 @@ protected: // all slots. void freeAllBuffers(); static bool isExternalFormat(uint32_t format); - static GLenum getTextureTarget(uint32_t format); private: @@ -348,10 +347,6 @@ private: // reset mCurrentTexture to INVALID_BUFFER_SLOT. int mCurrentTexture; - // mCurrentTextureTarget is the GLES texture target to be used with the - // current texture. - GLenum mCurrentTextureTarget; - // mCurrentTextureBuf is the graphic buffer of the current texture. It's // possible that this buffer is not associated with any buffer slot, so we // must track it separately in order to support the getCurrentBuffer method. diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index 9c352ad..0460bbd 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -122,7 +122,10 @@ public: uint32_t reserved[2]; }; + explicit Surface(const sp<ISurfaceTexture>& st); + static status_t writeToParcel(const sp<Surface>& control, Parcel* parcel); + static sp<Surface> readFromParcel(const Parcel& data); static bool isValid(const sp<Surface>& surface) { return (surface != 0) && surface->isValid(); @@ -147,14 +150,14 @@ private: Surface& operator = (Surface& rhs); Surface(const Surface& rhs); - Surface(const sp<SurfaceControl>& control); + explicit Surface(const sp<SurfaceControl>& control); Surface(const Parcel& data, const sp<IBinder>& ref); ~Surface(); /* * private stuff... */ - void init(); + void init(const sp<ISurfaceTexture>& surfaceTexture); static void cleanCachedSurfacesLocked(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index c4f9e53..ccf98e5 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -184,6 +184,7 @@ status_t SurfaceControl::writeSurfaceToParcel( identity = control->mIdentity; } parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); + parcel->writeStrongBinder(NULL); // NULL ISurfaceTexture in this case. parcel->writeInt32(identity); return NO_ERROR; } @@ -192,7 +193,8 @@ sp<Surface> SurfaceControl::getSurface() const { Mutex::Autolock _l(mLock); if (mSurfaceData == 0) { - mSurfaceData = new Surface(const_cast<SurfaceControl*>(this)); + sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this)); + mSurfaceData = new Surface(surface_control); } return mSurfaceData; } @@ -208,31 +210,58 @@ Surface::Surface(const sp<SurfaceControl>& surface) mSurface(surface->mSurface), mIdentity(surface->mIdentity) { - init(); + sp<ISurfaceTexture> st; + if (mSurface != NULL) { + st = mSurface->getSurfaceTexture(); + } + init(st); } Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref) : SurfaceTextureClient() { - mSurface = interface_cast<ISurface>(ref); + mSurface = interface_cast<ISurface>(ref); + sp<IBinder> st_binder(parcel.readStrongBinder()); + sp<ISurfaceTexture> st; + if (st_binder != NULL) { + st = interface_cast<ISurfaceTexture>(st_binder); + } else if (mSurface != NULL) { + st = mSurface->getSurfaceTexture(); + } + mIdentity = parcel.readInt32(); - init(); + init(st); +} + +Surface::Surface(const sp<ISurfaceTexture>& st) + : SurfaceTextureClient(), + mSurface(NULL), + mIdentity(0) +{ + init(st); } status_t Surface::writeToParcel( const sp<Surface>& surface, Parcel* parcel) { sp<ISurface> sur; + sp<ISurfaceTexture> st; uint32_t identity = 0; if (Surface::isValid(surface)) { sur = surface->mSurface; + st = surface->getISurfaceTexture(); identity = surface->mIdentity; - } else if (surface != 0 && surface->mSurface != 0) { - LOGW("Parceling invalid surface with non-NULL ISurface as NULL: " - "mSurface = %p, mIdentity = %d", - surface->mSurface.get(), surface->mIdentity); + } else if (surface != 0 && + (surface->mSurface != NULL || + surface->getISurfaceTexture() != NULL)) { + LOGE("Parceling invalid surface with non-NULL ISurface/ISurfaceTexture as NULL: " + "mSurface = %p, surfaceTexture = %p, mIdentity = %d, ", + surface->mSurface.get(), surface->getISurfaceTexture().get(), + surface->mIdentity); } - parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); + + parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL); + parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL); parcel->writeInt32(identity); return NO_ERROR; @@ -249,8 +278,8 @@ sp<Surface> Surface::readFromParcel(const Parcel& data) { surface = new Surface(data, binder); sCachedSurfaces.add(binder, surface); } - if (surface->mSurface == 0) { - surface = 0; + if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) { + surface = 0; } cleanCachedSurfacesLocked(); return surface; @@ -267,10 +296,9 @@ void Surface::cleanCachedSurfacesLocked() { } } -void Surface::init() +void Surface::init(const sp<ISurfaceTexture>& surfaceTexture) { - if (mSurface != NULL) { - sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture()); + if (mSurface != NULL || surfaceTexture != NULL) { LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface"); if (surfaceTexture != NULL) { setISurfaceTexture(surfaceTexture); diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index c190195..8d19957 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -86,7 +86,6 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode) : mClientBufferCount(0), mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), - mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES), mCurrentTransform(0), mCurrentTimestamp(0), mNextTransform(0), @@ -651,12 +650,8 @@ status_t SurfaceTexture::updateTexImage() { LOGW("updateTexImage: clearing GL error: %#04x", error); } - GLenum target = getTextureTarget(mSlots[buf].mGraphicBuffer->format); - if (target != mCurrentTextureTarget) { - glDeleteTextures(1, &mTexName); - } - glBindTexture(target, mTexName); - glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); bool failed = false; while ((error = glGetError()) != GL_NO_ERROR) { @@ -678,7 +673,6 @@ status_t SurfaceTexture::updateTexImage() { // Update the SurfaceTexture state. mCurrentTexture = buf; - mCurrentTextureTarget = target; mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; mCurrentCrop = mSlots[buf].mCrop; mCurrentTransform = mSlots[buf].mTransform; @@ -692,7 +686,7 @@ status_t SurfaceTexture::updateTexImage() { mDequeueCondition.signal(); } else { // We always bind the texture even if we don't update its contents. - glBindTexture(mCurrentTextureTarget, mTexName); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName); } return OK; @@ -717,20 +711,8 @@ bool SurfaceTexture::isExternalFormat(uint32_t format) return false; } -GLenum SurfaceTexture::getTextureTarget(uint32_t format) -{ - GLenum target = GL_TEXTURE_2D; -#if defined(GL_OES_EGL_image_external) - if (isExternalFormat(format)) { - target = GL_TEXTURE_EXTERNAL_OES; - } -#endif - return target; -} - GLenum SurfaceTexture::getCurrentTextureTarget() const { - Mutex::Autolock lock(mMutex); - return mCurrentTextureTarget; + return GL_TEXTURE_EXTERNAL_OES; } void SurfaceTexture::getTransformMatrix(float mtx[16]) { @@ -959,12 +941,12 @@ void SurfaceTexture::dump(String8& result, const char* prefix, } snprintf(buffer, SIZE, - "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d, target=0x%04x}\n" + "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n" "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n" , prefix, mCurrentCrop.left, mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, - mCurrentTransform, mCurrentTexture, mCurrentTextureTarget, + mCurrentTransform, mCurrentTexture, prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, mNextCrop.bottom, mCurrentTransform, fifoSize, fifo.string() ); diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index 0fac6cd..44babcf 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -832,9 +832,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { pt->requestExitAndWait(); } -// XXX: This test is disabled because there are currently no drivers that can -// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target. -TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) { +TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) { const int texWidth = 64; const int texHeight = 66; @@ -871,26 +869,24 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) { EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35)); EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231)); - EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35)); + EXPECT_TRUE(checkPixel(23, 65, 231, 35, 231, 35)); EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35)); EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35)); EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231)); - EXPECT_TRUE(checkPixel(37, 33, 228, 38, 38, 38)); + EXPECT_TRUE(checkPixel(37, 34, 35, 231, 231, 231)); EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231)); - EXPECT_TRUE(checkPixel(36, 47, 228, 35, 231, 231)); - EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35)); - EXPECT_TRUE(checkPixel(48, 3, 228, 228, 38, 35)); + EXPECT_TRUE(checkPixel(37, 47, 231, 35, 231, 231)); + EXPECT_TRUE(checkPixel(25, 38, 35, 35, 35, 35)); + EXPECT_TRUE(checkPixel(49, 6, 35, 231, 35, 35)); EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231)); - EXPECT_TRUE(checkPixel(24, 25, 41, 41, 231, 231)); - EXPECT_TRUE(checkPixel(10, 9, 38, 38, 231, 231)); + EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231)); + EXPECT_TRUE(checkPixel(10, 6, 35, 35, 231, 231)); EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231)); - EXPECT_TRUE(checkPixel(56, 31, 38, 228, 231, 35)); + EXPECT_TRUE(checkPixel(55, 28, 35, 35, 231, 35)); EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231)); } -// XXX: This test is disabled because there are currently no drivers that can -// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target. -TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) { +TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) { const int texWidth = 64; const int texHeight = 64; @@ -944,9 +940,7 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) { EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35)); } -// XXX: This test is disabled because there are currently no drivers that can -// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target. -TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) { +TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) { const int texWidth = 64; const int texHeight = 64; @@ -956,7 +950,7 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) { EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, mANW.get(), NULL); ASSERT_EQ(EGL_SUCCESS, eglGetError()); - ASSERT_NE(EGL_NO_SURFACE, mEglSurface); + ASSERT_NE(EGL_NO_SURFACE, stcEglSurface); EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface, mEglContext)); @@ -980,6 +974,8 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) { eglSwapBuffers(mEglDisplay, stcEglSurface); + eglDestroySurface(mEglDisplay, stcEglSurface); + // Do the consumer side of things EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)); diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 31e4631..82e8d77 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -54,7 +54,8 @@ public class AudioFormat { /** Default audio channel mask */ public static final int CHANNEL_OUT_DEFAULT = 1; - // Channel mask definitions must be kept in sync with native values in include/media/AudioSystem.h + // Channel mask definitions must be kept in sync with native values + // in /system/core/include/system/audio.h public static final int CHANNEL_OUT_FRONT_LEFT = 0x4; public static final int CHANNEL_OUT_FRONT_RIGHT = 0x8; public static final int CHANNEL_OUT_FRONT_CENTER = 0x10; @@ -64,6 +65,25 @@ public class AudioFormat { public static final int CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100; public static final int CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200; public static final int CHANNEL_OUT_BACK_CENTER = 0x400; + /** @hide */ + public static final int CHANNEL_OUT_SIDE_LEFT = 0x800; + /** @hide */ + public static final int CHANNEL_OUT_SIDE_RIGHT = 0x1000; + /** @hide */ + public static final int CHANNEL_OUT_TOP_CENTER = 0x2000; + /** @hide */ + public static final int CHANNEL_OUT_TOP_FRONT_LEFT = 0x4000; + /** @hide */ + public static final int CHANNEL_OUT_TOP_FRONT_CENTER = 0x8000; + /** @hide */ + public static final int CHANNEL_OUT_TOP_FRONT_RIGHT = 0x10000; + /** @hide */ + public static final int CHANNEL_OUT_TOP_BACK_LEFT = 0x20000; + /** @hide */ + public static final int CHANNEL_OUT_TOP_BACK_CENTER = 0x40000; + /** @hide */ + public static final int CHANNEL_OUT_TOP_BACK_RIGHT = 0x80000; + public static final int CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT; public static final int CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT); public static final int CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | @@ -75,6 +95,12 @@ public class AudioFormat { public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER); + /** @hide */ + public static final int CHANNEL_OUT_7POINT1_SURROUND = ( + CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_FRONT_RIGHT | + CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT | + CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | + CHANNEL_OUT_LOW_FREQUENCY); public static final int CHANNEL_IN_DEFAULT = 1; public static final int CHANNEL_IN_LEFT = 0x4; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 482b437..95671bc 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -611,7 +611,7 @@ public class MediaPlayer * needed. Not calling this method when playing back a video will * result in only the audio track being played. * - * Either a surface or surface texture must be set if a display or video sink + * Either a surface holder or surface must be set if a display or video sink * is needed. Not calling this method or {@link #setTexture(SurfaceTexture)} * when playing back a video will result in only the audio track being played. * @@ -630,6 +630,27 @@ public class MediaPlayer } /** + * Sets the {@link Surface} to be used as the sink for the video portion of + * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but does not + * support {@link #setScreenOnWhilePlaying(boolean)} or {@link #updateSurfaceScreenOn()}. + * Setting a Surface will un-set any Surface or SurfaceHolder that was previously set. + * + * @param surface The {@link Surface} to be used for the video portion of the media. + * + * @hide Pending review by API council. + */ + public void setSurface(Surface surface) { + if (mScreenOnWhilePlaying && surface != null && mSurface != null) { + Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for Surface"); + } + mSurfaceHolder = null; + mSurface = surface; + mParcelSurfaceTexture = null; // TODO(tedbo): Remove. + _setVideoSurfaceOrSurfaceTexture(); + updateSurfaceScreenOn(); + } + + /** * Sets the {@link SurfaceTexture} to be used as the sink for the * video portion of the media. Either a surface or surface texture * must be set if a video sink is needed. The same surface texture @@ -665,7 +686,7 @@ public class MediaPlayer * @param pst The {@link ParcelSurfaceTexture} to be used as the sink for * the video portion of the media. * - * @hide Pending review by API council. + * @hide Pending removal when there are no more callers. */ public void setParcelSurfaceTexture(ParcelSurfaceTexture pst) { if (mScreenOnWhilePlaying && pst != null && mParcelSurfaceTexture == null) { @@ -1000,8 +1021,8 @@ public class MediaPlayer */ public void setScreenOnWhilePlaying(boolean screenOn) { if (mScreenOnWhilePlaying != screenOn) { - if (screenOn && mParcelSurfaceTexture != null) { - Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective for SurfaceTexture"); + if (screenOn && mSurfaceHolder == null) { + Log.w(TAG, "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder"); } mScreenOnWhilePlaying = screenOn; updateSurfaceScreenOn(); diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 082dab3..fc8ab96 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -158,7 +158,7 @@ <!-- Checkbox label for application compatibility mode OFF (normal mode on tablets). [CHAR LIMIT=25] --> <string name="compat_mode_off">Stretch to fill screen</string> - + <!-- Compatibility mode help screen: header text. [CHAR LIMIT=50] --> <string name="compat_mode_help_header">Compatibility Zoom</string> @@ -168,7 +168,7 @@ <!-- toast message displayed when a screenshot is saved to the Gallery. --> <string name="screenshot_saving_toast">Screenshot saved to Gallery</string> <!-- toast message displayed when we fail to take a screenshot. --> - <string name="screenshot_failed_toast">Could not save screenshot</string> + <string name="screenshot_failed_toast">Could not save screenshot. External storage may be in use.</string> <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] --> <string name="usb_preference_title">USB file transfer options</string> @@ -299,5 +299,4 @@ <!-- Content description of the ringer silent icon in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_ringer_silent">Ringer silent.</string> - </resources> diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 83a5578..02a955b 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -87,7 +87,7 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi Context context = params[0].context; Bitmap image = params[0].image; - try{ + try { long currentTime = System.currentTimeMillis(); String date = new SimpleDateFormat("MM-dd-yy-kk-mm-ss").format(new Date(currentTime)); String imageDir = Environment.getExternalStoragePublicDirectory( @@ -114,7 +114,9 @@ class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Voi out.close(); params[0].result = 0; - }catch(IOException e){ + } catch (Exception e) { + // IOException/UnsupportedOperationException may be thrown if external storage is not + // mounted params[0].result = 1; } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index e0debf7..bfc3cdd 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -2040,13 +2040,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mActionModePopup = new PopupWindow(mContext, null, com.android.internal.R.attr.actionModePopupWindowStyle); mActionModePopup.setLayoutInScreenEnabled(true); + mActionModePopup.setLayoutInsetDecor(true); mActionModePopup.setClippingEnabled(false); mActionModePopup.setContentView(mActionModeView); mActionModePopup.setWidth(MATCH_PARENT); TypedValue heightValue = new TypedValue(); mContext.getTheme().resolveAttribute( - com.android.internal.R.attr.actionBarSize, heightValue, false); + com.android.internal.R.attr.actionBarSize, heightValue, true); final int height = TypedValue.complexToDimensionPixelSize(heightValue.data, mContext.getResources().getDisplayMetrics()); mActionModePopup.setHeight(height); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index ae13ab5..b7f6adf 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -2444,20 +2444,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: if (down) { - // If the power key down was already triggered, take the screenshot - if (mPowerDownTriggered) { - // Dismiss the power-key longpress - mHandler.removeCallbacks(mPowerLongPress); - mPowerKeyHandled = true; - - // Take the screenshot - takeScreenshot(); - - // Prevent the event from being passed through to the current activity - result &= ~ACTION_PASS_TO_USER; - break; + if (isScreenOn) { + // If the power key down was already triggered, take the screenshot + if (mPowerDownTriggered) { + // Dismiss the power-key longpress + mHandler.removeCallbacks(mPowerLongPress); + mPowerKeyHandled = true; + + // Take the screenshot + takeScreenshot(); + + // Prevent the event from being passed through to the current activity + result &= ~ACTION_PASS_TO_USER; + break; + } + mVolumeDownTriggered = true; } - mVolumeDownTriggered = true; } else { mVolumeDownTriggered = false; } @@ -2541,17 +2543,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_POWER: { result &= ~ACTION_PASS_TO_USER; if (down) { - // If the volume down key has been triggered, then just take the screenshot - if (mVolumeDownTriggered) { - // Take the screenshot - takeScreenshot(); - mPowerKeyHandled = true; - - // Prevent the event from being passed through to the current activity - break; + if (isScreenOn) { + // If the volume down key has been triggered, then just take the screenshot + if (mVolumeDownTriggered) { + // Take the screenshot + takeScreenshot(); + mPowerKeyHandled = true; + + // Prevent the event from being passed through to the current activity + break; + } + mPowerDownTriggered = true; } - mPowerDownTriggered = true; - ITelephony telephonyService = getTelephonyService(); boolean hungUp = false; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 0323fe0..cb1f921 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1043,6 +1043,25 @@ status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args return NO_ERROR; } +status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, "\n- %d Effect Chains:\n", mEffectChains.size()); + write(fd, buffer, strlen(buffer)); + + for (size_t i = 0; i < mEffectChains.size(); ++i) { + sp<EffectChain> chain = mEffectChains[i]; + if (chain != 0) { + chain->dump(fd, args); + } + } + return NO_ERROR; +} + + // ---------------------------------------------------------------------------- AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, @@ -1111,24 +1130,6 @@ status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16> return NO_ERROR; } -status_t AudioFlinger::PlaybackThread::dumpEffectChains(int fd, const Vector<String16>& args) -{ - const size_t SIZE = 256; - char buffer[SIZE]; - String8 result; - - snprintf(buffer, SIZE, "\n- %d Effect Chains:\n", mEffectChains.size()); - write(fd, buffer, strlen(buffer)); - - for (size_t i = 0; i < mEffectChains.size(); ++i) { - sp<EffectChain> chain = mEffectChains[i]; - if (chain != 0) { - chain->dump(fd, args); - } - } - return NO_ERROR; -} - status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args) { const size_t SIZE = 256; @@ -4178,6 +4179,7 @@ status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) write(fd, result.string(), result.size()); dumpBase(fd, args); + dumpEffectChains(fd, args); return NO_ERROR; } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index fff4f06..e2cf946 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -285,6 +285,7 @@ private: }; status_t dumpBase(int fd, const Vector<String16>& args); + status_t dumpEffectChains(int fd, const Vector<String16>& args); // base for record and playback class TrackBase : public AudioBufferProvider, public RefBase { @@ -724,7 +725,6 @@ private: virtual status_t dumpInternals(int fd, const Vector<String16>& args); status_t dumpTracks(int fd, const Vector<String16>& args); - status_t dumpEffectChains(int fd, const Vector<String16>& args); SortedVector< sp<Track> > mTracks; // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java index 4a0c837..ffdc288 100644 --- a/services/java/com/android/server/TextServicesManagerService.java +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -156,6 +156,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { final String curSpellCheckerId = Settings.Secure.getString(mContext.getContentResolver(), Settings.Secure.SPELL_CHECKER_SERVICE); + if (DBG) { + Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId); + } if (TextUtils.isEmpty(curSpellCheckerId)) { return null; } @@ -198,6 +201,11 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } @Override + public SpellCheckerInfo[] getEnabledSpellCheckers() { + return mSpellCheckerList.toArray(new SpellCheckerInfo[mSpellCheckerList.size()]); + } + + @Override public void finishSpellCheckerService(ISpellCheckerSessionListener listener) { synchronized(mSpellCheckerMap) { for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) { @@ -208,6 +216,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } private void setCurrentSpellChecker(SpellCheckerInfo sci) { + if (DBG) { + Slog.w(TAG, "setCurrentSpellChecker: " + sci.getId()); + } if (sci == null || mSpellCheckerMap.containsKey(sci.getId())) return; Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId()); diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index bb9d15b..92647e6 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -49,6 +49,7 @@ import android.util.SparseArray; import android.view.IWindow; import android.view.View; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; @@ -129,10 +130,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private boolean mIsAccessibilityEnabled; - private boolean mIsTouchExplorationRequested; - private AccessibilityInputFilter mInputFilter; + private boolean mHasInputFilter; + private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = new ArrayList<AccessibilityServiceInfo>(); private boolean mIsTouchExplorationEnabled; @@ -189,7 +190,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub manageServicesLocked(); } } - + @Override public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { @@ -236,17 +237,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mIsAccessibilityEnabled = Settings.Secure.getInt( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; - // if accessibility is enabled inform our clients we are on - if (mIsAccessibilityEnabled) { - sendAccessibilityEnabledToClientsLocked(); - } + manageServicesLocked(); // get touch exploration enabled setting on boot - mIsTouchExplorationRequested = Settings.Secure.getInt( + mIsTouchExplorationEnabled = Settings.Secure.getInt( mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1; - updateTouchExplorationEnabledLocked(); + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1; + updateInputFilterLocked(); + + sendStateToClientsLocked(); } return; @@ -288,13 +288,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } else { unbindAllServicesLocked(); } - sendAccessibilityEnabledToClientsLocked(); + sendStateToClientsLocked(); } } }); Uri touchExplorationRequestedUri = Settings.Secure.getUriFor( - Settings.Secure.TOUCH_EXPLORATION_REQUESTED); + Settings.Secure.TOUCH_EXPLORATION_ENABLED); contentResolver.registerContentObserver(touchExplorationRequestedUri, false, new ContentObserver(new Handler()) { @Override @@ -302,10 +302,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub super.onChange(selfChange); synchronized (mLock) { - mIsTouchExplorationRequested = Settings.Secure.getInt( + mIsTouchExplorationEnabled = Settings.Secure.getInt( mContext.getContentResolver(), - Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1; - updateTouchExplorationEnabledLocked(); + Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1; + updateInputFilterLocked(); + sendStateToClientsLocked(); } } }); @@ -325,7 +326,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub }); } - public boolean addClient(IAccessibilityManagerClient client) throws RemoteException { + public int addClient(IAccessibilityManagerClient client) throws RemoteException { synchronized (mLock) { final IAccessibilityManagerClient addedClient = client; mClients.add(addedClient); @@ -338,7 +339,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } }, 0); - return mIsAccessibilityEnabled; + return getState(); } } @@ -628,7 +629,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub service.linkToOwnDeath(); mServices.add(service); mComponentNameToServiceMap.put(service.mComponentName, service); - updateTouchExplorationEnabledLocked(); + updateInputFilterLocked(); } catch (RemoteException e) { /* do nothing */ } @@ -648,7 +649,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mComponentNameToServiceMap.remove(service.mComponentName); mHandler.removeMessages(service.mId); service.unlinkToOwnDeath(); - updateTouchExplorationEnabledLocked(); + updateInputFilterLocked(); return removed; } @@ -781,12 +782,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** - * Updates the state of {@link android.view.accessibility.AccessibilityManager} clients. + * Sends the state to the clients. */ - private void sendAccessibilityEnabledToClientsLocked() { + private void sendStateToClientsLocked() { + final int state = getState(); for (int i = 0, count = mClients.size(); i < count; i++) { try { - mClients.get(i).setEnabled(mIsAccessibilityEnabled); + mClients.get(i).setState(state); } catch (RemoteException re) { mClients.remove(i); count--; @@ -796,48 +798,39 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } /** - * Sends the touch exploration state to clients. + * Gets the current state as a set of flags. + * + * @return The state. */ - private void sendTouchExplorationEnabledToClientsLocked() { - for (int i = 0, count = mClients.size(); i < count; i++) { - try { - mClients.get(i).setTouchExplorationEnabled(mIsTouchExplorationEnabled); - } catch (RemoteException re) { - mClients.remove(i); - count--; - i--; - } + private int getState() { + int state = 0; + if (mIsAccessibilityEnabled) { + state |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; } + // Touch exploration relies on enabled accessibility. + if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) { + state |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; + } + return state; } /** - * Updates the touch exploration state. Touch exploration is enabled if it - * is requested, accessibility is on and there is at least one enabled - * accessibility service providing spoken feedback. + * Updates the touch exploration state. */ - private void updateTouchExplorationEnabledLocked() { - if (mIsAccessibilityEnabled && mIsTouchExplorationRequested) { - final boolean hasSpeakingServicesEnabled = !getEnabledAccessibilityServiceList( - AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty(); - if (!mIsTouchExplorationEnabled) { - if (!hasSpeakingServicesEnabled) { - return; - } + private void updateInputFilterLocked() { + if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) { + if (!mHasInputFilter) { + mHasInputFilter = true; if (mInputFilter == null) { mInputFilter = new AccessibilityInputFilter(mContext); } mWindowManagerService.setInputFilter(mInputFilter); - mIsTouchExplorationEnabled = true; - sendTouchExplorationEnabledToClientsLocked(); - return; - } else if (hasSpeakingServicesEnabled) { - return; } + return; } - if (mIsTouchExplorationEnabled) { + if (mHasInputFilter) { + mHasInputFilter = false; mWindowManagerService.setInputFilter(null); - mIsTouchExplorationEnabled = false; - sendTouchExplorationEnabledToClientsLocked(); } } diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java index 5a3a55d..0ad58d0 100644 --- a/services/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/java/com/android/server/accessibility/TouchExplorer.java @@ -19,21 +19,21 @@ package com.android.server.accessibility; import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END; import static android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START; -import com.android.server.accessibility.AccessibilityInputFilter.Explorer; -import com.android.server.wm.InputFilter; - import android.content.Context; import android.os.Handler; import android.os.SystemClock; import android.util.Slog; import android.view.MotionEvent; -import android.view.ViewConfiguration; -import android.view.WindowManagerPolicy; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; +import android.view.ViewConfiguration; +import android.view.WindowManagerPolicy; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import com.android.server.accessibility.AccessibilityInputFilter.Explorer; +import com.android.server.wm.InputFilter; + import java.util.Arrays; /** @@ -146,6 +146,9 @@ public class TouchExplorer implements Explorer { // Command for delayed sending of a hover event. private final SendHoverDelayed mSendHoverDelayed; + // Command for delayed sending of a long press. + private final PerformLongPressDelayed mPerformLongPressDelayed; + /** * Creates a new instance. * @@ -160,6 +163,7 @@ public class TouchExplorer implements Explorer { mPointerTracker = new PointerTracker(context); mHandler = new Handler(context.getMainLooper()); mSendHoverDelayed = new SendHoverDelayed(); + mPerformLongPressDelayed = new PerformLongPressDelayed(); mAccessibilityManager = AccessibilityManager.getInstance(context); } @@ -208,15 +212,7 @@ public class TouchExplorer implements Explorer { final int activePointerCount = pointerTracker.getActivePointerCount(); switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: { - // Send a hover for every finger down so the user gets feedback - // where she is currently touching. - mSendHoverDelayed.forceSendAndRemove(); - final int pointerIndex = event.getActionIndex(); - final int pointerIdBits = (1 << event.getPointerId(pointerIndex)); - mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, - policyFlags, DELAY_SEND_HOVER_MOVE); - } break; + case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: { switch (activePointerCount) { case 0: { @@ -224,13 +220,13 @@ public class TouchExplorer implements Explorer { + "touch exploring state!"); } case 1: { - // Schedule a hover event which will lead to firing an - // accessibility event from the hovered view. - mSendHoverDelayed.remove(); + // Send hover if pending. + mSendHoverDelayed.forceSendAndRemove(); + // Send a hover for every finger down so the user gets feedback. final int pointerId = pointerTracker.getPrimaryActivePointerId(); final int pointerIdBits = (1 << pointerId); final int lastAction = pointerTracker.getLastInjectedHoverAction(); - // If a schedules hover enter for another pointer is delivered we send move. + // If a hover enter for another pointer is delivered we send move. final int action = (lastAction == MotionEvent.ACTION_HOVER_ENTER) ? MotionEvent.ACTION_HOVER_MOVE : MotionEvent.ACTION_HOVER_ENTER; @@ -244,7 +240,19 @@ public class TouchExplorer implements Explorer { // If more pointers down on the screen since the last touch // exploration we discard the last cached touch explore event. if (event.getPointerCount() != mLastTouchExploreEvent.getPointerCount()) { - mLastTouchExploreEvent = null; + mLastTouchExploreEvent = null; + break; + } + + // If the down is in the time slop => schedule a long press. + final long pointerDownTime = + pointerTracker.getReceivedPointerDownTime(pointerId); + final long lastExploreTime = mLastTouchExploreEvent.getEventTime(); + final long deltaTimeExplore = pointerDownTime - lastExploreTime; + if (deltaTimeExplore <= ACTIVATION_TIME_SLOP) { + mPerformLongPressDelayed.post(event, policyFlags, + ViewConfiguration.getLongPressTimeout()); + break; } } break; default: { @@ -275,6 +283,7 @@ public class TouchExplorer implements Explorer { sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START); // Make sure the scheduled down/move event is sent. mSendHoverDelayed.forceSendAndRemove(); + mPerformLongPressDelayed.remove(); // If we have transitioned to exploring state from another one // we need to send a hover enter event here. final int lastAction = mPointerTracker.getLastInjectedHoverAction(); @@ -291,20 +300,11 @@ public class TouchExplorer implements Explorer { policyFlags); } - // Detect long press on the last touch explored position. - if (!mTouchExploreGestureInProgress && mLastTouchExploreEvent != null) { + // If the exploring pointer moved enough => cancel the long press. + if (!mTouchExploreGestureInProgress && mLastTouchExploreEvent != null + && mPerformLongPressDelayed.isPenidng()) { - // If the down was not in the time slop => nothing else to do. - final long pointerDownTime = - pointerTracker.getReceivedPointerDownTime(pointerId); - final long lastExploreTime = mLastTouchExploreEvent.getEventTime(); - final long deltaTimeExplore = pointerDownTime - lastExploreTime; - if (deltaTimeExplore > ACTIVATION_TIME_SLOP) { - mLastTouchExploreEvent = null; - break; - } - - // If the pointer moved more than the tap slop => nothing else to do. + // If the pointer moved more than the tap slop => cancel long press. final float deltaX = mLastTouchExploreEvent.getX(pointerIndex) - event.getX(pointerIndex); final float deltaY = mLastTouchExploreEvent.getY(pointerIndex) @@ -312,24 +312,14 @@ public class TouchExplorer implements Explorer { final float moveDelta = (float) Math.hypot(deltaX, deltaY); if (moveDelta > mTouchExplorationTapSlop) { mLastTouchExploreEvent = null; + mPerformLongPressDelayed.remove(); break; } - - // If down for long enough we get a long press. - final long deltaTimeMove = event.getEventTime() - pointerDownTime; - if (deltaTimeMove > ViewConfiguration.getLongPressTimeout()) { - mCurrentState = STATE_DELEGATING; - // Make sure the scheduled hover exit is delivered. - mSendHoverDelayed.forceSendAndRemove(); - sendDownForAllActiveNotInjectedPointers(event, policyFlags); - sendMotionEvent(event, policyFlags); - mTouchExploreGestureInProgress = false; - mLastTouchExploreEvent = null; - } } } break; case 2: { mSendHoverDelayed.forceSendAndRemove(); + mPerformLongPressDelayed.remove(); // We want to no longer hover over the location so subsequent // touch at the same spot will generate a hover enter. sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, @@ -360,6 +350,7 @@ public class TouchExplorer implements Explorer { } break; default: { mSendHoverDelayed.forceSendAndRemove(); + mPerformLongPressDelayed.remove(); // We want to no longer hover over the location so subsequent // touch at the same spot will generate a hover enter. sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, @@ -388,22 +379,26 @@ public class TouchExplorer implements Explorer { break; } + mSendHoverDelayed.forceSendAndRemove(); + mPerformLongPressDelayed.remove(); + // If touch exploring announce the end of the gesture. + // Also do not click on the last explored location. if (mTouchExploreGestureInProgress) { - sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); mTouchExploreGestureInProgress = false; + mLastTouchExploreEvent = MotionEvent.obtain(event); + sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END); + break; } // Detect whether to activate i.e. click on the last explored location. if (mLastTouchExploreEvent != null) { - // If the down was not in the time slop => nothing else to do. final long eventTime = pointerTracker.getLastReceivedUpPointerDownTime(); final long exploreTime = mLastTouchExploreEvent.getEventTime(); final long deltaTime = eventTime - exploreTime; if (deltaTime > ACTIVATION_TIME_SLOP) { - mSendHoverDelayed.forceSendAndRemove(); final int lastAction = mPointerTracker.getLastInjectedHoverAction(); if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, @@ -413,15 +408,14 @@ public class TouchExplorer implements Explorer { break; } - // If the pointer moved more than the tap slop => nothing else to do. + // If a tap is farther than the tap slop => nothing to do. final int pointerIndex = event.findPointerIndex(pointerId); - final float deltaX = pointerTracker.getLastReceivedUpPointerDownX() + final float deltaX = mLastTouchExploreEvent.getX(pointerIndex) - event.getX(pointerIndex); - final float deltaY = pointerTracker.getLastReceivedUpPointerDownY() + final float deltaY = mLastTouchExploreEvent.getY(pointerIndex) - event.getY(pointerIndex); final float deltaMove = (float) Math.hypot(deltaX, deltaY); if (deltaMove > mTouchExplorationTapSlop) { - mSendHoverDelayed.forceSendAndRemove(); final int lastAction = mPointerTracker.getLastInjectedHoverAction(); if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, @@ -432,7 +426,6 @@ public class TouchExplorer implements Explorer { } // All preconditions are met, so click the last explored location. - mSendHoverDelayed.forceSendAndRemove(); sendActionDownAndUp(mLastTouchExploreEvent, policyFlags); mLastTouchExploreEvent = null; } else { @@ -448,6 +441,8 @@ public class TouchExplorer implements Explorer { } } break; case MotionEvent.ACTION_CANCEL: { + mSendHoverDelayed.remove(); + mPerformLongPressDelayed.remove(); final int lastAction = pointerTracker.getLastInjectedHoverAction(); if (lastAction != MotionEvent.ACTION_HOVER_EXIT) { final int pointerId = pointerTracker.getPrimaryActivePointerId(); @@ -934,8 +929,6 @@ public class TouchExplorer implements Explorer { private int mInjectedPointersDown; // Keep track of the last up pointer data. - private float mLastReceivedUpPointerDownX; - private float mLastReveivedUpPointerDownY; private long mLastReceivedUpPointerDownTime; private int mLastReceivedUpPointerId; private boolean mLastReceivedUpPointerActive; @@ -968,8 +961,6 @@ public class TouchExplorer implements Explorer { mPrimaryActivePointerId = 0; mHasMovingActivePointer = false; mInjectedPointersDown = 0; - mLastReceivedUpPointerDownX = 0; - mLastReveivedUpPointerDownY = 0; mLastReceivedUpPointerDownTime = 0; mLastReceivedUpPointerId = 0; mLastReceivedUpPointerActive = false; @@ -1126,20 +1117,6 @@ public class TouchExplorer implements Explorer { } /** - * @return The X coordinate where the last up received pointer went down. - */ - public float getLastReceivedUpPointerDownX() { - return mLastReceivedUpPointerDownX; - } - - /** - * @return The Y coordinate where the last up received pointer went down. - */ - public float getLastReceivedUpPointerDownY() { - return mLastReveivedUpPointerDownY; - } - - /** * @return The time when the last up received pointer went down. */ public long getLastReceivedUpPointerDownTime() { @@ -1220,8 +1197,6 @@ public class TouchExplorer implements Explorer { final int pointerFlag = (1 << pointerId); mLastReceivedUpPointerId = 0; - mLastReceivedUpPointerDownX = 0; - mLastReveivedUpPointerDownY = 0; mLastReceivedUpPointerDownTime = 0; mLastReceivedUpPointerActive = false; @@ -1262,8 +1237,6 @@ public class TouchExplorer implements Explorer { final int pointerFlag = (1 << pointerId); mLastReceivedUpPointerId = pointerId; - mLastReceivedUpPointerDownX = getReceivedPointerDownX(pointerId); - mLastReveivedUpPointerDownY = getReceivedPointerDownY(pointerId); mLastReceivedUpPointerDownTime = getReceivedPointerDownTime(pointerId); mLastReceivedUpPointerActive = isActivePointer(pointerId); @@ -1400,6 +1373,51 @@ public class TouchExplorer implements Explorer { } /** + * Class for delayed sending of long press. + */ + private final class PerformLongPressDelayed implements Runnable { + private MotionEvent mEvent; + private int mPolicyFlags; + + public void post(MotionEvent prototype, int policyFlags, long delay) { + mEvent = MotionEvent.obtain(prototype); + mPolicyFlags = policyFlags; + mHandler.postDelayed(this, delay); + } + + public void remove() { + if (isPenidng()) { + mHandler.removeCallbacks(this); + clear(); + } + } + + private boolean isPenidng() { + return (mEvent != null); + } + + @Override + public void run() { + mCurrentState = STATE_DELEGATING; + // Make sure the scheduled hover exit is delivered. + mSendHoverDelayed.forceSendAndRemove(); + sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags); + mTouchExploreGestureInProgress = false; + mLastTouchExploreEvent = null; + clear(); + } + + private void clear() { + if (!isPenidng()) { + return; + } + mEvent.recycle(); + mEvent = null; + mPolicyFlags = 0; + } + } + + /** * Class for delayed sending of hover events. */ private final class SendHoverDelayed implements Runnable { diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java index 1234bfd..46bcc4a 100644 --- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java @@ -29,12 +29,13 @@ import android.provider.Settings; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IAccessibilityManager; import android.view.accessibility.IAccessibilityManagerClient; /** * This test exercises the - * {@link com.android.server.AccessibilityManagerService} by mocking the + * {@link com.android.server.accessibility.AccessibilityManagerService} by mocking the * {@link android.view.accessibility.AccessibilityManager} which talks to to the * service. The service itself is interacting with the platform. Note: Testing * the service in full isolation would require significant amount of work for @@ -97,7 +98,9 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient(); // invoke the method under test - boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient); + final int stateFlagsDisabled = mManagerService.addClient(mockClient); + boolean enabledAccessibilityDisabled = + (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0; // check expected result assertFalse("The client must be disabled since accessibility is disabled.", @@ -107,7 +110,10 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { ensureAccessibilityEnabled(mContext, true); // invoke the method under test - boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient); + final int stateFlagsEnabled = mManagerService.addClient(mockClient); + boolean enabledAccessibilityEnabled = + (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0; + // check expected result assertTrue("The client must be enabled since accessibility is enabled.", @@ -123,7 +129,9 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient(); // invoke the method under test - boolean enabledAccessibilityEnabled = mManagerService.addClient(mockClient); + final int stateFlagsEnabled = mManagerService.addClient(mockClient); + boolean enabledAccessibilityEnabled = + (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0; // check expected result assertTrue("The client must be enabled since accessibility is enabled.", @@ -133,7 +141,9 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { ensureAccessibilityEnabled(mContext, false); // invoke the method under test - boolean enabledAccessibilityDisabled = mManagerService.addClient(mockClient); + final int stateFlagsDisabled = mManagerService.addClient(mockClient); + boolean enabledAccessibilityDisabled = + (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0; // check expected result assertFalse("The client must be disabled since accessibility is disabled.", @@ -537,10 +547,10 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase { * This class is a mock {@link IAccessibilityManagerClient}. */ public class MyMockAccessibilityManagerClient extends IAccessibilityManagerClient.Stub { - boolean mIsEnabled; + int mState; - public void setEnabled(boolean enabled) { - mIsEnabled = enabled; + public void setState(int state) { + mState = state; } public void setTouchExplorationEnabled(boolean enabled) { diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java index 1463d30..e083815 100644 --- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java @@ -70,7 +70,8 @@ public class AccessibilityManagerTest extends AndroidTestCase { // configure the mock service behavior IAccessibilityManager mockServiceInterface = mMockServiceInterface; - expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true); + expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn( + AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED); expect(mockServiceInterface.getInstalledAccessibilityServiceList()).andReturn( expectedServices); replay(mockServiceInterface); @@ -91,7 +92,8 @@ public class AccessibilityManagerTest extends AndroidTestCase { public void testInterrupt() throws Exception { // configure the mock service behavior IAccessibilityManager mockServiceInterface = mMockServiceInterface; - expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true); + expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn( + AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED); mockServiceInterface.interrupt(); replay(mockServiceInterface); @@ -107,7 +109,8 @@ public class AccessibilityManagerTest extends AndroidTestCase { public void testIsEnabled() throws Exception { // configure the mock service behavior IAccessibilityManager mockServiceInterface = mMockServiceInterface; - expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true); + expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn( + AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED); replay(mockServiceInterface); // invoke the method under test @@ -118,7 +121,7 @@ public class AccessibilityManagerTest extends AndroidTestCase { assertTrue("Must be enabled since the mock service is enabled", isEnabledServiceEnabled); // disable accessibility - manager.getClient().setEnabled(false); + manager.getClient().setState(0); // wait for the asynchronous IBinder call to complete Thread.sleep(TIMEOUT_BINDER_CALL); @@ -141,7 +144,8 @@ public class AccessibilityManagerTest extends AndroidTestCase { // configure the mock service behavior IAccessibilityManager mockServiceInterface = mMockServiceInterface; - expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(true); + expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn( + AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED); expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent))) .andReturn(true); expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent))) @@ -176,7 +180,7 @@ public class AccessibilityManagerTest extends AndroidTestCase { // configure the mock service behavior IAccessibilityManager mockServiceInterface = mMockServiceInterface; - expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(false); + expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient())).andReturn(0); replay(mockServiceInterface); // invoke the method under test (accessibility disabled) diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index 54685a6..74c6b49 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -1059,7 +1059,7 @@ public class WifiStateMachine extends StateMachine { } } - private void startTethering(ArrayList<String> available) { + private boolean startTethering(ArrayList<String> available) { boolean wifiAvailable = false; @@ -1085,18 +1085,20 @@ public class WifiStateMachine extends StateMachine { } catch (Exception e) { Log.e(TAG, "Error configuring interface " + intf + ", :" + e); setWifiApEnabled(null, false); - return; + return false; } if(mCm.tether(intf) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { Log.e(TAG, "Error tethering on " + intf); setWifiApEnabled(null, false); - return; + return false; } - break; + return true; } } } + // We found no interfaces to tether + return false; } private void stopTethering() { @@ -3098,8 +3100,9 @@ public class WifiStateMachine extends StateMachine { break; case CMD_TETHER_INTERFACE: ArrayList<String> available = (ArrayList<String>) message.obj; - startTethering(available); - transitionTo(mTetheredState); + if (startTethering(available)) { + transitionTo(mTetheredState); + } break; case WifiP2pService.P2P_ENABLE_PENDING: // turn of soft Ap and defer to be handled in DriverUnloadedState |