diff options
119 files changed, 2580 insertions, 35 deletions
diff --git a/Android.mk b/Android.mk index 7a46a1fa0424..58bc2c7f9a0e 100644 --- a/Android.mk +++ b/Android.mk @@ -98,6 +98,8 @@ LOCAL_SRC_FILES += \ core/java/android/app/maintenance/IIdleService.aidl \ core/java/android/bluetooth/IBluetooth.aidl \ core/java/android/bluetooth/IBluetoothA2dp.aidl \ + core/java/android/bluetooth/IBluetoothA2dpSink.aidl \ + core/java/android/bluetooth/IBluetoothAvrcpController.aidl \ core/java/android/bluetooth/IBluetoothCallback.aidl \ core/java/android/bluetooth/IBluetoothHeadset.aidl \ core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \ @@ -110,6 +112,7 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothPbap.aidl \ core/java/android/bluetooth/IBluetoothMap.aidl \ core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \ + core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \ core/java/android/bluetooth/IBluetoothGatt.aidl \ core/java/android/bluetooth/IBluetoothGattCallback.aidl \ core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \ diff --git a/api/current.txt b/api/current.txt index a2d62b0bef6b..941eb5b2b9df 100644 --- a/api/current.txt +++ b/api/current.txt @@ -35001,7 +35001,8 @@ package android.view.textservice { package android.webkit { - public abstract interface ClientCertRequest { + public abstract class ClientCertRequest { + ctor public ClientCertRequest(); method public abstract void cancel(); method public abstract java.lang.String getHost(); method public abstract java.lang.String[] getKeyTypes(); diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 7b709acd911c..51754901163d 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -90,6 +90,11 @@ public final class BluetoothA2dp implements BluetoothProfile { public static final String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED"; + /** @hide */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED = + "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED"; + /** * A2DP sink device is streaming music. This state can be one of * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java new file mode 100644 index 000000000000..2e273459add8 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothA2dpSink.java @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class provides the public APIs to control the Bluetooth A2DP Sink + * profile. + * + *<p>BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink + * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get + * the BluetoothA2dpSink proxy object. + * + * @hide + */ +public final class BluetoothA2dpSink implements BluetoothProfile { + private static final String TAG = "BluetoothA2dpSink"; + private static final boolean DBG = true; + private static final boolean VDBG = false; + + /** + * Intent used to broadcast the change in connection state of the A2DP Sink + * profile. + * + * <p>This intent will have 3 extras: + * <ul> + * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> + * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * </ul> + * + * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED"; + + /** + * Intent used to broadcast the change in the Playing state of the A2DP Sink + * profile. + * + * <p>This intent will have 3 extras: + * <ul> + * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> + * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * </ul> + * + * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING}, + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + public static final String ACTION_PLAYING_STATE_CHANGED = + "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED"; + + /** + * A2DP sink device is streaming music. This state can be one of + * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of + * {@link #ACTION_PLAYING_STATE_CHANGED} intent. + */ + public static final int STATE_PLAYING = 10; + + /** + * A2DP sink device is NOT streaming music. This state can be one of + * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of + * {@link #ACTION_PLAYING_STATE_CHANGED} intent. + */ + public static final int STATE_NOT_PLAYING = 11; + + /** + * Intent used to broadcast the change in the Playing state of the A2DP Sink + * profile. + * + * <p>This intent will have 3 extras: + * <ul> + * <li> {@link #EXTRA_AUDIO_CONFIG} - The audio configuration for the remote device. </li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * </ul> + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + public static final String ACTION_AUDIO_CONFIG_CHANGED = + "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED"; + + /** + * Extra for the {@link #ACTION_AUDIO_CONFIG_CHANGED} intent. + * + * This extra represents the current audio configuration of the A2DP source device. + * {@see BluetoothAudioConfig} + */ + public static final String EXTRA_AUDIO_CONFIG + = "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG"; + + private Context mContext; + private ServiceListener mServiceListener; + private IBluetoothA2dpSink mService; + private BluetoothAdapter mAdapter; + + final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = + new IBluetoothStateChangeCallback.Stub() { + public void onBluetoothStateChange(boolean up) { + if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); + if (!up) { + if (VDBG) Log.d(TAG,"Unbinding service..."); + synchronized (mConnection) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } else { + synchronized (mConnection) { + try { + if (mService == null) { + if (VDBG) Log.d(TAG,"Binding service..."); + doBind(); + } + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + }; + /** + * Create a BluetoothA2dp proxy object for interacting with the local + * Bluetooth A2DP service. + * + */ + /*package*/ BluetoothA2dpSink(Context context, ServiceListener l) { + mContext = context; + mServiceListener = l; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + + doBind(); + } + + boolean doBind() { + Intent intent = new Intent(IBluetoothA2dpSink.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, + android.os.Process.myUserHandle())) { + Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent); + return false; + } + return true; + } + + /*package*/ void close() { + mServiceListener = null; + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (Exception e) { + Log.e(TAG,"",e); + } + } + + synchronized (mConnection) { + if (mService != null) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + + public void finalize() { + close(); + } + /** + * Initiate connection to a profile of the remote bluetooth device. + * + * <p> Currently, the system supports only 1 connection to the + * A2DP profile. The API will automatically disconnect connected + * devices before connecting. + * + * <p> This API returns false in scenarios like the profile on the + * device is already connected or Bluetooth is not turned on. + * When this API returns true, it is guaranteed that + * connection state intent for the profile will be broadcasted with + * the state. Users can get the connection state of the profile + * from this intent. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission. + * + * @param device Remote Bluetooth Device + * @return false on immediate error, + * true otherwise + * @hide + */ + public boolean connect(BluetoothDevice device) { + if (DBG) log("connect(" + device + ")"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.connect(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Initiate disconnection from a profile + * + * <p> This API will return false in scenarios like the profile on the + * Bluetooth device is not in connected state etc. When this API returns, + * true, it is guaranteed that the connection state change + * intent will be broadcasted with the state. Users can get the + * disconnection state of the profile from this intent. + * + * <p> If the disconnection is initiated by a remote device, the state + * will transition from {@link #STATE_CONNECTED} to + * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the + * host (local) device the state will transition from + * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to + * state {@link #STATE_DISCONNECTED}. The transition to + * {@link #STATE_DISCONNECTING} can be used to distinguish between the + * two scenarios. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission. + * + * @param device Remote Bluetooth Device + * @return false on immediate error, + * true otherwise + * @hide + */ + public boolean disconnect(BluetoothDevice device) { + if (DBG) log("disconnect(" + device + ")"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.disconnect(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * {@inheritDoc} + */ + public List<BluetoothDevice> getConnectedDevices() { + if (VDBG) log("getConnectedDevices()"); + if (mService != null && isEnabled()) { + try { + return mService.getConnectedDevices(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * {@inheritDoc} + */ + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + if (VDBG) log("getDevicesMatchingStates()"); + if (mService != null && isEnabled()) { + try { + return mService.getDevicesMatchingConnectionStates(states); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * {@inheritDoc} + */ + public int getConnectionState(BluetoothDevice device) { + if (VDBG) log("getState(" + device + ")"); + if (mService != null && isEnabled() + && isValidDevice(device)) { + try { + return mService.getConnectionState(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.STATE_DISCONNECTED; + } + + /** + * Get the current audio configuration for the A2DP source device, + * or null if the device has no audio configuration + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @param device Remote bluetooth device. + * @return audio configuration for the device, or null + * + * {@see BluetoothAudioConfig} + */ + public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { + if (VDBG) log("getAudioConfig(" + device + ")"); + if (mService != null && isEnabled() + && isValidDevice(device)) { + try { + return mService.getAudioConfig(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return null; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return null; + } + + /** + * Helper for converting a state to a string. + * + * For debug use only - strings are not internationalized. + * @hide + */ + public static String stateToString(int state) { + switch (state) { + case STATE_DISCONNECTED: + return "disconnected"; + case STATE_CONNECTING: + return "connecting"; + case STATE_CONNECTED: + return "connected"; + case STATE_DISCONNECTING: + return "disconnecting"; + case STATE_PLAYING: + return "playing"; + case STATE_NOT_PLAYING: + return "not playing"; + default: + return "<unknown state " + state + ">"; + } + } + + private final ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) Log.d(TAG, "Proxy object connected"); + mService = IBluetoothA2dpSink.Stub.asInterface(service); + + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK, + BluetoothA2dpSink.this); + } + } + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.d(TAG, "Proxy object disconnected"); + mService = null; + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP_SINK); + } + } + }; + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +} diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 42c2aebead52..ba42f51b6245 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2009-2014 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. @@ -1390,6 +1390,12 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.A2DP) { BluetoothA2dp a2dp = new BluetoothA2dp(context, listener); return true; + } else if (profile == BluetoothProfile.A2DP_SINK) { + BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener); + return true; + } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) { + BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener); + return true; } else if (profile == BluetoothProfile.INPUT_DEVICE) { BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener); return true; @@ -1402,6 +1408,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP) { BluetoothMap map = new BluetoothMap(context, listener); return true; + } else if (profile == BluetoothProfile.HEADSET_CLIENT) { + BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener); + return true; } else { return false; } @@ -1430,6 +1439,14 @@ public final class BluetoothAdapter { BluetoothA2dp a2dp = (BluetoothA2dp)proxy; a2dp.close(); break; + case BluetoothProfile.A2DP_SINK: + BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy; + a2dpSink.close(); + break; + case BluetoothProfile.AVRCP_CONTROLLER: + BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy; + avrcp.close(); + break; case BluetoothProfile.INPUT_DEVICE: BluetoothInputDevice iDev = (BluetoothInputDevice)proxy; iDev.close(); @@ -1454,6 +1471,10 @@ public final class BluetoothAdapter { BluetoothMap map = (BluetoothMap)proxy; map.close(); break; + case BluetoothProfile.HEADSET_CLIENT: + BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy; + headsetClient.close(); + break; } } diff --git a/core/java/android/bluetooth/BluetoothAudioConfig.aidl b/core/java/android/bluetooth/BluetoothAudioConfig.aidl new file mode 100644 index 000000000000..63be5cff87da --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAudioConfig.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2009 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.bluetooth; + +parcelable BluetoothAudioConfig; diff --git a/core/java/android/bluetooth/BluetoothAudioConfig.java b/core/java/android/bluetooth/BluetoothAudioConfig.java new file mode 100644 index 000000000000..03176b9e0739 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAudioConfig.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2009 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.bluetooth; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Represents the audio configuration for a Bluetooth A2DP source device. + * + * {@see BluetoothA2dpSink} + * + * {@hide} + */ +public final class BluetoothAudioConfig implements Parcelable { + + private final int mSampleRate; + private final int mChannelConfig; + private final int mAudioFormat; + + public BluetoothAudioConfig(int sampleRate, int channelConfig, int audioFormat) { + mSampleRate = sampleRate; + mChannelConfig = channelConfig; + mAudioFormat = audioFormat; + } + + @Override + public boolean equals(Object o) { + if (o instanceof BluetoothAudioConfig) { + BluetoothAudioConfig bac = (BluetoothAudioConfig)o; + return (bac.mSampleRate == mSampleRate && + bac.mChannelConfig == mChannelConfig && + bac.mAudioFormat == mAudioFormat); + } + return false; + } + + @Override + public int hashCode() { + return mSampleRate | (mChannelConfig << 24) | (mAudioFormat << 28); + } + + @Override + public String toString() { + return "{mSampleRate:" + mSampleRate + ",mChannelConfig:" + mChannelConfig + + ",mAudioFormat:" + mAudioFormat + "}"; + } + + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<BluetoothAudioConfig> CREATOR = + new Parcelable.Creator<BluetoothAudioConfig>() { + public BluetoothAudioConfig createFromParcel(Parcel in) { + int sampleRate = in.readInt(); + int channelConfig = in.readInt(); + int audioFormat = in.readInt(); + return new BluetoothAudioConfig(sampleRate, channelConfig, audioFormat); + } + public BluetoothAudioConfig[] newArray(int size) { + return new BluetoothAudioConfig[size]; + } + }; + + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mSampleRate); + out.writeInt(mChannelConfig); + out.writeInt(mAudioFormat); + } + + /** + * Returns the sample rate in samples per second + * @return sample rate + */ + public int getSampleRate() { + return mSampleRate; + } + + /** + * Returns the channel configuration (either {@link android.media.AudioFormat#CHANNEL_IN_MONO} + * or {@link android.media.AudioFormat#CHANNEL_IN_STEREO}) + * @return channel configuration + */ + public int getChannelConfig() { + return mChannelConfig; + } + + /** + * Returns the channel audio format (either {@link android.media.AudioFormat#ENCODING_PCM_16BIT} + * or {@link android.media.AudioFormat#ENCODING_PCM_8BIT} + * @return audio format + */ + public int getAudioFormat() { + return mAudioFormat; + } +} diff --git a/core/java/android/bluetooth/BluetoothAvrcp.java b/core/java/android/bluetooth/BluetoothAvrcp.java new file mode 100644 index 000000000000..44fe1b737129 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAvrcp.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +/** + * This class contains constants for Bluetooth AVRCP profile. + * + * {@hide} + */ +public final class BluetoothAvrcp { + + /* + * State flags for Passthrough commands + */ + public static final int PASSTHROUGH_STATE_PRESS = 0; + public static final int PASSTHROUGH_STATE_RELEASE = 1; + + /* + * Operation IDs for Passthrough commands + */ + public static final int PASSTHROUGH_ID_SELECT = 0x00; /* select */ + public static final int PASSTHROUGH_ID_UP = 0x01; /* up */ + public static final int PASSTHROUGH_ID_DOWN = 0x02; /* down */ + public static final int PASSTHROUGH_ID_LEFT = 0x03; /* left */ + public static final int PASSTHROUGH_ID_RIGHT = 0x04; /* right */ + public static final int PASSTHROUGH_ID_RIGHT_UP = 0x05; /* right-up */ + public static final int PASSTHROUGH_ID_RIGHT_DOWN = 0x06; /* right-down */ + public static final int PASSTHROUGH_ID_LEFT_UP = 0x07; /* left-up */ + public static final int PASSTHROUGH_ID_LEFT_DOWN = 0x08; /* left-down */ + public static final int PASSTHROUGH_ID_ROOT_MENU = 0x09; /* root menu */ + public static final int PASSTHROUGH_ID_SETUP_MENU = 0x0A; /* setup menu */ + public static final int PASSTHROUGH_ID_CONT_MENU = 0x0B; /* contents menu */ + public static final int PASSTHROUGH_ID_FAV_MENU = 0x0C; /* favorite menu */ + public static final int PASSTHROUGH_ID_EXIT = 0x0D; /* exit */ + public static final int PASSTHROUGH_ID_0 = 0x20; /* 0 */ + public static final int PASSTHROUGH_ID_1 = 0x21; /* 1 */ + public static final int PASSTHROUGH_ID_2 = 0x22; /* 2 */ + public static final int PASSTHROUGH_ID_3 = 0x23; /* 3 */ + public static final int PASSTHROUGH_ID_4 = 0x24; /* 4 */ + public static final int PASSTHROUGH_ID_5 = 0x25; /* 5 */ + public static final int PASSTHROUGH_ID_6 = 0x26; /* 6 */ + public static final int PASSTHROUGH_ID_7 = 0x27; /* 7 */ + public static final int PASSTHROUGH_ID_8 = 0x28; /* 8 */ + public static final int PASSTHROUGH_ID_9 = 0x29; /* 9 */ + public static final int PASSTHROUGH_ID_DOT = 0x2A; /* dot */ + public static final int PASSTHROUGH_ID_ENTER = 0x2B; /* enter */ + public static final int PASSTHROUGH_ID_CLEAR = 0x2C; /* clear */ + public static final int PASSTHROUGH_ID_CHAN_UP = 0x30; /* channel up */ + public static final int PASSTHROUGH_ID_CHAN_DOWN = 0x31; /* channel down */ + public static final int PASSTHROUGH_ID_PREV_CHAN = 0x32; /* previous channel */ + public static final int PASSTHROUGH_ID_SOUND_SEL = 0x33; /* sound select */ + public static final int PASSTHROUGH_ID_INPUT_SEL = 0x34; /* input select */ + public static final int PASSTHROUGH_ID_DISP_INFO = 0x35; /* display information */ + public static final int PASSTHROUGH_ID_HELP = 0x36; /* help */ + public static final int PASSTHROUGH_ID_PAGE_UP = 0x37; /* page up */ + public static final int PASSTHROUGH_ID_PAGE_DOWN = 0x38; /* page down */ + public static final int PASSTHROUGH_ID_POWER = 0x40; /* power */ + public static final int PASSTHROUGH_ID_VOL_UP = 0x41; /* volume up */ + public static final int PASSTHROUGH_ID_VOL_DOWN = 0x42; /* volume down */ + public static final int PASSTHROUGH_ID_MUTE = 0x43; /* mute */ + public static final int PASSTHROUGH_ID_PLAY = 0x44; /* play */ + public static final int PASSTHROUGH_ID_STOP = 0x45; /* stop */ + public static final int PASSTHROUGH_ID_PAUSE = 0x46; /* pause */ + public static final int PASSTHROUGH_ID_RECORD = 0x47; /* record */ + public static final int PASSTHROUGH_ID_REWIND = 0x48; /* rewind */ + public static final int PASSTHROUGH_ID_FAST_FOR = 0x49; /* fast forward */ + public static final int PASSTHROUGH_ID_EJECT = 0x4A; /* eject */ + public static final int PASSTHROUGH_ID_FORWARD = 0x4B; /* forward */ + public static final int PASSTHROUGH_ID_BACKWARD = 0x4C; /* backward */ + public static final int PASSTHROUGH_ID_ANGLE = 0x50; /* angle */ + public static final int PASSTHROUGH_ID_SUBPICT = 0x51; /* subpicture */ + public static final int PASSTHROUGH_ID_F1 = 0x71; /* F1 */ + public static final int PASSTHROUGH_ID_F2 = 0x72; /* F2 */ + public static final int PASSTHROUGH_ID_F3 = 0x73; /* F3 */ + public static final int PASSTHROUGH_ID_F4 = 0x74; /* F4 */ + public static final int PASSTHROUGH_ID_F5 = 0x75; /* F5 */ + public static final int PASSTHROUGH_ID_VENDOR = 0x7E; /* vendor unique */ + public static final int PASSTHROUGH_KEYPRESSED_RELEASE = 0x80; +} diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java new file mode 100644 index 000000000000..b53a8fc0f6fc --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAvrcpController.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class provides the public APIs to control the Bluetooth AVRCP Controller + * profile. + * + *<p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP + * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get + * the BluetoothAvrcpController proxy object. + * + * {@hide} + */ +public final class BluetoothAvrcpController implements BluetoothProfile { + private static final String TAG = "BluetoothAvrcpController"; + private static final boolean DBG = true; + private static final boolean VDBG = false; + + /** + * Intent used to broadcast the change in connection state of the AVRCP Controller + * profile. + * + * <p>This intent will have 3 extras: + * <ul> + * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> + * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li> + * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> + * </ul> + * + * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of + * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, + * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to + * receive. + */ + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED"; + + private Context mContext; + private ServiceListener mServiceListener; + private IBluetoothAvrcpController mService; + private BluetoothAdapter mAdapter; + + final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = + new IBluetoothStateChangeCallback.Stub() { + public void onBluetoothStateChange(boolean up) { + if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); + if (!up) { + if (VDBG) Log.d(TAG,"Unbinding service..."); + synchronized (mConnection) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } else { + synchronized (mConnection) { + try { + if (mService == null) { + if (VDBG) Log.d(TAG,"Binding service..."); + doBind(); + } + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + }; + + /** + * Create a BluetoothAvrcpController proxy object for interacting with the local + * Bluetooth AVRCP service. + * + */ + /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) { + mContext = context; + mServiceListener = l; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + + doBind(); + } + + boolean doBind() { + Intent intent = new Intent(IBluetoothAvrcpController.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, + android.os.Process.myUserHandle())) { + Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent); + return false; + } + return true; + } + + /*package*/ void close() { + mServiceListener = null; + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (Exception e) { + Log.e(TAG,"",e); + } + } + + synchronized (mConnection) { + if (mService != null) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + + public void finalize() { + close(); + } + + /** + * {@inheritDoc} + */ + public List<BluetoothDevice> getConnectedDevices() { + if (VDBG) log("getConnectedDevices()"); + if (mService != null && isEnabled()) { + try { + return mService.getConnectedDevices(); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * {@inheritDoc} + */ + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + if (VDBG) log("getDevicesMatchingStates()"); + if (mService != null && isEnabled()) { + try { + return mService.getDevicesMatchingConnectionStates(states); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * {@inheritDoc} + */ + public int getConnectionState(BluetoothDevice device) { + if (VDBG) log("getState(" + device + ")"); + if (mService != null && isEnabled() + && isValidDevice(device)) { + try { + return mService.getConnectionState(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.STATE_DISCONNECTED; + } + + public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) { + if (DBG) Log.d(TAG, "sendPassThroughCmd"); + if (mService != null && isEnabled()) { + try { + mService.sendPassThroughCmd(device, keyCode, keyState); + return; + } catch (RemoteException e) { + Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e); + return; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + } + + private final ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) Log.d(TAG, "Proxy object connected"); + mService = IBluetoothAvrcpController.Stub.asInterface(service); + + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER, + BluetoothAvrcpController.this); + } + } + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.d(TAG, "Proxy object disconnected"); + mService = null; + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER); + } + } + }; + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +} diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java new file mode 100644 index 000000000000..ff4ebee221e9 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java @@ -0,0 +1,1167 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Public API to control Hands Free Profile (HFP role only). + * <p> + * This class defines methods that shall be used by application to manage profile + * connection, calls states and calls actions. + * <p> + * + * @hide + * */ +public final class BluetoothHeadsetClient implements BluetoothProfile { + private static final String TAG = "BluetoothHeadsetClient"; + private static final boolean DBG = true; + private static final boolean VDBG = false; + + /** + * Intent sent whenever connection to remote changes. + * + * <p>It includes two extras: + * <code>BluetoothProfile.EXTRA_PREVIOUS_STATE</code> + * and <code>BluetoothProfile.EXTRA_STATE</code>, which + * are mandatory. + * <p>There are also non mandatory feature extras: + * {@link #EXTRA_AG_FEATURE_3WAY_CALLING}, + * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}, + * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT}, + * {@link #EXTRA_AG_FEATURE_REJECT_CALL}, + * {@link #EXTRA_AG_FEATURE_ECC}, + * {@link #EXTRA_AG_FEATURE_RESPONSE_AND_HOLD}, + * {@link #EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL}, + * {@link #EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL}, + * {@link #EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT}, + * {@link #EXTRA_AG_FEATURE_MERGE}, + * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH}, + * sent as boolean values only when <code>EXTRA_STATE</code> + * is set to <code>STATE_CONNECTED</code>.</p> + * + * <p>Note that features supported by AG are being sent as + * booleans with value <code>true</code>, + * and not supported ones are <strong>not</strong> being sent at all.</p> + */ + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED"; + + /** + * Intent sent whenever audio state changes. + * + * <p>It includes two mandatory extras: + * {@link BluetoothProfile.EXTRA_STATE}, + * {@link BluetoothProfile.EXTRA_PREVIOUS_STATE}, + * with possible values: + * {@link #STATE_AUDIO_CONNECTING}, + * {@link #STATE_AUDIO_CONNECTED}, + * {@link #STATE_AUDIO_DISCONNECTED}</p> + * <p>When <code>EXTRA_STATE</code> is set + * to </code>STATE_AUDIO_CONNECTED</code>, + * it also includes {@link #EXTRA_AUDIO_WBS} + * indicating wide band speech support.</p> + */ + public static final String ACTION_AUDIO_STATE_CHANGED = + "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED"; + + /** + * Intent sending updates of the Audio Gateway state. + * Each extra is being sent only when value it + * represents has been changed recently on AG. + * <p>It can contain one or more of the following extras: + * {@link #EXTRA_NETWORK_STATUS}, + * {@link #EXTRA_NETWORK_SIGNAL_STRENGTH}, + * {@link #EXTRA_NETWORK_ROAMING}, + * {@link #EXTRA_BATTERY_LEVEL}, + * {@link #EXTRA_OPERATOR_NAME}, + * {@link #EXTRA_VOICE_RECOGNITION}, + * {@link #EXTRA_IN_BAND_RING}</p> + */ + public static final String ACTION_AG_EVENT = + "android.bluetooth.headsetclient.profile.action.AG_EVENT"; + + /** + * Intent sent whenever state of a call changes. + * + * <p>It includes: + * {@link #EXTRA_CALL}, + * with value of {@link BluetoothHeadsetClientCall} instance, + * representing actual call state.</p> + */ + public static final String ACTION_CALL_CHANGED = + "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED"; + + /** + * Intent that notifies about the result of the last issued action. + * Please note that not every action results in explicit action result code being sent. + * Instead other notifications about new Audio Gateway state might be sent, + * like <code>ACTION_AG_EVENT</code> with <code>EXTRA_VOICE_RECOGNITION</code> value + * when for example user started voice recognition from HF unit. + */ + public static final String ACTION_RESULT = + "android.bluetooth.headsetclient.profile.action.RESULT"; + + /** + * Intent that notifies about the number attached to the last voice tag + * recorded on AG. + * + * <p>It contains: + * {@link #EXTRA_NUMBER}, + * with a <code>String</code> value representing phone number.</p> + */ + public static final String ACTION_LAST_VTAG = + "android.bluetooth.headsetclient.profile.action.LAST_VTAG"; + + public static final int STATE_AUDIO_DISCONNECTED = 0; + public static final int STATE_AUDIO_CONNECTING = 1; + public static final int STATE_AUDIO_CONNECTED = 2; + + /** + * Extra with information if connected audio is WBS. + * <p>Possible values: <code>true</code>, + * <code>false</code>.</p> + */ + public static final String EXTRA_AUDIO_WBS = + "android.bluetooth.headsetclient.extra.AUDIO_WBS"; + + /** + * Extra for AG_EVENT indicates network status. + * <p>Value: 0 - network unavailable, + * 1 - network available </p> + */ + public static final String EXTRA_NETWORK_STATUS = + "android.bluetooth.headsetclient.extra.NETWORK_STATUS"; + /** + * Extra for AG_EVENT intent indicates network signal strength. + * <p>Value: <code>Integer</code> representing signal strength.</p> + */ + public static final String EXTRA_NETWORK_SIGNAL_STRENGTH = + "android.bluetooth.headsetclient.extra.NETWORK_SIGNAL_STRENGTH"; + /** + * Extra for AG_EVENT intent indicates roaming state. + * <p>Value: 0 - no roaming + * 1 - active roaming</p> + */ + public static final String EXTRA_NETWORK_ROAMING = + "android.bluetooth.headsetclient.extra.NETWORK_ROAMING"; + /** + * Extra for AG_EVENT intent indicates the battery level. + * <p>Value: <code>Integer</code> representing signal strength.</p> + */ + public static final String EXTRA_BATTERY_LEVEL = + "android.bluetooth.headsetclient.extra.BATTERY_LEVEL"; + /** + * Extra for AG_EVENT intent indicates operator name. + * <p>Value: <code>String</code> representing operator name.</p> + */ + public static final String EXTRA_OPERATOR_NAME = + "android.bluetooth.headsetclient.extra.OPERATOR_NAME"; + /** + * Extra for AG_EVENT intent indicates voice recognition state. + * <p>Value: + * 0 - voice recognition stopped, + * 1 - voice recognition started.</p> + */ + public static final String EXTRA_VOICE_RECOGNITION = + "android.bluetooth.headsetclient.extra.VOICE_RECOGNITION"; + /** + * Extra for AG_EVENT intent indicates in band ring state. + * <p>Value: + * 0 - in band ring tone not supported, or + * 1 - in band ring tone supported.</p> + */ + public static final String EXTRA_IN_BAND_RING = + "android.bluetooth.headsetclient.extra.IN_BAND_RING"; + + /** + * Extra for AG_EVENT intent indicates subscriber info. + * <p>Value: <code>String</code> containing subscriber information.</p> + */ + public static final String EXTRA_SUBSCRIBER_INFO = + "android.bluetooth.headsetclient.extra.SUBSCRIBER_INFO"; + + /** + * Extra for AG_CALL_CHANGED intent indicates the + * {@link BluetoothHeadsetClientCall} object that has changed. + */ + public static final String EXTRA_CALL = + "android.bluetooth.headsetclient.extra.CALL"; + + /** + * Extra for ACTION_LAST_VTAG intent. + * <p>Value: <code>String</code> representing phone number + * corresponding to last voice tag recorded on AG</p> + */ + public static final String EXTRA_NUMBER = + "android.bluetooth.headsetclient.extra.NUMBER"; + + /** + * Extra for ACTION_RESULT intent that shows the result code of + * last issued action. + * <p>Possible results: + * {@link #ACTION_RESULT_OK}, + * {@link #ACTION_RESULT_ERROR}, + * {@link #ACTION_RESULT_ERROR_NO_CARRIER}, + * {@link #ACTION_RESULT_ERROR_BUSY}, + * {@link #ACTION_RESULT_ERROR_NO_ANSWER}, + * {@link #ACTION_RESULT_ERROR_DELAYED}, + * {@link #ACTION_RESULT_ERROR_BLACKLISTED}, + * {@link #ACTION_RESULT_ERROR_CME}</p> + */ + public static final String EXTRA_RESULT_CODE = + "android.bluetooth.headsetclient.extra.RESULT_CODE"; + + /** + * Extra for ACTION_RESULT intent that shows the extended result code of + * last issued action. + * <p>Value: <code>Integer</code> - error code.</p> + */ + public static final String EXTRA_CME_CODE = + "android.bluetooth.headsetclient.extra.CME_CODE"; + + /* Extras for AG_FEATURES, extras type is boolean */ + // TODO verify if all of those are actually useful + /** + * AG feature: three way calling. + */ + public final static String EXTRA_AG_FEATURE_3WAY_CALLING = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_3WAY_CALLING"; + /** + * AG feature: voice recognition. + */ + public final static String EXTRA_AG_FEATURE_VOICE_RECOGNITION = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_VOICE_RECOGNITION"; + /** + * AG feature: fetching phone number for voice tagging procedure. + */ + public final static String EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT"; + /** + * AG feature: ability to reject incoming call. + */ + public final static String EXTRA_AG_FEATURE_REJECT_CALL = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_REJECT_CALL"; + /** + * AG feature: enhanced call handling (terminate specific call, private consultation). + */ + public final static String EXTRA_AG_FEATURE_ECC = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ECC"; + /** + * AG feature: response and hold. + */ + public final static String EXTRA_AG_FEATURE_RESPONSE_AND_HOLD = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RESPONSE_AND_HOLD"; + /** + * AG call handling feature: accept held or waiting call in three way calling scenarios. + */ + public final static String EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL"; + /** + * AG call handling feature: release held or waiting call in three way calling scenarios. + */ + public final static String EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL"; + /** + * AG call handling feature: release active call and accept held or waiting call in three way + * calling scenarios. + */ + public final static String EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT"; + /** + * AG call handling feature: merge two calls, held and active - multi party conference mode. + */ + public final static String EXTRA_AG_FEATURE_MERGE = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE"; + /** + * AG call handling feature: merge calls and disconnect from multi party + * conversation leaving peers connected to each other. + * Note that this feature needs to be supported by mobile network operator + * as it requires connection and billing transfer. + */ + public final static String EXTRA_AG_FEATURE_MERGE_AND_DETACH = + "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE_AND_DETACH"; + + /* Action result codes */ + public final static int ACTION_RESULT_OK = 0; + public final static int ACTION_RESULT_ERROR = 1; + public final static int ACTION_RESULT_ERROR_NO_CARRIER = 2; + public final static int ACTION_RESULT_ERROR_BUSY = 3; + public final static int ACTION_RESULT_ERROR_NO_ANSWER = 4; + public final static int ACTION_RESULT_ERROR_DELAYED = 5; + public final static int ACTION_RESULT_ERROR_BLACKLISTED = 6; + public final static int ACTION_RESULT_ERROR_CME = 7; + + /* Detailed CME error codes */ + public final static int CME_PHONE_FAILURE = 0; + public final static int CME_NO_CONNECTION_TO_PHONE = 1; + public final static int CME_OPERATION_NOT_ALLOWED = 3; + public final static int CME_OPERATION_NOT_SUPPORTED = 4; + public final static int CME_PHSIM_PIN_REQUIRED = 5; + public final static int CME_PHFSIM_PIN_REQUIRED = 6; + public final static int CME_PHFSIM_PUK_REQUIRED = 7; + public final static int CME_SIM_NOT_INSERTED = 10; + public final static int CME_SIM_PIN_REQUIRED = 11; + public final static int CME_SIM_PUK_REQUIRED = 12; + public final static int CME_SIM_FAILURE = 13; + public final static int CME_SIM_BUSY = 14; + public final static int CME_SIM_WRONG = 15; + public final static int CME_INCORRECT_PASSWORD = 16; + public final static int CME_SIM_PIN2_REQUIRED = 17; + public final static int CME_SIM_PUK2_REQUIRED = 18; + public final static int CME_MEMORY_FULL = 20; + public final static int CME_INVALID_INDEX = 21; + public final static int CME_NOT_FOUND = 22; + public final static int CME_MEMORY_FAILURE = 23; + public final static int CME_TEXT_STRING_TOO_LONG = 24; + public final static int CME_INVALID_CHARACTER_IN_TEXT_STRING = 25; + public final static int CME_DIAL_STRING_TOO_LONG = 26; + public final static int CME_INVALID_CHARACTER_IN_DIAL_STRING = 27; + public final static int CME_NO_NETWORK_SERVICE = 30; + public final static int CME_NETWORK_TIMEOUT = 31; + public final static int CME_EMERGENCY_SERVICE_ONLY = 32; + public final static int CME_NO_SIMULTANOUS_VOIP_CS_CALLS = 33; + public final static int CME_NOT_SUPPORTED_FOR_VOIP = 34; + public final static int CME_SIP_RESPONSE_CODE = 35; + public final static int CME_NETWORK_PERSONALIZATION_PIN_REQUIRED = 40; + public final static int CME_NETWORK_PERSONALIZATION_PUK_REQUIRED = 41; + public final static int CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED = 42; + public final static int CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED = 43; + public final static int CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED = 44; + public final static int CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED = 45; + public final static int CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED = 46; + public final static int CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED = 47; + public final static int CME_HIDDEN_KEY_REQUIRED = 48; + public final static int CME_EAP_NOT_SUPPORTED = 49; + public final static int CME_INCORRECT_PARAMETERS = 50; + + /* Action policy for other calls when accepting call */ + public static final int CALL_ACCEPT_NONE = 0; + public static final int CALL_ACCEPT_HOLD = 1; + public static final int CALL_ACCEPT_TERMINATE = 2; + + private Context mContext; + private ServiceListener mServiceListener; + private IBluetoothHeadsetClient mService; + private BluetoothAdapter mAdapter; + + final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = + new IBluetoothStateChangeCallback.Stub() { + @Override + public void onBluetoothStateChange(boolean up) { + if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); + if (!up) { + if (VDBG) Log.d(TAG,"Unbinding service..."); + synchronized (mConnection) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } else { + synchronized (mConnection) { + try { + if (mService == null) { + if (VDBG) Log.d(TAG,"Binding service..."); + Intent intent = new Intent(IBluetoothHeadsetClient.class.getName()); + doBind(); + } + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + } + }; + + /** + * Create a BluetoothHeadsetClient proxy object. + */ + /*package*/ BluetoothHeadsetClient(Context context, ServiceListener l) { + mContext = context; + mServiceListener = l; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException e) { + Log.e(TAG,"",e); + } + } + + doBind(); + } + + boolean doBind() { + Intent intent = new Intent(IBluetoothHeadsetClient.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, + android.os.Process.myUserHandle())) { + Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent); + return false; + } + return true; + } + + /** + * Close the connection to the backing service. + * Other public functions of BluetoothHeadsetClient will return default error + * results once close() has been called. Multiple invocations of close() + * are ok. + */ + /*package*/ void close() { + if (VDBG) log("close()"); + + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (Exception e) { + Log.e(TAG,"",e); + } + } + + synchronized (mConnection) { + if (mService != null) { + try { + mService = null; + mContext.unbindService(mConnection); + } catch (Exception re) { + Log.e(TAG,"",re); + } + } + } + mServiceListener = null; + } + + /** + * Connects to remote device. + * + * Currently, the system supports only 1 connection. So, in case of the + * second connection, this implementation will disconnect already connected + * device automatically and will process the new one. + * + * @param device a remote device we want connect to + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED} + * intent. + */ + public boolean connect(BluetoothDevice device) { + if (DBG) log("connect(" + device + ")"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.connect(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Disconnects remote device + * + * @param device a remote device we want disconnect + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED} + * intent. + */ + public boolean disconnect(BluetoothDevice device) { + if (DBG) log("disconnect(" + device + ")"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.disconnect(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Return the list of connected remote devices + * + * @return list of connected devices; empty list if nothing is connected. + */ + @Override + public List<BluetoothDevice> getConnectedDevices() { + if (VDBG) log("getConnectedDevices()"); + if (mService != null && isEnabled()) { + try { + return mService.getConnectedDevices(); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * Returns list of remote devices in a particular state + * + * @param states collection of states + * @return list of devices that state matches the states listed in + * <code>states</code>; empty list if nothing matches the + * <code>states</code> + */ + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + if (VDBG) log("getDevicesMatchingStates()"); + if (mService != null && isEnabled()) { + try { + return mService.getDevicesMatchingConnectionStates(states); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return new ArrayList<BluetoothDevice>(); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return new ArrayList<BluetoothDevice>(); + } + + /** + * Returns state of the <code>device</code> + * + * @param device a remote device + * @return the state of connection of the device + */ + @Override + public int getConnectionState(BluetoothDevice device) { + if (VDBG) log("getConnectionState(" + device + ")"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.getConnectionState(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return BluetoothProfile.STATE_DISCONNECTED; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return BluetoothProfile.STATE_DISCONNECTED; + } + + /** + * Set priority of the profile + * + * The device should already be paired. + */ + public boolean setPriority(BluetoothDevice device, int priority) { + if (DBG) log("setPriority(" + device + ", " + priority + ")"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + if (priority != BluetoothProfile.PRIORITY_OFF && + priority != BluetoothProfile.PRIORITY_ON) { + return false; + } + try { + return mService.setPriority(device, priority); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Get the priority of the profile. + */ + public int getPriority(BluetoothDevice device) { + if (VDBG) log("getPriority(" + device + ")"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.getPriority(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + return PRIORITY_OFF; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return PRIORITY_OFF; + } + + /** + * Starts voice recognition. + * + * @param device remote device + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_AG_EVENT} + * intent. + * + * <p>Feature required for successful execution is being reported by: + * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. + * This method invocation will fail silently when feature is not supported.</p> + */ + public boolean startVoiceRecognition(BluetoothDevice device) { + if (DBG) log("startVoiceRecognition()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.startVoiceRecognition(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Stops voice recognition. + * + * @param device remote device + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_AG_EVENT} + * intent. + * + * <p>Feature required for successful execution is being reported by: + * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. + * This method invocation will fail silently when feature is not supported.</p> + */ + public boolean stopVoiceRecognition(BluetoothDevice device) { + if (DBG) log("stopVoiceRecognition()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.stopVoiceRecognition(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Returns list of all calls in any state. + * + * @param device remote device + * @return list of calls; empty list if none call exists + */ + public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { + if (DBG) log("getCurrentCalls()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.getCurrentCalls(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return null; + } + + /** + * Returns list of current values of AG indicators. + * + * @param device remote device + * @return bundle of AG indicators; null if device is not in + * CONNECTED state + */ + public Bundle getCurrentAgEvents(BluetoothDevice device) { + if (DBG) log("getCurrentCalls()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.getCurrentAgEvents(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return null; + } + + /** + * Accepts a call + * + * @param device remote device + * @param flag action policy while accepting a call. Possible values + * {@link #CALL_ACCEPT_NONE}, {@link #CALL_ACCEPT_HOLD}, + * {@link #CALL_ACCEPT_TERMINATE} + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent. + */ + public boolean acceptCall(BluetoothDevice device, int flag) { + if (DBG) log("acceptCall()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.acceptCall(device, flag); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Holds a call. + * + * @param device remote device + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent. + */ + public boolean holdCall(BluetoothDevice device) { + if (DBG) log("holdCall()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.holdCall(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Rejects a call. + * + * @param device remote device + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent. + * + * <p>Feature required for successful execution is being reported by: + * {@link #EXTRA_AG_FEATURE_REJECT_CALL}. + * This method invocation will fail silently when feature is not supported.</p> + */ + public boolean rejectCall(BluetoothDevice device) { + if (DBG) log("rejectCall()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.rejectCall(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Terminates a specified call. + * + * Works only when Extended Call Control is supported by Audio Gateway. + * + * @param device remote device + * @param index index of the call to be terminated + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent. + * + * <p>Feature required for successful execution is being reported by: + * {@link #EXTRA_AG_FEATURE_ECC}. + * This method invocation will fail silently when feature is not supported.</p> + */ + public boolean terminateCall(BluetoothDevice device, int index) { + if (DBG) log("terminateCall()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.terminateCall(device, index); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Enters private mode with a specified call. + * + * Works only when Extended Call Control is supported by Audio Gateway. + * + * @param device remote device + * @param index index of the call to connect in private mode + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent. + * + * <p>Feature required for successful execution is being reported by: + * {@link #EXTRA_AG_FEATURE_ECC}. + * This method invocation will fail silently when feature is not supported.</p> + */ + public boolean enterPrivateMode(BluetoothDevice device, int index) { + if (DBG) log("enterPrivateMode()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.enterPrivateMode(device, index); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Performs explicit call transfer. + * + * That means connect other calls and disconnect. + * + * @param device remote device + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent. + * + * <p>Feature required for successful execution is being reported by: + * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH}. + * This method invocation will fail silently when feature is not supported.</p> + */ + public boolean explicitCallTransfer(BluetoothDevice device) { + if (DBG) log("explicitCallTransfer()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.explicitCallTransfer(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Redials last number from Audio Gateway. + * + * @param device remote device + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent in case of success; {@link #ACTION_RESULT} is sent + * otherwise; + */ + public boolean redial(BluetoothDevice device) { + if (DBG) log("redial()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.redial(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Places a call with specified number. + * + * @param device remote device + * @param number valid phone number + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent in case of success; {@link #ACTION_RESULT} is sent + * otherwise; + */ + public boolean dial(BluetoothDevice device, String number) { + if (DBG) log("dial()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.dial(device, number); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Places a call to the number under specified memory location. + * + * @param device remote device + * @param location valid memory location + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_CALL_CHANGED} + * intent in case of success; {@link #ACTION_RESULT} is sent + * otherwise; + */ + public boolean dialMemory(BluetoothDevice device, int location) { + if (DBG) log("dialMemory()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.dialMemory(device, location); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Sends DTMF code. + * + * Possible code values : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,*,# + * + * @param device remote device + * @param code ASCII code + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_RESULT} intent; + */ + public boolean sendDTMF(BluetoothDevice device, byte code) { + if (DBG) log("sendDTMF()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.sendDTMF(device, code); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Get a number corresponding to last voice tag recorded on AG. + * + * @param device remote device + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_LAST_VTAG} + * or {@link #ACTION_RESULT} intent; + * + * <p>Feature required for successful execution is being reported by: + * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT}. + * This method invocation will fail silently when feature is not supported.</p> + */ + public boolean getLastVoiceTagNumber(BluetoothDevice device) { + if (DBG) log("getLastVoiceTagNumber()"); + if (mService != null && isEnabled() && + isValidDevice(device)) { + try { + return mService.getLastVoiceTagNumber(device); + } catch (RemoteException e) { + Log.e(TAG, Log.getStackTraceString(new Throwable())); + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Accept the incoming connection. + */ + public boolean acceptIncomingConnect(BluetoothDevice device) { + if (DBG) log("acceptIncomingConnect"); + if (mService != null && isEnabled()) { + try { + return mService.acceptIncomingConnect(device); + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return false; + } + + /** + * Reject the incoming connection. + */ + public boolean rejectIncomingConnect(BluetoothDevice device) { + if (DBG) log("rejectIncomingConnect"); + if (mService != null) { + try { + return mService.rejectIncomingConnect(device); + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return false; + } + + /** + * Returns current audio state of Audio Gateway. + * + * Note: This is an internal function and shouldn't be exposed + */ + public int getAudioState(BluetoothDevice device) { + if (VDBG) log("getAudioState"); + if (mService != null && isEnabled()) { + try { + return mService.getAudioState(device); + } catch (RemoteException e) {Log.e(TAG, e.toString());} + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; + } + + /** + * Initiates a connection of audio channel. + * + * It setup SCO channel with remote connected Handsfree AG device. + * + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} + * intent; + */ + public boolean connectAudio() { + if (mService != null && isEnabled()) { + try { + return mService.connectAudio(); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return false; + } + + /** + * Disconnects audio channel. + * + * It tears down the SCO channel from remote AG device. + * + * @return <code>true</code> if command has been issued successfully; + * <code>false</code> otherwise; + * upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} + * intent; + */ + public boolean disconnectAudio() { + if (mService != null && isEnabled()) { + try { + return mService.disconnectAudio(); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return false; + } + + /** + * Get Audio Gateway features + * + * @param device remote device + * @return bundle of AG features; null if no service or + * AG not connected + */ + public Bundle getCurrentAgFeatures(BluetoothDevice device) { + if (mService != null && isEnabled()) { + try { + return mService.getCurrentAgFeatures(device); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); + } + return null; + } + + + private ServiceConnection mConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + if (DBG) Log.d(TAG, "Proxy object connected"); + mService = IBluetoothHeadsetClient.Stub.asInterface(service); + + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT, + BluetoothHeadsetClient.this); + } + } + @Override + public void onServiceDisconnected(ComponentName className) { + if (DBG) Log.d(TAG, "Proxy object disconnected"); + mService = null; + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET_CLIENT); + } + } + }; + + private boolean isEnabled() { + if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true; + return false; + } + + private boolean isValidDevice(BluetoothDevice device) { + if (device == null) return false; + + if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true; + return false; + } + + private static void log(String msg) { + Log.d(TAG, msg); + } +} diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl b/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl new file mode 100644 index 000000000000..35f792387ec7 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +parcelable BluetoothHeadsetClientCall; diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java new file mode 100644 index 000000000000..a15bd975ad84 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class represents a single call, its state and properties. + * It implements {@link Parcelable} for inter-process message passing. + * @hide + */ +public final class BluetoothHeadsetClientCall implements Parcelable { + + /* Call state */ + /** + * Call is active. + */ + public static final int CALL_STATE_ACTIVE = 0; + /** + * Call is in held state. + */ + public static final int CALL_STATE_HELD = 1; + /** + * Outgoing call that is being dialed right now. + */ + public static final int CALL_STATE_DIALING = 2; + /** + * Outgoing call that remote party has already been alerted about. + */ + public static final int CALL_STATE_ALERTING = 3; + /** + * Incoming call that can be accepted or rejected. + */ + public static final int CALL_STATE_INCOMING = 4; + /** + * Waiting call state when there is already an active call. + */ + public static final int CALL_STATE_WAITING = 5; + /** + * Call that has been held by response and hold + * (see Bluetooth specification for further references). + */ + public static final int CALL_STATE_HELD_BY_RESPONSE_AND_HOLD = 6; + /** + * Call that has been already terminated and should not be referenced as a valid call. + */ + public static final int CALL_STATE_TERMINATED = 7; + + private final int mId; + private int mState; + private String mNumber; + private boolean mMultiParty; + private final boolean mOutgoing; + + /** + * Creates BluetoothHeadsetClientCall instance. + */ + public BluetoothHeadsetClientCall(int id, int state, String number, boolean multiParty, + boolean outgoing) { + mId = id; + mState = state; + mNumber = number != null ? number : ""; + mMultiParty = multiParty; + mOutgoing = outgoing; + } + + /** + * Sets call's state. + * + * <p>Note: This is an internal function and shouldn't be exposed</p> + * + * @param state new call state. + */ + public void setState(int state) { + mState = state; + } + + /** + * Sets call's number. + * + * <p>Note: This is an internal function and shouldn't be exposed</p> + * + * @param number String representing phone number. + */ + public void setNumber(String number) { + mNumber = number; + } + + /** + * Sets this call as multi party call. + * + * <p>Note: This is an internal function and shouldn't be exposed</p> + * + * @param multiParty if <code>true</code> sets this call as a part + * of multi party conference. + */ + public void setMultiParty(boolean multiParty) { + mMultiParty = multiParty; + } + + /** + * Gets call's Id. + * + * @return call id. + */ + public int getId() { + return mId; + } + + /** + * Gets call's current state. + * + * @return state of this particular phone call. + */ + public int getState() { + return mState; + } + + /** + * Gets call's number. + * + * @return string representing phone number. + */ + public String getNumber() { + return mNumber; + } + + /** + * Checks if call is an active call in a conference mode (aka multi party). + * + * @return <code>true</code> if call is a multi party call, + * <code>false</code> otherwise. + */ + public boolean isMultiParty() { + return mMultiParty; + } + + /** + * Checks if this call is an outgoing call. + * + * @return <code>true</code> if its outgoing call, + * <code>false</code> otherwise. + */ + public boolean isOutgoing() { + return mOutgoing; + } + + public String toString() { + StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mId: "); + builder.append(mId); + builder.append(", mState: "); + switch (mState) { + case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break; + case CALL_STATE_HELD: builder.append("HELD"); break; + case CALL_STATE_DIALING: builder.append("DIALING"); break; + case CALL_STATE_ALERTING: builder.append("ALERTING"); break; + case CALL_STATE_INCOMING: builder.append("INCOMING"); break; + case CALL_STATE_WAITING: builder.append("WAITING"); break; + case CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: builder.append("HELD_BY_RESPONSE_AND_HOLD"); break; + case CALL_STATE_TERMINATED: builder.append("TERMINATED"); break; + default: builder.append(mState); break; + } + builder.append(", mNumber: "); + builder.append(mNumber); + builder.append(", mMultiParty: "); + builder.append(mMultiParty); + builder.append(", mOutgoing: "); + builder.append(mOutgoing); + builder.append("}"); + return builder.toString(); + } + + /** + * {@link Parcelable.Creator} interface implementation. + */ + public static final Parcelable.Creator<BluetoothHeadsetClientCall> CREATOR = + new Parcelable.Creator<BluetoothHeadsetClientCall>() { + @Override + public BluetoothHeadsetClientCall createFromParcel(Parcel in) { + return new BluetoothHeadsetClientCall(in.readInt(), in.readInt(), + in.readString(), in.readInt() == 1, in.readInt() == 1); + } + + @Override + public BluetoothHeadsetClientCall[] newArray(int size) { + return new BluetoothHeadsetClientCall[size]; + } + }; + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mId); + out.writeInt(mState); + out.writeString(mNumber); + out.writeInt(mMultiParty ? 1 : 0); + out.writeInt(mOutgoing ? 1 : 0); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index d89806028556..136740505a4a 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2010-2014 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. @@ -110,6 +110,18 @@ public interface BluetoothProfile { public static final int A2DP_SINK = 10; /** + * AVRCP Controller Profile + * @hide + */ + public static final int AVRCP_CONTROLLER = 11; + + /** + * Headset Client - HFP HF Role + * @hide + */ + public static final int HEADSET_CLIENT = 16; + + /** * Default priority for devices that we try to auto-connect to and * and allow incoming connections for the profile * @hide diff --git a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl new file mode 100644 index 000000000000..b7c647677000 --- /dev/null +++ b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +import android.bluetooth.BluetoothAudioConfig; +import android.bluetooth.BluetoothDevice; + +/** + * APIs for Bluetooth A2DP sink service + * + * @hide + */ +interface IBluetoothA2dpSink { + boolean connect(in BluetoothDevice device); + boolean disconnect(in BluetoothDevice device); + List<BluetoothDevice> getConnectedDevices(); + List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); + int getConnectionState(in BluetoothDevice device); + BluetoothAudioConfig getAudioConfig(in BluetoothDevice device); +} diff --git a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl new file mode 100644 index 000000000000..f917a50860b7 --- /dev/null +++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +import android.bluetooth.BluetoothDevice; + +/** + * APIs for Bluetooth AVRCP controller service + * + * @hide + */ +interface IBluetoothAvrcpController { + List<BluetoothDevice> getConnectedDevices(); + List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); + int getConnectionState(in BluetoothDevice device); + void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState); +} diff --git a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl new file mode 100644 index 000000000000..e518b7d225f8 --- /dev/null +++ b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 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.bluetooth; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadsetClientCall; +import android.os.Bundle; + +/** + * API for Bluetooth Headset Client service (HFP HF Role) + * + * {@hide} + */ +interface IBluetoothHeadsetClient { + boolean connect(in BluetoothDevice device); + boolean disconnect(in BluetoothDevice device); + + boolean acceptIncomingConnect(in BluetoothDevice device); + boolean rejectIncomingConnect(in BluetoothDevice device); + + List<BluetoothDevice> getConnectedDevices(); + List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states); + int getConnectionState(in BluetoothDevice device); + boolean setPriority(in BluetoothDevice device, int priority); + int getPriority(in BluetoothDevice device); + + boolean startVoiceRecognition(in BluetoothDevice device); + boolean stopVoiceRecognition(in BluetoothDevice device); + + List<BluetoothHeadsetClientCall> getCurrentCalls(in BluetoothDevice device); + Bundle getCurrentAgEvents(in BluetoothDevice device); + + boolean acceptCall(in BluetoothDevice device, int flag); + boolean holdCall(in BluetoothDevice device); + boolean rejectCall(in BluetoothDevice device); + boolean terminateCall(in BluetoothDevice device, int index); + + boolean enterPrivateMode(in BluetoothDevice device, int index); + boolean explicitCallTransfer(in BluetoothDevice device); + + boolean redial(in BluetoothDevice device); + boolean dial(in BluetoothDevice device, String number); + boolean dialMemory(in BluetoothDevice device, int location); + + boolean sendDTMF(in BluetoothDevice device, byte code); + boolean getLastVoiceTagNumber(in BluetoothDevice device); + + int getAudioState(in BluetoothDevice device); + boolean connectAudio(); + boolean disconnectAudio(); + + Bundle getCurrentAgFeatures(in BluetoothDevice device); +} diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 453ee179a239..f75ae5588ba5 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13529,6 +13529,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, throw new IllegalStateException("This view must be attached to a window first"); } + if (getWidth() == 0 || getHeight() == 0) { + return; + } + switch (mLayerType) { case LAYER_TYPE_HARDWARE: // The only part of a hardware layer we can build in response to diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java index 588b868726c3..4a7f5fdf1f66 100644 --- a/core/java/android/webkit/ClientCertRequest.java +++ b/core/java/android/webkit/ClientCertRequest.java @@ -27,7 +27,7 @@ import java.security.cert.X509Certificate; * such as the host name and the port number requesting the cert, the acceptable * key types and the principals. * - * The user should call one of the interface methods to indicate how to deal + * The user should call one of the class methods to indicate how to deal * with the client certificate request. All methods should be called on * UI thread. * @@ -37,42 +37,45 @@ import java.security.cert.X509Certificate; * {@link WebView#clearClientCertPreferences}. * */ -public interface ClientCertRequest { +public abstract class ClientCertRequest { + + public ClientCertRequest() { } + /** * Returns the acceptable types of asymmetric keys (can be null). */ - public String[] getKeyTypes(); + public abstract String[] getKeyTypes(); /** * Returns the acceptable certificate issuers for the certificate * matching the private key (can be null). */ - public Principal[] getPrincipals(); + public abstract Principal[] getPrincipals(); /** * Returns the host name of the server requesting the certificate. */ - public String getHost(); + public abstract String getHost(); /** * Returns the port number of the server requesting the certificate. */ - public int getPort(); + public abstract int getPort(); /** * Proceed with the specified private key and client certificate chain. * Remember the user's positive choice and use it for future requests. */ - public void proceed(PrivateKey privateKey, X509Certificate[] chain); + public abstract void proceed(PrivateKey privateKey, X509Certificate[] chain); /** * Ignore the request for now. Do not remember user's choice. */ - public void ignore(); + public abstract void ignore(); /** * Cancel this request. Remember the user's choice and use it for * future requests. */ - public void cancel(); + public abstract void cancel(); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 91ca7b4619f9..482c7e8aa2a3 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -1486,11 +1486,11 @@ public class WebView extends AbsoluteLayout } /** - * Clears the client certificate preferences table stored in response - * to proceeding/cancelling client cert requests. Note that webview + * Clears the client certificate preferences stored in response + * to proceeding/cancelling client cert requests. Note that Webview * automatically clears these preferences when it receives a - * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The client certificate - * preferences are global for all Webviews. + * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The preferences are + * shared by all the webviews that are created by the embedder application. * * @param onCleared A runnable to be invoked when client certs are cleared. * The embedder can pass null if not interested in the diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 3067cdd0209d..b628b7ca918e 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -123,10 +123,30 @@ <protected-broadcast android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" /> <protected-broadcast + android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" /> + <protected-broadcast + android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" /> + <protected-broadcast + android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" /> + <protected-broadcast + android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" /> + <protected-broadcast + android:name="android.bluetooth.headsetclient.profile.action.RESULT" /> + <protected-broadcast + android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" /> + <protected-broadcast android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" /> <protected-broadcast + android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" /> + <protected-broadcast + android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" /> + <protected-broadcast + android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" /> + <protected-broadcast + android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" /> + <protected-broadcast android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" /> diff --git a/core/res/assets/images/android-logo-mask.png b/core/res/assets/images/android-logo-mask.png Binary files differindex 3078b28886cf..ad40645e8943 100644 --- a/core/res/assets/images/android-logo-mask.png +++ b/core/res/assets/images/android-logo-mask.png diff --git a/core/res/assets/images/android-logo-shine.png b/core/res/assets/images/android-logo-shine.png Binary files differindex add67968840f..cb65f229eb52 100644 --- a/core/res/assets/images/android-logo-shine.png +++ b/core/res/assets/images/android-logo-shine.png diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java index a5a074cd0e91..e1dec9d7e940 100644 --- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java @@ -537,4 +537,3 @@ public class AnimatedStateListDrawable extends StateListDrawable { } } } - diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index 16548d0801ef..1ee022490e7b 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -91,10 +91,10 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An @Override public boolean setVisible(boolean visible, boolean restart) { - boolean changed = super.setVisible(visible, restart); + final boolean changed = super.setVisible(visible, restart); if (visible) { if (changed || restart) { - setFrame(0, true, restart || mCurFrame >= 0); + setFrame(0, true, mAnimating); } } else { unscheduleSelf(this); diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java index 0d70e7503792..345400e399da 100644 --- a/graphics/java/android/graphics/drawable/Ripple.java +++ b/graphics/java/android/graphics/drawable/Ripple.java @@ -38,15 +38,18 @@ import java.util.ArrayList; */ class Ripple { private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); - private static final TimeInterpolator DECEL_INTERPOLATOR = new DecelerateInterpolator(4); + private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator(); private static final float GLOBAL_SPEED = 1.0f; private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED; - private static final float WAVE_TOUCH_UP_ACCELERATION = 3096.0f * GLOBAL_SPEED; - private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.9f / GLOBAL_SPEED; - private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED; + private static final float WAVE_TOUCH_UP_ACCELERATION = 3400.0f * GLOBAL_SPEED; + private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED; + private static final float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED; + private static final float WAVE_OUTER_OPACITY_VELOCITY_MIN = 1.5f * GLOBAL_SPEED; + private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f; + private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f; - private static final long RIPPLE_ENTER_DELAY = 100; + private static final long RIPPLE_ENTER_DELAY = 80; // Hardware animators. private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>(); @@ -311,7 +314,7 @@ class Ripple { public void enter() { final int radiusDuration = (int) (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5); - final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY); + final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN); final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1); radius.setAutoCancel(true); @@ -355,7 +358,6 @@ class Ripple { */ public void exit() { cancelSoftwareAnimations(); - final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); final float remaining; if (mAnimRadius != null && mAnimRadius.isRunning()) { @@ -368,13 +370,23 @@ class Ripple { + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5); final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f); + // Scale the outer max opacity and opacity velocity based + // on the size of the outer radius + + float outerSizeInfluence = MathUtils.constrain( + (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity) + / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1); + float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_VELOCITY_MIN, + WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence); + // Determine at what time the inner and outer opacity intersect. // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000 // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000 + final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity) - / (WAVE_OPACITY_DECAY_VELOCITY + WAVE_OUTER_OPACITY_VELOCITY) + 0.5f)); + / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f)); final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection - * WAVE_OUTER_OPACITY_VELOCITY / 1000) + 0.5f); + * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f); if (mCanUseHardware) { exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity); @@ -606,4 +618,14 @@ class Ripple { removeSelf(); } }; + + /** + * Interpolator with a smooth log deceleration + */ + private static final class LogInterpolator implements TimeInterpolator { + @Override + public float getInterpolation(float input) { + return 1 - (float) Math.pow(400, -input * 1.4); + } + } } diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png Binary files differindex fa5a0f0382a8..b28624f7f79d 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png Binary files differindex d88397ec0c97..9ce434d67b66 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png Binary files differindex 59d4695abf4a..51dce693418c 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png Binary files differindex bbebcb1317ad..3f3e288a46e3 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png Binary files differindex 93dc268b746b..9856cbf871b8 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png Binary files differindex 00738729bc8e..6910456f1523 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png Binary files differindex 00738729bc8e..e8c6ec63fead 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png Binary files differindex 8a3d69c1ad70..06dcd2079e73 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png Binary files differindex 0afd6fe1484d..240f536bbcd6 100644 --- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png Binary files differindex 6ca3652c0366..e464347cf07d 100644 --- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png Binary files differindex 66f5c06aee34..f8b59e883543 100644 --- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png Binary files differindex e49a2af970a0..1b578a68f322 100644 --- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png Binary files differindex 84879b99c5b3..80ecaba37ae9 100644 --- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png Binary files differindex d005f61c3a3c..c7bf2c7794b0 100644 --- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png Binary files differindex dca30abaf865..278de4263027 100644 --- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png Binary files differindex 6915a4a18de9..464831ccbb9a 100644 --- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png Binary files differindex 309fd4e3abe0..c24132cd5068 100644 --- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png Binary files differindex 23b570e5438d..bc84f221271c 100644 --- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png Binary files differindex 1c5f73f26535..f4e219ee098c 100644 --- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png Binary files differindex 40cf808793ee..ece2e378d4e7 100644 --- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png Binary files differindex 36dd2be22bc5..d524dcfc8b7b 100644 --- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png Binary files differindex 3b979cd5e724..373e84a999db 100644 --- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png Binary files differindex e8d1dea2196e..e5a102ab22ea 100644 --- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png Binary files differindex 0ab099162905..6b19593ea805 100644 --- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png Binary files differindex 4ced46b608d1..a5e0686be797 100644 --- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png Binary files differindex 891397c5c56f..f878093ab387 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png Binary files differindex 5cf38551453f..7780b160437a 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png Binary files differindex edb5b1fd157c..343d0dd31d2f 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png Binary files differindex 3212336ea36b..8e9583b231bb 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png Binary files differindex 7aff620e8ab6..7d387037134b 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png Binary files differindex 9f66c14aa63e..6e186a34a458 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png Binary files differindex 9f66c14aa63e..12b40427a9b2 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png Binary files differindex 972b1a855473..e2a89c3ce8ac 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png Binary files differindex 473b0cbe5c77..311720b37ffb 100644 --- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png Binary files differindex 8ad60a559ccd..67e4ee78ce8a 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png Binary files differindex 17cc7221dd40..dfef430806c8 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png Binary files differindex 6fa0d5f03a7a..de6d1092f4a7 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png Binary files differindex 70b3ef643046..7d0c3fbe6c18 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png Binary files differindex be6a5ef134f2..3baeb52c26a7 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png Binary files differindex b26600d7f554..d5b48e8a25ae 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png Binary files differindex b26600d7f554..26d7e7b8a7af 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png Binary files differindex f2cb7be85f05..c49198dcf88d 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png Binary files differindex 170bdb67ebbc..2a21f29c0c8e 100644 --- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png Binary files differindex b4bea6d899fd..538d7d1fc97e 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png Binary files differindex eb0eca1efa24..eb8e80b6d286 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png Binary files differindex 3d8d19b136bb..1c2c35a3fc0e 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png Binary files differindex 0f6fdadf0c46..eec613f3cfb2 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png Binary files differindex cbe5f77c0bc1..1c0bad8a99b6 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png Binary files differindex 80eb80359a3f..1293fa8a55b1 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png Binary files differindex 80eb80359a3f..96a9cce282cb 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png Binary files differindex a6d892f1a877..9ffc80ada55e 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png Binary files differindex 7183b81360b9..aa9b57bcebf4 100644 --- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png Binary files differindex 657d546bda2d..b34352225809 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png Binary files differindex df23594d7853..f2f7b506113c 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png Binary files differindex ab27aecc4762..383398ce1e60 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png Binary files differindex 31f98e10db0c..53444ab88f97 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png Binary files differindex 104aed78bd93..4294937a0885 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png Binary files differindex 18e113aae328..7cb3ee45e164 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png Binary files differindex 18e113aae328..b0179460ccc3 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png Binary files differindex 079e68d6d0f8..e8dd07c7e9b0 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png Binary files differindex c38b43ae2f41..f396ea9075d6 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png Binary files differindex c9507af7620d..1b817cf41f73 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png Binary files differindex 242677660e32..21b7a06bc2da 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png Binary files differindex 48fb7816c4b8..676fc14d591c 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png Binary files differindex c6fb9bf59d49..26f4ba9fa2f5 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png Binary files differindex 528df6d500d4..ea21b609b334 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png Binary files differindex 055070ab9474..c7d77c2f8fcd 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png Binary files differindex 055070ab9474..ae12cfdd6b27 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png Binary files differindex e17e8f42e8cc..8c27d451bb04 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png Binary files differindex aafee031d96e..c98827c80b18 100644 --- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png +++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png Binary files differindex e3cf7a683a06..ec2951d3f219 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png Binary files differindex 7e034b84e4f4..5103190e096b 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png Binary files differindex a4b3a684e00a..818aa4fa7607 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png Binary files differindex 321fadb20f30..254f75774368 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png Binary files differindex 6e3219f543d6..f0de417d80dc 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png Binary files differindex 2b6021b55b1f..97f1526ba6ac 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png Binary files differindex 2b6021b55b1f..773fa9486530 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png Binary files differindex 023ca546b95a..8a8e94130375 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png Binary files differindex 3c9dccbf6a65..ad7dfc3862d2 100644 --- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png Binary files differindex d8f170311dd4..77969b895860 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png Binary files differindex 4e12cc94ba17..b171f920f6a1 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png Binary files differindex 37951a041a16..ad35c65045d4 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png Binary files differindex 7281482d976e..d60229f600b9 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png Binary files differindex a13418c006a6..8fffa8e3410b 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png Binary files differindex 066c2d9ed9ad..921505519bf3 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png Binary files differindex a619a940ee3b..bcf7eb18569f 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png Binary files differindex 115109a1ed94..a261f850798c 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png Binary files differindex 3101cb021873..4c612f721a47 100755..100644 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 09a94f50df65..c8851dc7d83c 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -120,11 +120,13 @@ duration of the transition in to recents. --> <integer name="recents_animate_task_bar_enter_delay">225</integer> <!-- The min animation duration for animating the task bar out. --> + <integer name="recents_animate_task_exit_to_home_duration">225</integer> + <!-- The min animation duration for animating the task bar out. --> <integer name="recents_animate_task_bar_exit_duration">125</integer> <!-- The min animation duration for animating the task in when transitioning from home. --> - <integer name="recents_animate_task_enter_from_home_duration">325</integer> + <integer name="recents_animate_task_enter_from_home_duration">275</integer> <!-- The animation stagger to apply to each task animation when transitioning from home. --> - <integer name="recents_animate_task_enter_from_home_delay">16</integer> + <integer name="recents_animate_task_enter_from_home_delay">10</integer> <!-- The min animation duration for animating the nav bar scrim in. --> <integer name="recents_nav_bar_scrim_enter_duration">400</integer> <!-- The animation duration for animating the removal of a task view. --> diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 8861752133d4..3e61f87771a1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -287,7 +287,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta /** Updates each of the task animation rects. */ void updateAnimationRects() { - if (mServiceIsBound && mBootCompleted) { + if (mServiceIsBound) { Resources res = mContext.getResources(); int statusBarHeight = res.getDimensionPixelSize( com.android.internal.R.dimen.status_bar_height); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index cd4d206fcd4f..1d355cd2daf4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -26,7 +26,7 @@ public class Constants { public static class App { // Enables the home->Recents transition - public static final boolean EnableHomeTransition = false; + public static final boolean EnableHomeTransition = true; // Enables the screenshot app->Recents transition public static final boolean EnableScreenshotAppTransition = false; // Enables the filtering of tasks according to their grouping diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index b1f37336f899..433dcb4988eb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -70,6 +70,7 @@ public class RecentsConfiguration { /** Task view animation and styles */ public int taskViewEnterFromHomeDuration; public int taskViewEnterFromHomeDelay; + public int taskViewExitToHomeDuration; public int taskViewRemoveAnimDuration; public int taskViewRemoveAnimTranslationXPx; public int taskViewTranslationZMinPx; @@ -174,6 +175,8 @@ public class RecentsConfiguration { res.getInteger(R.integer.recents_animate_task_enter_from_home_duration); taskViewEnterFromHomeDelay = res.getInteger(R.integer.recents_animate_task_enter_from_home_delay); + taskViewExitToHomeDuration = + res.getInteger(R.integer.recents_animate_task_exit_to_home_duration); taskViewRemoveAnimDuration = res.getInteger(R.integer.recents_animate_task_view_remove_duration); taskViewRemoveAnimTranslationXPx = diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 7376255b3e7b..ffd41357047f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -327,8 +327,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On animate() .translationY(ctx.offscreenTranslationY) .setStartDelay(0) - .setInterpolator(mConfig.fastOutSlowInInterpolator) - .setDuration(mConfig.taskViewEnterFromHomeDuration) + .setInterpolator(mConfig.fastOutLinearInInterpolator) + .setDuration(mConfig.taskViewExitToHomeDuration) .withLayer() .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable()) .start(); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 0cb2ab930310..b9416576cecc 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1104,7 +1104,7 @@ public class UserManagerService extends IUserManager.Stub { final UserInfo user; synchronized (mPackagesLock) { user = mUsers.get(userHandle); - if (userHandle == 0 || user == null) { + if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) { return false; } mRemovingUserIds.put(userHandle, true); |