diff options
52 files changed, 995 insertions, 534 deletions
@@ -201,6 +201,7 @@ LOCAL_SRC_FILES += \ core/java/android/service/trust/ITrustAgentServiceCallback.aidl \ core/java/android/service/voice/IVoiceInteractionService.aidl \ core/java/android/service/voice/IVoiceInteractionSession.aidl \ + core/java/android/service/voice/IVoiceInteractionSessionService.aidl \ core/java/android/service/wallpaper/IWallpaperConnection.aidl \ core/java/android/service/wallpaper/IWallpaperEngine.aidl \ core/java/android/service/wallpaper/IWallpaperService.aidl \ diff --git a/api/current.txt b/api/current.txt index 4fef0d0..34b1ac8 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1009,6 +1009,7 @@ package android { field public static final int selectedDateVerticalBar = 16843591; // 0x1010347 field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342 field public static final int sequence = 16843815; // 0x1010427 + field public static final int sessionService = 16843850; // 0x101044a field public static final int settingsActivity = 16843301; // 0x1010225 field public static final int shadowColor = 16843105; // 0x1010161 field public static final int shadowDx = 16843106; // 0x1010162 @@ -1663,10 +1664,14 @@ package android { field public static final int decelerate_cubic = 17563651; // 0x10c0003 field public static final int decelerate_quad = 17563649; // 0x10c0001 field public static final int decelerate_quint = 17563653; // 0x10c0005 - field public static final int fast_out_linear_in = 17563663; // 0x10c000f - field public static final int fast_out_slow_in = 17563661; // 0x10c000d + field public static final int fast_out_linear_in = 17563667; // 0x10c0013 + field public static final int fast_out_slow_in = 17563665; // 0x10c0011 + field public static final int l_resource_pad1 = 17563664; // 0x10c0010 + field public static final int l_resource_pad2 = 17563663; // 0x10c000f + field public static final int l_resource_pad3 = 17563662; // 0x10c000e + field public static final int l_resource_pad4 = 17563661; // 0x10c000d field public static final int linear = 17563659; // 0x10c000b - field public static final int linear_out_slow_in = 17563662; // 0x10c000e + field public static final int linear_out_slow_in = 17563666; // 0x10c0012 field public static final int overshoot = 17563656; // 0x10c0008 } @@ -4842,20 +4847,26 @@ package android.app { } public class VoiceInteractor { - method public android.app.VoiceInteractor.Request startCommand(android.app.VoiceInteractor.Callback, java.lang.String, android.os.Bundle); - method public android.app.VoiceInteractor.Request startConfirmation(android.app.VoiceInteractor.Callback, java.lang.String, android.os.Bundle); + method public boolean submitRequest(android.app.VoiceInteractor.Request); method public boolean[] supportsCommands(java.lang.String[]); } - public static class VoiceInteractor.Callback { - ctor public VoiceInteractor.Callback(); - method public void onCancel(android.app.VoiceInteractor.Request); - method public void onCommandResult(android.app.VoiceInteractor.Request, android.os.Bundle); - method public void onConfirmationResult(android.app.VoiceInteractor.Request, boolean, android.os.Bundle); + public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request { + ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle); + method public void onCommandResult(android.os.Bundle); } - public static class VoiceInteractor.Request { + public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request { + ctor public VoiceInteractor.ConfirmationRequest(java.lang.CharSequence, android.os.Bundle); + method public void onConfirmationResult(boolean, android.os.Bundle); + } + + public static abstract class VoiceInteractor.Request { + ctor public VoiceInteractor.Request(); method public void cancel(); + method public android.app.Activity getActivity(); + method public android.content.Context getContext(); + method public void onCancel(); } public final class WallpaperInfo implements android.os.Parcelable { @@ -24919,7 +24930,7 @@ package android.service.voice { public class VoiceInteractionService extends android.app.Service { ctor public VoiceInteractionService(); method public android.os.IBinder onBind(android.content.Intent); - method public void startVoiceActivity(android.content.Intent, android.service.voice.VoiceInteractionSession); + method public void startVoiceActivity(android.content.Intent, android.os.Bundle); field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService"; field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction"; } @@ -24938,10 +24949,16 @@ package android.service.voice { public static class VoiceInteractionSession.Request { method public void sendCancelResult(); - method public void sendCommandResult(android.os.Bundle); + method public void sendCommandResult(boolean, android.os.Bundle); method public void sendConfirmResult(boolean, android.os.Bundle); } + public abstract class VoiceInteractionSessionService extends android.app.Service { + ctor public VoiceInteractionSessionService(); + method public android.os.IBinder onBind(android.content.Intent); + method public abstract android.service.voice.VoiceInteractionSession onNewSession(android.os.Bundle); + } + } package android.service.wallpaper { diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 41afa39..1780e03 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -51,6 +51,7 @@ #include "BootAnimation.h" +#define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip" #define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip" #define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip" #define EXIT_PROP_NAME "service.bootanim.exit" @@ -283,6 +284,9 @@ status_t BootAnimation::readyToRun() { (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) && ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) || + ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) && + ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) || + ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) && ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) { mZip = zipFile; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 197eaf8..8981c88 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -5454,7 +5454,7 @@ public class Activity extends ContextThemeWrapper mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; mVoiceInteractor = voiceInteractor != null - ? new VoiceInteractor(this, voiceInteractor, Looper.myLooper()) : null; + ? new VoiceInteractor(this, this, voiceInteractor, Looper.myLooper()) : null; mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java index 6820dfd..6dc48b0 100644 --- a/core/java/android/app/VoiceInteractor.java +++ b/core/java/android/app/VoiceInteractor.java @@ -22,6 +22,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.util.ArrayMap; import android.util.Log; import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.IVoiceInteractorCallback; @@ -39,50 +40,85 @@ public class VoiceInteractor { static final boolean DEBUG = true; final Context mContext; + final Activity mActivity; final IVoiceInteractor mInteractor; final HandlerCaller mHandlerCaller; final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() { @Override public void executeMessage(Message msg) { SomeArgs args = (SomeArgs)msg.obj; + Request request; switch (msg.what) { case MSG_CONFIRMATION_RESULT: + request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onConfirmResult: req=" - + ((IVoiceInteractorRequest)args.arg2).asBinder() - + " confirmed=" + msg.arg1 + " result=" + args.arg3); - ((Callback)args.arg1).onConfirmationResult( - findRequest((IVoiceInteractorRequest)args.arg2), - msg.arg1 != 0, (Bundle)args.arg3); + + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + + " confirmed=" + msg.arg1 + " result=" + args.arg2); + if (request != null) { + ((ConfirmationRequest)request).onConfirmationResult(msg.arg1 != 0, + (Bundle) args.arg2); + request.clear(); + } break; case MSG_COMMAND_RESULT: + request = pullRequest((IVoiceInteractorRequest)args.arg1, msg.arg1 != 0); if (DEBUG) Log.d(TAG, "onCommandResult: req=" - + ((IVoiceInteractorRequest)args.arg2).asBinder() + + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request + " result=" + args.arg2); - ((Callback)args.arg1).onCommandResult( - findRequest((IVoiceInteractorRequest) args.arg2), - (Bundle) args.arg3); + if (request != null) { + ((CommandRequest)request).onCommandResult((Bundle) args.arg2); + if (msg.arg1 != 0) { + request.clear(); + } + } break; case MSG_CANCEL_RESULT: + request = pullRequest((IVoiceInteractorRequest)args.arg1, true); if (DEBUG) Log.d(TAG, "onCancelResult: req=" - + ((IVoiceInteractorRequest)args.arg2).asBinder()); - ((Callback)args.arg1).onCancel( - findRequest((IVoiceInteractorRequest) args.arg2)); + + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request); + if (request != null) { + request.onCancel(); + request.clear(); + } break; } } }; - final WeakHashMap<IBinder, Request> mActiveRequests = new WeakHashMap<IBinder, Request>(); + final IVoiceInteractorCallback.Stub mCallback = new IVoiceInteractorCallback.Stub() { + @Override + public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed, + Bundle result) { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO( + MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, request, result)); + } + + @Override + public void deliverCommandResult(IVoiceInteractorRequest request, boolean complete, + Bundle result) { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO( + MSG_COMMAND_RESULT, complete ? 1 : 0, request, result)); + } + + @Override + public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO( + MSG_CANCEL_RESULT, request)); + } + }; + + final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>(); static final int MSG_CONFIRMATION_RESULT = 1; static final int MSG_COMMAND_RESULT = 2; static final int MSG_CANCEL_RESULT = 3; - public static class Request { - final IVoiceInteractorRequest mRequestInterface; + public static abstract class Request { + IVoiceInteractorRequest mRequestInterface; + Context mContext; + Activity mActivity; - Request(IVoiceInteractorRequest requestInterface) { - mRequestInterface = requestInterface; + public Request() { } public void cancel() { @@ -92,126 +128,130 @@ public class VoiceInteractor { Log.w(TAG, "Voice interactor has died", e); } } + + public Context getContext() { + return mContext; + } + + public Activity getActivity() { + return mActivity; + } + + public void onCancel() { + } + + void clear() { + mRequestInterface = null; + mContext = null; + mActivity = null; + } + + abstract IVoiceInteractorRequest submit(IVoiceInteractor interactor, + String packageName, IVoiceInteractorCallback callback) throws RemoteException; } - public static class Callback { - VoiceInteractor mInteractor; + public static class ConfirmationRequest extends Request { + final CharSequence mPrompt; + final Bundle mExtras; - final IVoiceInteractorCallback.Stub mWrapper = new IVoiceInteractorCallback.Stub() { - @Override - public void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed, - Bundle result) { - mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageIOOO( - MSG_CONFIRMATION_RESULT, confirmed ? 1 : 0, Callback.this, request, - result)); - } + /** + * Confirms an operation with the user via the trusted system + * VoiceInteractionService. This allows an Activity to complete an unsafe operation that + * would require the user to touch the screen when voice interaction mode is not enabled. + * The result of the confirmation will be returned through an asynchronous call to + * either {@link #onConfirmationResult(boolean, android.os.Bundle)} or + * {@link #onCancel()}. + * + * <p>In some cases this may be a simple yes / no confirmation or the confirmation could + * include context information about how the action will be completed + * (e.g. booking a cab might include details about how long until the cab arrives) + * so the user can give a confirmation. + * @param prompt Optional confirmation text to read to the user as the action being + * confirmed. + * @param extras Additional optional information. + */ + public ConfirmationRequest(CharSequence prompt, Bundle extras) { + mPrompt = prompt; + mExtras = extras; + } - @Override - public void deliverCommandResult(IVoiceInteractorRequest request, Bundle result) { - mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageOOO( - MSG_COMMAND_RESULT, Callback.this, request, result)); - } + public void onConfirmationResult(boolean confirmed, Bundle result) { + } - @Override - public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException { - mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageOO( - MSG_CANCEL_RESULT, Callback.this, request)); - } - }; + IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, + IVoiceInteractorCallback callback) throws RemoteException { + return interactor.startConfirmation(packageName, callback, mPrompt.toString(), mExtras); + } + } - public void onConfirmationResult(Request request, boolean confirmed, Bundle result) { + public static class CommandRequest extends Request { + final String mCommand; + final Bundle mArgs; + + /** + * Execute a command using the trusted system VoiceInteractionService. + * This allows an Activity to request additional information from the user needed to + * complete an action (e.g. booking a table might have several possible times that the + * user could select from or an app might need the user to agree to a terms of service). + * The result of the confirmation will be returned through an asynchronous call to + * either {@link #onCommandResult(android.os.Bundle)} or + * {@link #onCancel()}. + * + * <p>The command is a string that describes the generic operation to be performed. + * The command will determine how the properties in extras are interpreted and the set of + * available commands is expected to grow over time. An example might be + * "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number of bags as part of + * airline check-in. (This is not an actual working example.) + * + * @param command The desired command to perform. + * @param args Additional arguments to control execution of the command. + */ + public CommandRequest(String command, Bundle args) { + mCommand = command; + mArgs = args; } - public void onCommandResult(Request request, Bundle result) { + public void onCommandResult(Bundle result) { } - public void onCancel(Request request) { + IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName, + IVoiceInteractorCallback callback) throws RemoteException { + return interactor.startConfirmation(packageName, callback, mCommand, mArgs); } - } + } - VoiceInteractor(Context context, IVoiceInteractor interactor, Looper looper) { + VoiceInteractor(Context context, Activity activity, IVoiceInteractor interactor, + Looper looper) { mContext = context; + mActivity = activity; mInteractor = interactor; mHandlerCaller = new HandlerCaller(context, looper, mHandlerCallerCallback, true); } - Request storeRequest(IVoiceInteractorRequest request) { - synchronized (mActiveRequests) { - Request req = new Request(request); - mActiveRequests.put(request.asBinder(), req); - return req; - } - } - - Request findRequest(IVoiceInteractorRequest request) { + Request pullRequest(IVoiceInteractorRequest request, boolean complete) { synchronized (mActiveRequests) { Request req = mActiveRequests.get(request.asBinder()); - if (req == null) { - throw new IllegalStateException("Received callback without active request: " - + request); + if (req != null && complete) { + mActiveRequests.remove(request.asBinder()); } return req; } } - /** - * Asynchronously confirms an operation with the user via the trusted system - * VoiceinteractionService. This allows an Activity to complete an unsafe operation that - * would require the user to touch the screen when voice interaction mode is not enabled. - * The result of the confirmation will be returned by calling the - * {@link Callback#onConfirmationResult Callback.onConfirmationResult} method. - * - * In some cases this may be a simple yes / no confirmation or the confirmation could - * include context information about how the action will be completed - * (e.g. booking a cab might include details about how long until the cab arrives) so the user - * can give informed consent. - * @param callback Required callback target for interaction results. - * @param prompt Optional confirmation text to read to the user as the action being confirmed. - * @param extras Additional optional information. - * @return Returns a new {@link Request} object representing this operation. - */ - public Request startConfirmation(Callback callback, String prompt, Bundle extras) { + public boolean submitRequest(Request request) { try { - callback.mInteractor = this; - Request req = storeRequest(mInteractor.startConfirmation( - mContext.getOpPackageName(), callback.mWrapper, prompt, extras)); - if (DEBUG) Log.d(TAG, "startConfirmation: req=" + req.mRequestInterface.asBinder() - + " prompt=" + prompt + " extras=" + extras); - return req; - } catch (RemoteException e) { - throw new RuntimeException("Voice interactor has died", e); - } - } - - /** - * Asynchronously executes a command using the trusted system VoiceinteractionService. - * This allows an Activity to request additional information from the user needed to - * complete an action (e.g. booking a table might have several possible times that the - * user could select from or an app might need the user to agree to a terms of service). - * - * The command is a string that describes the generic operation to be performed. - * The command will determine how the properties in extras are interpreted and the set of - * available commands is expected to grow over time. An example might be - * "com.google.voice.commands.REQUEST_NUMBER_BAGS" to request the number of bags as part of - * airline check-in. (This is not an actual working example.) - * The result of the command will be returned by calling the - * {@link Callback#onCommandResult Callback.onCommandResult} method. - * - * @param callback Required callback target for interaction results. - * @param command - * @param extras - * @return Returns a new {@link Request} object representing this operation. - */ - public Request startCommand(Callback callback, String command, Bundle extras) { - try { - callback.mInteractor = this; - Request req = storeRequest(mInteractor.startCommand( - mContext.getOpPackageName(), callback.mWrapper, command, extras)); - if (DEBUG) Log.d(TAG, "startCommand: req=" + req.mRequestInterface.asBinder() - + " command=" + command + " extras=" + extras); - return req; + IVoiceInteractorRequest ireq = request.submit(mInteractor, + mContext.getOpPackageName(), mCallback); + request.mRequestInterface = ireq; + request.mContext = mContext; + request.mActivity = mActivity; + synchronized (mActiveRequests) { + mActiveRequests.put(ireq.asBinder(), request); + } + return true; } catch (RemoteException e) { - throw new RuntimeException("Voice interactor has died", e); + Log.w(TAG, "Remove voice interactor service died", e); + return false; } } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index e6e0f35..f08097b 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -16,6 +16,7 @@ package android.app; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -44,10 +45,14 @@ import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; +import android.text.TextUtils; import android.util.Log; import android.view.WindowManagerGlobal; import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -65,6 +70,11 @@ public class WallpaperManager { private float mWallpaperXStep = -1; private float mWallpaperYStep = -1; + /** {@hide} */ + private static final String PROP_WALLPAPER = "ro.config.wallpaper"; + /** {@hide} */ + private static final String PROP_WALLPAPER_COMPONENT = "ro.config.wallpaper_component"; + /** * Activity Action: Show settings for choosing wallpaper. Do not use directly to construct * an intent; instead, use {@link #getCropAndSetWallpaperIntent}. @@ -298,8 +308,7 @@ public class WallpaperManager { private Bitmap getDefaultWallpaperLocked(Context context) { try { - InputStream is = context.getResources().openRawResource( - com.android.internal.R.drawable.default_wallpaper); + InputStream is = openDefaultWallpaper(context); if (is != null) { int width = mService.getWidthHint(); int height = mService.getHeightHint(); @@ -403,8 +412,7 @@ public class WallpaperManager { horizontalAlignment = Math.max(0, Math.min(1, horizontalAlignment)); verticalAlignment = Math.max(0, Math.min(1, verticalAlignment)); - InputStream is = new BufferedInputStream( - resources.openRawResource(com.android.internal.R.drawable.default_wallpaper)); + InputStream is = new BufferedInputStream(openDefaultWallpaper(mContext)); if (is == null) { Log.e(TAG, "default wallpaper input stream is null"); @@ -429,8 +437,7 @@ public class WallpaperManager { } } - is = new BufferedInputStream(resources.openRawResource( - com.android.internal.R.drawable.default_wallpaper)); + is = new BufferedInputStream(openDefaultWallpaper(mContext)); RectF cropRectF; @@ -479,8 +486,7 @@ public class WallpaperManager { if (crop == null) { // BitmapRegionDecoder has failed, try to crop in-memory - is = new BufferedInputStream(resources.openRawResource( - com.android.internal.R.drawable.default_wallpaper)); + is = new BufferedInputStream(openDefaultWallpaper(mContext)); Bitmap fullSize = null; if (is != null) { BitmapFactory.Options options = new BitmapFactory.Options(); @@ -1009,6 +1015,53 @@ public class WallpaperManager { * wallpaper. */ public void clear() throws IOException { - setResource(com.android.internal.R.drawable.default_wallpaper); + setStream(openDefaultWallpaper(mContext)); + } + + /** + * Open stream representing the default static image wallpaper. + * + * @hide + */ + public static InputStream openDefaultWallpaper(Context context) { + final String path = SystemProperties.get(PROP_WALLPAPER); + if (!TextUtils.isEmpty(path)) { + final File file = new File(path); + if (file.exists()) { + try { + return new FileInputStream(file); + } catch (IOException e) { + // Ignored, fall back to platform default below + } + } + } + return context.getResources().openRawResource( + com.android.internal.R.drawable.default_wallpaper); + } + + /** + * Return {@link ComponentName} of the default live wallpaper, or + * {@code null} if none is defined. + * + * @hide + */ + public static ComponentName getDefaultWallpaperComponent(Context context) { + String flat = SystemProperties.get(PROP_WALLPAPER_COMPONENT); + if (!TextUtils.isEmpty(flat)) { + final ComponentName cn = ComponentName.unflattenFromString(flat); + if (cn != null) { + return cn; + } + } + + flat = context.getString(com.android.internal.R.string.default_wallpaper_component); + if (!TextUtils.isEmpty(flat)) { + final ComponentName cn = ComponentName.unflattenFromString(flat); + if (cn != null) { + return cn; + } + } + + return null; } } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 11e3795..0336dd6 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -16,12 +16,17 @@ package android.os; +import android.text.TextUtils; +import android.util.Slog; + import com.android.internal.telephony.TelephonyProperties; /** * Information about the current build, extracted from system properties. */ public class Build { + private static final String TAG = "Build"; + /** Value used for when a build property is unknown. */ public static final String UNKNOWN = "unknown"; @@ -509,7 +514,43 @@ public class Build { public static final String TAGS = getString("ro.build.tags"); /** A string that uniquely identifies this build. Do not attempt to parse this value. */ - public static final String FINGERPRINT = getString("ro.build.fingerprint"); + public static final String FINGERPRINT = deriveFingerprint(); + + /** + * Some devices split the fingerprint components between multiple + * partitions, so we might derive the fingerprint at runtime. + */ + private static String deriveFingerprint() { + String finger = SystemProperties.get("ro.build.fingerprint"); + if (TextUtils.isEmpty(finger)) { + finger = getString("ro.product.brand") + '/' + + getString("ro.product.name") + '/' + + getString("ro.product.device") + ':' + + getString("ro.build.version.release") + '/' + + getString("ro.build.id") + '/' + + getString("ro.build.version.incremental") + ':' + + getString("ro.build.type") + '/' + + getString("ro.build.tags"); + } + return finger; + } + + /** + * Ensure that raw fingerprint system property is defined. If it was derived + * dynamically by {@link #deriveFingerprint()} this is where we push the + * derived value into the property service. + * + * @hide + */ + public static void ensureFingerprintProperty() { + if (TextUtils.isEmpty(SystemProperties.get("ro.build.fingerprint"))) { + try { + SystemProperties.set("ro.build.fingerprint", FINGERPRINT); + } catch (IllegalArgumentException e) { + Slog.e(TAG, "Failed to set fingerprint property", e); + } + } + } // The following properties only make sense for internal engineering builds. public static final long TIME = getLong("ro.build.date.utc") * 1000; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b578b48..ab06230 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -764,6 +764,11 @@ public final class Settings { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_ZEN_MODE_SETTINGS = "android.settings.ZEN_MODE_SETTINGS"; + /** {@hide} */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String + ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO"; + // End of Intent actions for Settings /** diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index 2c0b76d..72720d1 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -87,7 +87,7 @@ public class StatusBarNotification implements Parcelable { } private String key() { - return pkg + '|' + opPkg + '|' + id + '|' + tag + '|' + uid; + return pkg + '|' + id + '|' + tag + '|' + uid; } public void writeToParcel(Parcel out, int flags) { diff --git a/core/java/android/service/voice/IVoiceInteractionSessionService.aidl b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl new file mode 100644 index 0000000..2519442 --- /dev/null +++ b/core/java/android/service/voice/IVoiceInteractionSessionService.aidl @@ -0,0 +1,28 @@ +/* + * 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.service.voice; + +import android.os.Bundle; + +import android.service.voice.IVoiceInteractionSession; + +/** + * @hide + */ +oneway interface IVoiceInteractionSessionService { + void newSession(IBinder token, in Bundle args); +} diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index ed93b74..d005890 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -21,6 +21,7 @@ import android.app.Instrumentation; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -50,12 +51,11 @@ public class VoiceInteractionService extends Service { IVoiceInteractionManagerService mSystemService; - public void startVoiceActivity(Intent intent, VoiceInteractionSession session) { + public void startVoiceActivity(Intent intent, Bundle sessionArgs) { try { - int res = mSystemService.startVoiceActivity(intent, + mSystemService.startVoiceActivity(intent, intent.resolveType(getContentResolver()), - mInterface, session.mSession, session.mInteractor); - Instrumentation.checkStartActivityResult(res, intent); + mInterface, sessionArgs); } catch (RemoteException e) { } } diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java new file mode 100644 index 0000000..a909ead --- /dev/null +++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java @@ -0,0 +1,125 @@ +/* + * 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.service.voice; + +import android.Manifest; +import android.content.ComponentName; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.speech.RecognitionService; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Xml; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +public class VoiceInteractionServiceInfo { + static final String TAG = "VoiceInteractionServiceInfo"; + + private String mParseError; + + private ServiceInfo mServiceInfo; + private String mSessionService; + private String mSettingsActivity; + + public VoiceInteractionServiceInfo(PackageManager pm, ComponentName comp) + throws PackageManager.NameNotFoundException { + this(pm, pm.getServiceInfo(comp, PackageManager.GET_META_DATA)); + } + + public VoiceInteractionServiceInfo(PackageManager pm, ServiceInfo si) { + if (!Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) { + mParseError = "Service does not require permission " + + Manifest.permission.BIND_VOICE_INTERACTION; + return; + } + + XmlResourceParser parser = null; + try { + parser = si.loadXmlMetaData(pm, VoiceInteractionService.SERVICE_META_DATA); + if (parser == null) { + mParseError = "No " + VoiceInteractionService.SERVICE_META_DATA + + " meta-data for " + si.packageName; + return; + } + + Resources res = pm.getResourcesForApplication(si.applicationInfo); + + AttributeSet attrs = Xml.asAttributeSet(parser); + + int type; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + + String nodeName = parser.getName(); + if (!"voice-interaction-service".equals(nodeName)) { + mParseError = "Meta-data does not start with voice-interaction-service tag"; + return; + } + + TypedArray array = res.obtainAttributes(attrs, + com.android.internal.R.styleable.VoiceInteractionService); + mSessionService = array.getString( + com.android.internal.R.styleable.VoiceInteractionService_sessionService); + mSettingsActivity = array.getString( + com.android.internal.R.styleable.VoiceInteractionService_settingsActivity); + array.recycle(); + if (mSessionService == null) { + mParseError = "No sessionService specified"; + return; + } + } catch (XmlPullParserException e) { + mParseError = "Error parsing voice interation service meta-data: " + e; + Log.w(TAG, "error parsing voice interaction service meta-data", e); + return; + } catch (IOException e) { + mParseError = "Error parsing voice interation service meta-data: " + e; + Log.w(TAG, "error parsing voice interaction service meta-data", e); + return; + } catch (PackageManager.NameNotFoundException e) { + mParseError = "Error parsing voice interation service meta-data: " + e; + Log.w(TAG, "error parsing voice interaction service meta-data", e); + return; + } finally { + if (parser != null) parser.close(); + } + mServiceInfo = si; + } + + public String getParseError() { + return mParseError; + } + + public ServiceInfo getServiceInfo() { + return mServiceInfo; + } + + public String getSessionService() { + return mSessionService; + } + + public String getSettingsActivity() { + return mSettingsActivity; + } +} diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 59544be..963b6b4 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -96,11 +96,11 @@ public abstract class VoiceInteractionSession { } } - public void sendCommandResult(Bundle result) { + public void sendCommandResult(boolean complete, Bundle result) { try { if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface + " result=" + result); - mCallback.deliverCommandResult(mInterface, result); + mCallback.deliverCommandResult(mInterface, complete, result); } catch (RemoteException e) { } } diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java new file mode 100644 index 0000000..40e5bba --- /dev/null +++ b/core/java/android/service/voice/VoiceInteractionSessionService.java @@ -0,0 +1,82 @@ +/** + * 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.service.voice; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import com.android.internal.app.IVoiceInteractionManagerService; +import com.android.internal.os.HandlerCaller; +import com.android.internal.os.SomeArgs; + +public abstract class VoiceInteractionSessionService extends Service { + + static final int MSG_NEW_SESSION = 1; + + IVoiceInteractionManagerService mSystemService; + + IVoiceInteractionSessionService mInterface = new IVoiceInteractionSessionService.Stub() { + public void newSession(IBinder token, Bundle args) { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(MSG_NEW_SESSION, + token, args)); + + } + }; + + HandlerCaller mHandlerCaller; + final HandlerCaller.Callback mHandlerCallerCallback = new HandlerCaller.Callback() { + @Override + public void executeMessage(Message msg) { + SomeArgs args = (SomeArgs)msg.obj; + switch (msg.what) { + case MSG_NEW_SESSION: + doNewSession((IBinder)args.arg1, (Bundle)args.arg2); + break; + } + } + }; + + @Override + public void onCreate() { + super.onCreate(); + mSystemService = IVoiceInteractionManagerService.Stub.asInterface( + ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); + mHandlerCaller = new HandlerCaller(this, Looper.myLooper(), + mHandlerCallerCallback, true); + } + + public abstract VoiceInteractionSession onNewSession(Bundle args); + + @Override + public IBinder onBind(Intent intent) { + return mInterface.asBinder(); + } + + void doNewSession(IBinder token, Bundle args) { + VoiceInteractionSession session = onNewSession(args); + try { + mSystemService.deliverNewSession(token, session.mSession, session.mInteractor); + } catch (RemoteException e) { + } + } +} diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java index 08e27d3..e70dc0c 100644 --- a/core/java/android/transition/Fade.java +++ b/core/java/android/transition/Fade.java @@ -105,7 +105,7 @@ public class Fade extends Visibility { if (DBG) { Log.d(LOG_TAG, "Created animator " + anim); } - FadeAnimatorListener listener = new FadeAnimatorListener(view, endAlpha); + FadeAnimatorListener listener = new FadeAnimatorListener(view); anim.addListener(listener); anim.addPauseListener(listener); return anim; @@ -138,13 +138,11 @@ public class Fade extends Visibility { private static class FadeAnimatorListener extends AnimatorListenerAdapter { private final View mView; - private final float mEndAlpha; private boolean mCanceled = false; - private float mPausedAlpha; + private float mPausedAlpha = -1; - public FadeAnimatorListener(View view, float endAlpha) { + public FadeAnimatorListener(View view) { mView = view; - mEndAlpha = endAlpha; } @Override @@ -158,14 +156,14 @@ public class Fade extends Visibility { @Override public void onAnimationEnd(Animator animator) { if (!mCanceled) { - mView.setTransitionAlpha(mEndAlpha); + mView.setTransitionAlpha(1); } } @Override public void onAnimationPause(Animator animator) { mPausedAlpha = mView.getTransitionAlpha(); - mView.setTransitionAlpha(mEndAlpha); + mView.setTransitionAlpha(1); } @Override diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index 526803a..6e6496c 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -347,10 +347,11 @@ public abstract class Visibility extends Transition { } if (viewToKeep != null) { + int originalVisibility = viewToKeep.getVisibility(); viewToKeep.setVisibility(View.VISIBLE); Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues); if (animator == null) { - viewToKeep.setVisibility(finalVisibility); + viewToKeep.setVisibility(originalVisibility); } else { final View finalViewToKeep = viewToKeep; animator.addListener(new AnimatorListenerAdapter() { diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index e3c0728..3219ddd 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -17,12 +17,15 @@ package com.android.internal.app; import android.content.Intent; +import android.os.Bundle; import com.android.internal.app.IVoiceInteractor; import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; interface IVoiceInteractionManagerService { - int startVoiceActivity(in Intent intent, String resolvedType, IVoiceInteractionService service, - IVoiceInteractionSession session, IVoiceInteractor interactor); + void startVoiceActivity(in Intent intent, String resolvedType, IVoiceInteractionService service, + in Bundle sessionArgs); + int deliverNewSession(IBinder token, IVoiceInteractionSession session, + IVoiceInteractor interactor); } diff --git a/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl index f5392e9..c6f93e1 100644 --- a/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl @@ -26,6 +26,6 @@ import com.android.internal.app.IVoiceInteractorRequest; oneway interface IVoiceInteractorCallback { void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed, in Bundle result); - void deliverCommandResult(IVoiceInteractorRequest request, in Bundle result); + void deliverCommandResult(IVoiceInteractorRequest request, boolean complete, in Bundle result); void deliverCancel(IVoiceInteractorRequest request); } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 326485d..69440be 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6279,6 +6279,7 @@ its {@link android.service.voice.VoiceInteractionService#SERVICE_META_DATA} meta-data entry. Described here are the attributes that can be included in that tag. --> <declare-styleable name="VoiceInteractionService"> + <attr name="sessionService" format="string" /> <attr name="settingsActivity" /> </declare-styleable> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 6491b33..085b9c3 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2155,6 +2155,13 @@ <public type="attr" name="colorPrimaryDark" /> <public type="attr" name="colorAccent" /> <public type="attr" name="nestedScrollingEnabled" /> + <public type="attr" name="windowEnterTransition" /> + <public type="attr" name="windowExitTransition" /> + <public type="attr" name="windowSharedElementEnterTransition" /> + <public type="attr" name="windowSharedElementExitTransition" /> + <public type="attr" name="windowAllowExitTransitionOverlap" /> + <public type="attr" name="windowAllowEnterTransitionOverlap" /> + <public type="attr" name="sessionService" /> <public-padding type="dimen" name="l_resource_pad" end="0x01050010" /> @@ -2385,17 +2392,14 @@ <public type="style" name="Widget.Holo.Light.Button.Borderless" /> + <public-padding type="interpolator" name="l_resource_pad" end="0x010c0010" /> + <!-- An interpolator which accelerates fast but decelerates slowly. --> <public type="interpolator" name="fast_out_slow_in" /> <!-- An interpolator which starts with a peak non-zero velocity and decelerates slowly. --> <public type="interpolator" name="linear_out_slow_in" /> <!-- An interpolator which accelerates fast and keeps accelerating until the end. --> <public type="interpolator" name="fast_out_linear_in" /> - <public type="attr" name="windowEnterTransition" /> - <public type="attr" name="windowExitTransition" /> - <public type="attr" name="windowSharedElementEnterTransition" /> - <public type="attr" name="windowSharedElementExitTransition" /> - <public type="attr" name="windowAllowExitTransitionOverlap" /> - <public type="attr" name="windowAllowEnterTransitionOverlap" /> + <public type="transition" name="no_transition" id="0x010f0000"/> </resources> diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java index 824e108..0e8831f 100644 --- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java +++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java @@ -501,10 +501,32 @@ public class TouchFeedbackDrawable extends LayerDrawable { } private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) { - final Ripple[] activeRipples = mActiveRipples; final int ripplesCount = mActiveRipplesCount; + if (ripplesCount == 0) { + return -1; + } + + final Ripple[] activeRipples = mActiveRipples; + final boolean projected = isProjected(); + final Rect layerBounds = projected ? getDirtyBounds() : bounds; + + // Separate the ripple color and alpha channel. The alpha will be + // applied when we merge the ripples down to the canvas. + final int rippleColor; + if (mState.mTint != null) { + rippleColor = mState.mTint.getColorForState(getState(), Color.TRANSPARENT); + } else { + rippleColor = Color.TRANSPARENT; + } + final int rippleAlpha = Color.alpha(rippleColor); + + if (mRipplePaint == null) { + mRipplePaint = new Paint(); + mRipplePaint.setAntiAlias(true); + } + final Paint ripplePaint = mRipplePaint; + ripplePaint.setColor(rippleColor); - Paint ripplePaint = null; boolean drewRipples = false; int restoreToCount = -1; int activeRipplesCount = 0; @@ -524,20 +546,9 @@ public class TouchFeedbackDrawable extends LayerDrawable { // If we're masking the ripple layer, make sure we have a layer // first. This will merge SRC_OVER (directly) onto the canvas. if (restoreToCount < 0) { - // Separate the ripple color and alpha channel. The alpha will be - // applied when we merge the ripples down to the canvas. - final int rippleColor; - if (mState.mTint != null) { - rippleColor = mState.mTint.getColorForState(getState(), Color.TRANSPARENT); - } else { - rippleColor = Color.TRANSPARENT; - } - final int rippleAlpha = Color.alpha(rippleColor); - // If we're projecting or we only have a mask, we want to treat the // underlying canvas as our content and merge the ripple layer down // using the tint xfermode. - final boolean projected = isProjected(); final PorterDuffXfermode xfermode; if (projected || maskOnly) { xfermode = mState.getTintXfermode(); @@ -547,18 +558,12 @@ public class TouchFeedbackDrawable extends LayerDrawable { final Paint layerPaint = getMaskingPaint(xfermode); layerPaint.setAlpha(rippleAlpha); - final Rect layerBounds = projected ? getDirtyBounds() : bounds; restoreToCount = canvas.saveLayer(layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom, layerPaint); layerPaint.setAlpha(255); } - if (mRipplePaint == null) { - mRipplePaint = new Paint(); - mRipplePaint.setAntiAlias(true); - } - - drewRipples |= ripple.draw(canvas, mRipplePaint); + drewRipples |= ripple.draw(canvas, ripplePaint); activeRipples[activeRipplesCount] = activeRipples[i]; activeRipplesCount++; diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml index b4847f0..b2d0219 100644 --- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml +++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml @@ -20,6 +20,7 @@ <!-- This contains emergency call button and carrier as shared by pin/pattern/password screens --> <com.android.keyguard.EmergencyCarrierArea xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" @@ -35,7 +36,8 @@ android:ellipsize="marquee" android:textAppearance="?android:attr/textAppearanceMedium" android:textSize="@dimen/kg_status_line_font_size" - android:textColor="?android:attr/textColorSecondary" /> + android:textColor="?android:attr/textColorSecondary" + androidprv:allCaps="@bool/kg_use_all_caps" /> <LinearLayout android:layout_width="match_parent" diff --git a/packages/Keyguard/res/values/attrs.xml b/packages/Keyguard/res/values/attrs.xml index e045dd2..2410b6a 100644 --- a/packages/Keyguard/res/values/attrs.xml +++ b/packages/Keyguard/res/values/attrs.xml @@ -133,4 +133,8 @@ <attr name="digit" format="integer" /> <attr name="textView" format="reference" /> </declare-styleable> + + <declare-styleable name="CarrierText"> + <attr name="allCaps" format="boolean" /> + </declare-styleable> </resources> diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java index 88558cd..05f2962 100644 --- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java +++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java @@ -17,6 +17,7 @@ package com.android.keyguard; import android.content.Context; +import android.content.res.TypedArray; import android.text.method.SingleLineTransformationMethod; import android.text.TextUtils; import android.util.AttributeSet; @@ -81,7 +82,14 @@ public class CarrierText extends TextView { public CarrierText(Context context, AttributeSet attrs) { super(context, attrs); mLockPatternUtils = new LockPatternUtils(mContext); - boolean useAllCaps = mContext.getResources().getBoolean(R.bool.kg_use_all_caps); + boolean useAllCaps; + TypedArray a = context.getTheme().obtainStyledAttributes( + attrs, R.styleable.CarrierText, 0, 0); + try { + useAllCaps = a.getBoolean(R.styleable.CarrierText_allCaps, false); + } finally { + a.recycle(); + } setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps)); } diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 69fbc1b..24ccb2b 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -45,6 +45,15 @@ android:layout_marginTop="@dimen/status_bar_height" android:visibility="gone" /> + <com.android.keyguard.CarrierText + android:id="@+id/keyguard_carrier_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:layout_marginLeft="8dp" + android:ellipsize="marquee" + android:textAppearance="?android:attr/textAppearanceMedium" /> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml index 5d2f330..d81e525 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml @@ -19,34 +19,27 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:focusable="true" + android:clickable="true" + android:background="@*android:drawable/notification_quantum_bg_dim" > - <com.android.systemui.statusbar.LatestItemView - android:id="@+id/container" + <TextView + android:id="@+id/more_text" android:layout_width="match_parent" - android:layout_height="40dp" - android:layout_marginTop="@dimen/notification_divider_height" - android:focusable="true" - android:clickable="true" - android:background="@*android:drawable/notification_quantum_bg_dim" - > - <TextView - android:id="@+id/more_text" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:gravity="center_horizontal" - android:textColor="@color/keyguard_overflow_content_color" - android:textAllCaps="true" - android:textAppearance="?android:attr/textAppearanceMedium" - /> - <com.android.systemui.statusbar.NotificationOverflowIconsView - android:id="@+id/overflow_icons_view" - android:layout_gravity="end|center_vertical" - android:gravity="end" - android:paddingLeft="8dp" - android:paddingRight="8dp" - android:layout_width="120dp" - android:layout_height="wrap_content" - /> - </com.android.systemui.statusbar.LatestItemView> + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:gravity="center_horizontal" + android:textColor="@color/keyguard_overflow_content_color" + android:textAllCaps="true" + android:textAppearance="?android:attr/textAppearanceMedium" + /> + <com.android.systemui.statusbar.NotificationOverflowIconsView + android:id="@+id/overflow_icons_view" + android:layout_gravity="end|center_vertical" + android:gravity="end" + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:layout_width="120dp" + android:layout_height="wrap_content" + /> </com.android.systemui.statusbar.NotificationOverflowContainer> diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml index d61d8b9..41e7dac 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_row.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml @@ -2,17 +2,18 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:focusable="true" + android:clickable="true" + android:background="@*android:drawable/notification_quantum_bg" > - <View - android:id="@+id/top_glow" - android:alpha="0" - android:visibility="invisible" + <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expanded" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expandedPublic" android:layout_width="match_parent" - android:layout_height="@dimen/notification_divider_height" - android:layout_gravity="top|center_horizontal" - android:background="@drawable/top_divider_glow" - /> + android:layout_height="wrap_content" /> <Button android:id="@+id/veto" @@ -25,35 +26,6 @@ android:paddingStart="8dp" /> - <com.android.systemui.statusbar.LatestItemView android:id="@+id/container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="@dimen/notification_divider_height" - android:layout_marginTop="@dimen/notification_divider_height" - android:focusable="true" - android:clickable="true" - android:background="@*android:drawable/notification_quantum_bg" - > - - <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expanded" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - - <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expandedPublic" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - </com.android.systemui.statusbar.LatestItemView> - - <View - android:id="@+id/bottom_glow" - android:alpha="0" - android:visibility="invisible" - android:layout_width="match_parent" - android:layout_height="@dimen/notification_divider_height" - android:layout_gravity="bottom|center_horizontal" - android:background="@drawable/bottom_divider_glow" - /> - <TextView android:id="@+id/debug_info" android:visibility="invisible" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 0604817..176879e 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -82,12 +82,6 @@ <!-- Height of a medium notification in the status bar --> <dimen name="notification_mid_height">128dp</dimen> - <!-- Height of a small notification in the status bar plus glow, padding, etc --> - <dimen name="notification_row_min_height">68dp</dimen> - - <!-- Height of a large notification in the status bar plus glow, padding, etc --> - <dimen name="notification_row_max_height">260dp</dimen> - <!-- size at which Notification icons will be drawn in the status bar --> <dimen name="status_bar_icon_drawing_size">18dip</dimen> @@ -261,6 +255,9 @@ <!-- Z distance between notifications if they are in the stack --> <dimen name="z_distance_between_notifications">2dp</dimen> + <!-- The padding between the individual notification cards. --> + <dimen name="notification_padding">3dp</dimen> + <!-- Width of the zen mode interstitial dialog. --> <dimen name="zen_mode_dialog_width">320dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index 8dd3f8d..c585a5b 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -19,7 +19,6 @@ package com.android.systemui; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.media.AudioManager; @@ -81,8 +80,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { private boolean mHasPopped; private View mEventSource; private View mCurrView; - private View mCurrViewTopGlow; - private View mCurrViewBottomGlow; private float mOldHeight; private float mNaturalHeight; private float mInitialTouchFocusY; @@ -99,9 +96,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { private ScaleGestureDetector mSGD; private ViewScaler mScaler; private ObjectAnimator mScaleAnimation; - private AnimatorSet mGlowAnimationSet; - private ObjectAnimator mGlowTopAnimation; - private ObjectAnimator mGlowBottomAnimation; private Vibrator mVibrator; private int mSmallSize; @@ -223,14 +217,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { } }; - mGlowTopAnimation = ObjectAnimator.ofFloat(null, "alpha", 0f); - mGlowTopAnimation.addListener(glowVisibilityController); - mGlowBottomAnimation = ObjectAnimator.ofFloat(null, "alpha", 0f); - mGlowBottomAnimation.addListener(glowVisibilityController); - mGlowAnimationSet = new AnimatorSet(); - mGlowAnimationSet.play(mGlowTopAnimation).with(mGlowBottomAnimation); - mGlowAnimationSet.setDuration(GLOW_DURATION); - final ViewConfiguration configuration = ViewConfiguration.get(mContext); mTouchSlop = configuration.getScaledTouchSlop(); @@ -251,7 +237,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { float newHeight = clamp(target); mScaler.setHeight(newHeight); - setGlow(calculateGlow(target, newHeight)); mLastFocusY = mSGD.getFocusY(); mLastSpanY = mSGD.getCurrentSpan(); } @@ -322,37 +307,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { return (GLOW_BASE + strength * (1f - GLOW_BASE)); } - public void setGlow(float glow) { - if (!mGlowAnimationSet.isRunning() || glow == 0f) { - if (mGlowAnimationSet.isRunning()) { - mGlowAnimationSet.end(); - } - if (mCurrViewTopGlow != null && mCurrViewBottomGlow != null) { - if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) { - // animate glow in and out - mGlowTopAnimation.setTarget(mCurrViewTopGlow); - mGlowBottomAnimation.setTarget(mCurrViewBottomGlow); - mGlowTopAnimation.setFloatValues(glow); - mGlowBottomAnimation.setFloatValues(glow); - mGlowAnimationSet.setupStartValues(); - mGlowAnimationSet.start(); - } else { - // set it explicitly in reponse to touches. - mCurrViewTopGlow.setAlpha(glow); - mCurrViewBottomGlow.setAlpha(glow); - handleGlowVisibility(); - } - } - } - } - - private void handleGlowVisibility() { - mCurrViewTopGlow.setVisibility(mCurrViewTopGlow.getAlpha() <= 0.0f ? - View.INVISIBLE : View.VISIBLE); - mCurrViewBottomGlow.setVisibility(mCurrViewBottomGlow.getAlpha() <= 0.0f ? - View.INVISIBLE : View.VISIBLE); - } - @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); @@ -466,9 +420,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { if (mHasPopped) { mScaler.setHeight(newHeight); - setGlow(GLOW_BASE); - } else { - setGlow(calculateGlow(4f * pull, 0f)); } final int x = (int) mSGD.getFocusX(); @@ -517,7 +468,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { if (DEBUG) Log.d(TAG, "scale type " + expandType + " beginning on view: " + v); mCallback.setUserLockedChild(v, true); setView(v); - setGlow(GLOW_BASE); mScaler.setView(v); mOldHeight = mScaler.getHeight(); if (mCallback.canChildBeExpanded(v)) { @@ -549,7 +499,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { if (mScaleAnimation.isRunning()) { mScaleAnimation.cancel(); } - setGlow(0f); mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight); if (targetHeight != currentHeight) { mScaleAnimation.setFloatValues(targetHeight); @@ -571,23 +520,11 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { private void clearView() { mCurrView = null; - mCurrViewTopGlow = null; - mCurrViewBottomGlow = null; + } private void setView(View v) { mCurrView = v; - if (v instanceof ViewGroup) { - ViewGroup g = (ViewGroup) v; - mCurrViewTopGlow = g.findViewById(R.id.top_glow); - mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow); - if (DEBUG) { - String debugLog = "Looking for glows: " + - (mCurrViewTopGlow != null ? "found top " : "didn't find top") + - (mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom"); - Log.v(TAG, debugLog); - } - } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index 5e90084..d647dfa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * 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. @@ -11,7 +11,7 @@ * 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. + * limitations under the License */ package com.android.systemui.statusbar; @@ -21,12 +21,15 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; -import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import com.android.internal.R; -public class LatestItemView extends FrameLayout { +/** + * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer} + * to implement dimming/activating on Keyguard for the double-tap gesture + */ +public class ActivatableNotificationView extends FrameLayout { private static final long DOUBLETAP_TIMEOUT_MS = 1000; @@ -48,11 +51,12 @@ public class LatestItemView extends FrameLayout { private OnActivatedListener mOnActivatedListener; - public LatestItemView(Context context, AttributeSet attrs) { + public ActivatableNotificationView(Context context, AttributeSet attrs) { super(context, attrs); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } + private final Runnable mTapTimeoutRunnable = new Runnable() { @Override public void run() { @@ -66,20 +70,6 @@ public class LatestItemView extends FrameLayout { } @Override - public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { - if (super.onRequestSendAccessibilityEvent(child, event)) { - // Add a record for the entire layout since its content is somehow small. - // The event comes from a leaf view that is interacted with. - AccessibilityEvent record = AccessibilityEvent.obtain(); - onInitializeAccessibilityEvent(record); - dispatchPopulateAccessibilityEvent(record); - event.appendRecord(record); - return true; - } - return false; - } - - @Override public boolean onTouchEvent(MotionEvent event) { if (mLocked) { return handleTouchEventLocked(event); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 2ea5add..3e21640 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -83,7 +83,7 @@ import java.util.ArrayList; import java.util.Locale; public abstract class BaseStatusBar extends SystemUI implements - CommandQueue.Callbacks, LatestItemView.OnActivatedListener { + CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener { public static final String TAG = "StatusBar"; public static final boolean DEBUG = false; public static final boolean MULTIUSER_DEBUG = false; @@ -737,8 +737,9 @@ public abstract class BaseStatusBar extends SystemUI implements return false; } - Log.v(TAG, "publicNotification: " - + sbn.getNotification().publicVersion); + if (DEBUG) { + Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion); + } Notification publicNotification = sbn.getNotification().publicVersion; @@ -759,20 +760,19 @@ public abstract class BaseStatusBar extends SystemUI implements // NB: the large icon is now handled entirely by the template // bind the click event to the content area - ViewGroup content = (ViewGroup)row.findViewById(R.id.container); SizeAdaptiveLayout expanded = (SizeAdaptiveLayout)row.findViewById(R.id.expanded); SizeAdaptiveLayout expandedPublic = (SizeAdaptiveLayout)row.findViewById(R.id.expandedPublic); - content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); PendingIntent contentIntent = sbn.getNotification().contentIntent; if (contentIntent != null) { final View.OnClickListener listener = makeClicker(contentIntent, sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp, sbn.getUserId()); - content.setOnClickListener(listener); + row.setOnClickListener(listener); } else { - content.setOnClickListener(null); + row.setOnClickListener(null); } // set up the adaptive layout @@ -882,7 +882,6 @@ public abstract class BaseStatusBar extends SystemUI implements entry.row = row; entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight); entry.row.setOnActivatedListener(this); - entry.content = content; entry.expanded = contentViewLocal; entry.expandedPublic = publicViewLocal; entry.setBigContentView(bigContentViewLocal); @@ -1349,9 +1348,9 @@ public abstract class BaseStatusBar extends SystemUI implements final View.OnClickListener listener = makeClicker(contentIntent, notification.getPackageName(), notification.getTag(), notification.getId(), isHeadsUp, notification.getUserId()); - entry.content.setOnClickListener(listener); + entry.row.setOnClickListener(listener); } else { - entry.content.setOnClickListener(null); + entry.row.setOnClickListener(null); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index bb481ec..35c02eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -20,13 +20,12 @@ import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; +import android.view.accessibility.AccessibilityEvent; import com.android.internal.widget.SizeAdaptiveLayout; import com.android.systemui.R; -public class ExpandableNotificationRow extends FrameLayout - implements LatestItemView.OnActivatedListener { +public class ExpandableNotificationRow extends ActivatableNotificationView { private int mRowMinHeight; private int mRowMaxHeight; @@ -41,8 +40,6 @@ public class ExpandableNotificationRow extends FrameLayout /** Are we showing the "public" version */ private boolean mShowingPublic; - private LatestItemView mLatestItemView; - /** * Is this notification expanded by the system. The expansion state can be overridden by the * user expansion. @@ -53,7 +50,6 @@ public class ExpandableNotificationRow extends FrameLayout private int mMaxExpandHeight; private boolean mMaxHeightNeedsUpdate; private NotificationActivator mActivator; - private LatestItemView.OnActivatedListener mOnActivatedListener; private boolean mSelfInitiatedLayout; public ExpandableNotificationRow(Context context, AttributeSet attrs) { @@ -65,10 +61,22 @@ public class ExpandableNotificationRow extends FrameLayout super.onFinishInflate(); mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic); mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded); - mLatestItemView = (LatestItemView) findViewById(R.id.container); mActivator = new NotificationActivator(this); - mLatestItemView.setOnActivatedListener(this); + } + + @Override + public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { + if (super.onRequestSendAccessibilityEvent(child, event)) { + // Add a record for the entire layout since its content is somehow small. + // The event comes from a leaf view that is interacted with. + AccessibilityEvent record = AccessibilityEvent.obtain(); + onInitializeAccessibilityEvent(record); + dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + return false; } public void setHeightRange(int rowMinHeight, int rowMaxHeight) { @@ -220,7 +228,7 @@ public class ExpandableNotificationRow extends FrameLayout * Sets the notification as dimmed, meaning that it will appear in a more gray variant. */ public void setDimmed(boolean dimmed) { - mLatestItemView.setDimmed(dimmed); + super.setDimmed(dimmed); mActivator.setDimmed(dimmed); } @@ -232,46 +240,10 @@ public class ExpandableNotificationRow extends FrameLayout return mMaxExpandHeight; } - /** - * Sets the notification as locked. In the locked state, the first tap will produce a quantum - * ripple to make the notification brighter and only the second tap will cause a click. - */ - public void setLocked(boolean locked) { - mLatestItemView.setLocked(locked); - } - - public void setOnActivatedListener(LatestItemView.OnActivatedListener listener) { - mOnActivatedListener = listener; - } - public NotificationActivator getActivator() { return mActivator; } - @Override - public void onActivated(View view) { - if (mOnActivatedListener != null) { - mOnActivatedListener.onActivated(this); - } - } - - @Override - public void onReset(View view) { - if (mOnActivatedListener != null) { - mOnActivatedListener.onReset(this); - } - } - - /** - * Sets the resource id for the background of this notification. - * - * @param bgResId The background resource to use in normal state. - * @param dimmedBgResId The background resource to use in dimmed state. - */ - public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) { - mLatestItemView.setBackgroundResourceIds(bgResId, dimmedBgResId); - } - /** * @return the potential height this view could expand in addition. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java index d563968..6401695 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java @@ -107,7 +107,7 @@ public class InterceptedNotifications { mBar.updateNotification(mSynKey, sbn); } final NotificationData.Entry entry = mBar.mNotificationData.findByKey(mSynKey); - entry.content.setOnClickListener(mSynClickListener); + entry.row.setOnClickListener(mSynClickListener); } private final View.OnClickListener mSynClickListener = new View.OnClickListener() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index b9a59dd..6b6f55a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -33,7 +33,6 @@ public class NotificationData { public StatusBarNotification notification; public StatusBarIconView icon; public ExpandableNotificationRow row; // the outer expanded view - public View content; // takes the click events and sends the PendingIntent public View expanded; // the inflated RemoteViews public View expandedPublic; // for insecure lockscreens public ImageView largeIcon; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java index be58dad..af91314 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java @@ -18,8 +18,6 @@ package com.android.systemui.statusbar; import android.content.Context; import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; import android.widget.TextView; import com.android.systemui.R; @@ -27,65 +25,30 @@ import com.android.systemui.R; /** * Container view for overflowing notification icons on Keyguard. */ -public class NotificationOverflowContainer extends FrameLayout - implements LatestItemView.OnActivatedListener { +public class NotificationOverflowContainer extends ActivatableNotificationView { private NotificationOverflowIconsView mIconsView; - private LatestItemView.OnActivatedListener mOnActivatedListener; private NotificationActivator mActivator; - public NotificationOverflowContainer(Context context) { - super(context); - } - public NotificationOverflowContainer(Context context, AttributeSet attrs) { super(context, attrs); } - public NotificationOverflowContainer(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public NotificationOverflowContainer(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view); mIconsView.setMoreText((TextView) findViewById(R.id.more_text)); - LatestItemView latestItemView = (LatestItemView) findViewById(R.id.container); mActivator = new NotificationActivator(this); mActivator.setDimmed(true); - latestItemView.setOnActivatedListener(this); - latestItemView.setLocked(true); + setLocked(true); } public NotificationOverflowIconsView getIconsView() { return mIconsView; } - public void setOnActivatedListener(LatestItemView.OnActivatedListener onActivatedListener) { - mOnActivatedListener = onActivatedListener; - } - - @Override - public void onActivated(View view) { - if (mOnActivatedListener != null) { - mOnActivatedListener.onActivated(this); - } - } - - @Override - public void onReset(View view) { - if (mOnActivatedListener != null) { - mOnActivatedListener.onReset(this); - } - } - public NotificationActivator getActivator() { return mActivator; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 9326946..545352c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -247,6 +247,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { private int mCarrierLabelHeight; private TextView mEmergencyCallLabel; private int mNotificationHeaderHeight; + private View mKeyguardCarrierLabel; private boolean mShowCarrierInPanel = false; @@ -616,6 +617,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); mKeyguardIconOverflowContainer.setOnActivatedListener(this); + mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text); mStackScroller.addView(mKeyguardIconOverflowContainer); mExpandedContents = mStackScroller; @@ -1344,7 +1346,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly()) && mStackScroller.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight) - && mStackScroller.getVisibility() == View.VISIBLE; + && mStackScroller.getVisibility() == View.VISIBLE + && !mOnKeyguard; if (force || mCarrierLabelVisible != makeVisible) { mCarrierLabelVisible = makeVisible; @@ -2715,8 +2718,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } mHeadsUpNotificationDecay = res.getInteger(R.integer.heads_up_notification_decay); - mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_row_min_height); - mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_row_max_height); + mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_min_height); + mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height); mKeyguardMaxNotificationCount = res.getInteger(R.integer.keyguard_max_notification_count); @@ -2956,6 +2959,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mKeyguardBottomArea.setVisibility(View.VISIBLE); mKeyguardIndicationTextView.setVisibility(View.VISIBLE); mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase); + mKeyguardCarrierLabel.setVisibility(View.VISIBLE); mNotificationPanelHeader.setVisibility(View.GONE); mKeyguardFlipper.setVisibility(View.VISIBLE); @@ -2964,6 +2968,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mKeyguardStatusView.setVisibility(View.GONE); mKeyguardBottomArea.setVisibility(View.GONE); mKeyguardIndicationTextView.setVisibility(View.GONE); + mKeyguardCarrierLabel.setVisibility(View.GONE); mNotificationPanelHeader.setVisibility(View.VISIBLE); mKeyguardFlipper.setVisibility(View.GONE); @@ -2974,6 +2979,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { updateRowStates(); checkBarModes(); updateNotificationIcons(); + updateCarrierLabelVisibility(false); } public void userActivity() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index c5dae85..6b5ef5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -69,8 +69,8 @@ public class StatusBarWindowView extends FrameLayout mStackScrollLayout = (NotificationStackScrollLayout) findViewById( R.id.notification_stack_scroller); mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel); - int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height); - int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height); + int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); + int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height); mExpandHelper = new ExpandHelper(getContext(), mStackScrollLayout, minHeight, maxHeight); mExpandHelper.setEventSource(this); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java index 2dba669..c94c65f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java @@ -135,8 +135,8 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); mEdgeSwipeHelper = new EdgeSwipeHelper(touchSlop); - int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height); - int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height); + int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); + int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height); mExpandHelper = new ExpandHelper(getContext(), this, minHeight, maxHeight); mContentHolder = (ViewGroup) findViewById(R.id.content_holder); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 36d94a9..948ef90 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -145,13 +145,13 @@ public class NotificationStackScrollLayout extends ViewGroup mSidePaddings = context.getResources() .getDimensionPixelSize(R.dimen.notification_side_padding); mCollapsedSize = context.getResources() - .getDimensionPixelSize(R.dimen.notification_row_min_height); + .getDimensionPixelSize(R.dimen.notification_min_height); mBottomStackPeekSize = context.getResources() .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount); mEmptyMarginBottom = context.getResources().getDimensionPixelSize( R.dimen.notification_stack_margin_bottom); - // currently the padding is in the elements themself - mPaddingBetweenElements = 0; + mPaddingBetweenElements = context.getResources() + .getDimensionPixelSize(R.dimen.notification_padding); mStackScrollAlgorithm = new StackScrollAlgorithm(context); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index d9e7f66..2a6e4ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -62,11 +62,10 @@ public class StackScrollAlgorithm { } private void initConstants(Context context) { - - // currently the padding is in the elements themself - mPaddingBetweenElements = 0; + mPaddingBetweenElements = context.getResources() + .getDimensionPixelSize(R.dimen.notification_padding); mCollapsedSize = context.getResources() - .getDimensionPixelSize(R.dimen.notification_row_min_height); + .getDimensionPixelSize(R.dimen.notification_min_height); mTopStackPeekSize = context.getResources() .getDimensionPixelSize(R.dimen.top_stack_peek_amount); mBottomStackPeekSize = context.getResources() @@ -323,7 +322,8 @@ public class StackScrollAlgorithm { // the offset starting at the transitionPosition of the bottom stack float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom); algorithmState.itemsInBottomStack += algorithmState.partialInBottom; - childViewState.yTranslation = transitioningPositionStart + offset - childHeight; + childViewState.yTranslation = transitioningPositionStart + offset - childHeight + - mPaddingBetweenElements; // We want at least to be at the end of the top stack when collapsing clampPositionToTopStackEnd(childViewState, childHeight); @@ -339,7 +339,8 @@ public class StackScrollAlgorithm { if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) { // We are visually entering the bottom stack currentYPosition = transitioningPositionStart - + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack); + + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack) + - mPaddingBetweenElements; childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING; } else { // we are fully inside the stack @@ -542,9 +543,13 @@ public class StackScrollAlgorithm { public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - mFirstChildMaxHeight = getMaxAllowedChildHeight( - mFirstChildWhileExpanding); - mFirstChildWhileExpanding.removeOnLayoutChangeListener(this); + if (mFirstChildWhileExpanding != null) { + mFirstChildMaxHeight = getMaxAllowedChildHeight( + mFirstChildWhileExpanding); + } else { + mFirstChildMaxHeight = 0; + } + v.removeOnLayoutChangeListener(this); } }); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java index 9742e65..6e2e87e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java @@ -197,18 +197,12 @@ public class StackScrollState { * @param clipHeight the desired clip height, the rest of the view will be clipped from the top */ private void updateChildClip(View child, int height, float clipHeight) { - // The children currently have paddings inside themselfs because of the expansion - // visualization. In order for the clipping to work correctly we have to set the correct - // clip rect on the child. - View container = child.findViewById(R.id.container); - if (container != null) { - int clipInset = (int) (height - clipHeight); - mClipRect.set(0, - clipInset, - child.getWidth(), - height); - child.setClipBounds(mClipRect); - } + int clipInset = (int) (height - clipHeight); + mClipRect.set(0, + clipInset, + child.getWidth(), + height); + child.setClipBounds(mClipRect); } /** @@ -218,22 +212,15 @@ public class StackScrollState { * @param height the currently applied height of the view * @param outlineHeight the desired height of the outline, the outline ends on the bottom */ - private void updateChildOutline(View child, - int height, - float outlineHeight) { - // The children currently have paddings inside themselfs because of the expansion - // visualization. In order for the shadows to work correctly we have to set the correct - // outline on the child. - View container = child.findViewById(R.id.container); - if (container != null) { - int shadowInset = (int) (height - outlineHeight); - getOutlineForSize(container.getLeft(), - container.getTop() + shadowInset, - container.getWidth(), - container.getHeight() - shadowInset, - mChildOutline); - child.setOutline(mChildOutline); - } + private void updateChildOutline(View child, int height, + float outlineHeight) { + int shadowInset = (int) (height - outlineHeight); + getOutlineForSize(child.getLeft(), + child.getTop() + shadowInset, + child.getWidth(), + child.getHeight() - shadowInset, + mChildOutline); + child.setOutline(mChildOutline); } private void getOutlineForSize(int leftInset, int topInset, int width, int height, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c401efb..2c623b5 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5439,7 +5439,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (FileUtils.contains(Environment.getRootDirectory(), codePath)) { codeRoot = Environment.getRootDirectory(); } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) { - codeRoot = Environment.getRootDirectory(); + codeRoot = Environment.getOemDirectory(); } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) { codeRoot = Environment.getVendorDirectory(); } else { diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 87953fe..3eb2d5f 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -25,6 +25,7 @@ import android.app.IWallpaperManager; import android.app.IWallpaperManagerCallback; import android.app.PendingIntent; import android.app.WallpaperInfo; +import android.app.WallpaperManager; import android.app.backup.BackupManager; import android.app.backup.WallpaperBackupHelper; import android.content.BroadcastReceiver; @@ -844,13 +845,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { try { if (componentName == null) { - String defaultComponent = - mContext.getString(com.android.internal.R.string.default_wallpaper_component); - if (defaultComponent != null) { - // See if there is a default wallpaper component specified - componentName = ComponentName.unflattenFromString(defaultComponent); - if (DEBUG) Slog.v(TAG, "Use default component wallpaper:" + componentName); - } + componentName = WallpaperManager.getDefaultWallpaperComponent(mContext); if (componentName == null) { // Fall back to static image wallpaper componentName = IMAGE_WALLPAPER; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 00d5468..08b1eba 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -29,6 +29,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.media.AudioService; +import android.os.Build; import android.os.Environment; import android.os.FactoryTest; import android.os.Handler; @@ -201,6 +202,10 @@ public final class SystemServer { // as efficient as possible with its memory usage. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); + // Some devices rely on runtime fingerprint generation, so make sure + // we've defined it before booting further. + Build.ensureFingerprintProperty(); + // Within the system server, it is an error to access Environment paths without // explicitly specifying a user. Environment.setUserRequired(true); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 9e2bcab..045c0f6 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -16,14 +16,18 @@ package com.android.server.voiceinteraction; +import android.Manifest; import android.app.ActivityManager; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.database.ContentObserver; import android.os.Binder; +import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.UserHandle; import android.provider.Settings; import android.service.voice.IVoiceInteractionService; @@ -134,9 +138,8 @@ public class VoiceInteractionManagerService extends SystemService { } @Override - public int startVoiceActivity(Intent intent, String resolvedType, - IVoiceInteractionService service, - IVoiceInteractionSession session, IVoiceInteractor interactor) { + public void startVoiceActivity(Intent intent, String resolvedType, + IVoiceInteractionService service, Bundle args) { synchronized (this) { if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) { throw new SecurityException( @@ -146,8 +149,8 @@ public class VoiceInteractionManagerService extends SystemService { final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { - return mImpl.startVoiceActivityLocked(callingPid, callingUid, - intent, resolvedType, session, interactor); + mImpl.startVoiceActivityLocked(callingPid, callingUid, + intent, resolvedType, args); } finally { Binder.restoreCallingIdentity(caller); } @@ -155,8 +158,43 @@ public class VoiceInteractionManagerService extends SystemService { } @Override + public int deliverNewSession(IBinder token, IVoiceInteractionSession session, + IVoiceInteractor interactor) { + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, "deliverNewSession without running voice interaction service"); + return ActivityManager.START_CANCELED; + } + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); + final long caller = Binder.clearCallingIdentity(); + try { + return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session, + interactor); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump PowerManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + synchronized (this) { + pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n"); + if (mImpl == null) { + pw.println(" (No active implementation)"); + return; + } + mImpl.dumpLocked(fd, pw, args); + } } class SettingsObserver extends ContentObserver { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index af8ae1e..6bbd1c1 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -16,6 +16,7 @@ package com.android.server.voiceinteraction; +import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.content.ComponentName; @@ -24,29 +25,40 @@ import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; +import android.os.Binder; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.service.voice.IVoiceInteractionService; import android.service.voice.IVoiceInteractionSession; +import android.service.voice.IVoiceInteractionSessionService; import android.service.voice.VoiceInteractionService; +import android.service.voice.VoiceInteractionServiceInfo; import android.util.Slog; import com.android.internal.app.IVoiceInteractor; +import java.io.FileDescriptor; +import java.io.PrintWriter; + class VoiceInteractionManagerServiceImpl { final static String TAG = "VoiceInteractionServiceManager"; + final boolean mValid; + final Context mContext; final Handler mHandler; final Object mLock; final int mUser; final ComponentName mComponent; final IActivityManager mAm; + final VoiceInteractionServiceInfo mInfo; + final ComponentName mSessionComponentName; boolean mBound = false; IVoiceInteractionService mService; - IVoiceInteractionSession mActiveSession; - IVoiceInteractor mActiveInteractor; + + SessionConnection mActiveSession; final ServiceConnection mConnection = new ServiceConnection() { @Override @@ -62,6 +74,72 @@ class VoiceInteractionManagerServiceImpl { } }; + final class SessionConnection implements ServiceConnection { + final IBinder mToken = new Binder(); + final Intent mIntent; + final String mResolvedType; + final Bundle mArgs; + boolean mBound; + IVoiceInteractionSessionService mService; + IVoiceInteractionSession mSession; + IVoiceInteractor mInteractor; + + SessionConnection(Intent intent, String resolvedType, Bundle args) { + mIntent = intent; + mResolvedType = resolvedType; + mArgs = args; + Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); + serviceIntent.setComponent(mSessionComponentName); + mBound = mContext.bindServiceAsUser(serviceIntent, this, + Context.BIND_AUTO_CREATE, new UserHandle(mUser)); + if (!mBound) { + Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent); + } + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mLock) { + mService = IVoiceInteractionSessionService.Stub.asInterface(service); + if (mActiveSession == this) { + try { + mService.newSession(mToken, mArgs); + } catch (RemoteException e) { + Slog.w(TAG, "Failed making new session", e); + } + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + + public void cancel() { + if (mBound) { + mContext.unbindService(this); + mBound = false; + mService = null; + mSession = null; + mInteractor = null; + } + } + + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); pw.print("mToken="); pw.println(mToken); + pw.print(prefix); pw.print("mIntent="); pw.println(mIntent); + pw.print(" mResolvedType="); pw.println(mResolvedType); + pw.print(prefix); pw.print("mArgs="); pw.println(mArgs); + pw.print(prefix); pw.print("mBound="); pw.println(mBound); + if (mBound) { + pw.print(prefix); pw.print("mService="); pw.println(mService); + pw.print(prefix); pw.print("mSession="); pw.println(mSession); + pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor); + } + } + }; + VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock, int userHandle, ComponentName service) { mContext = context; @@ -70,50 +148,85 @@ class VoiceInteractionManagerServiceImpl { mUser = userHandle; mComponent = service; mAm = ActivityManagerNative.getDefault(); - } - - public int startVoiceActivityLocked(int callingPid, int callingUid, Intent intent, - String resolvedType, IVoiceInteractionSession session, IVoiceInteractor interactor) { - if (session == null) { - throw new NullPointerException("session is null"); + VoiceInteractionServiceInfo info; + try { + info = new VoiceInteractionServiceInfo(context.getPackageManager(), service); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, "Voice interaction service not found: " + service); + mInfo = null; + mSessionComponentName = null; + mValid = false; + return; } - if (interactor == null) { - throw new NullPointerException("interactor is null"); + mInfo = info; + if (mInfo.getParseError() != null) { + Slog.w(TAG, "Bad voice interaction service: " + mInfo.getParseError()); + mSessionComponentName = null; + mValid = false; + return; } + mValid = true; + mSessionComponentName = new ComponentName(service.getPackageName(), + mInfo.getSessionService()); + } + + public void startVoiceActivityLocked(int callingPid, int callingUid, Intent intent, + String resolvedType, Bundle args) { if (mActiveSession != null) { - // XXX cancel current session. + mActiveSession.cancel(); + mActiveSession = null; } + mActiveSession = new SessionConnection(intent, resolvedType, args); intent.addCategory(Intent.CATEGORY_VOICE); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - mActiveSession = session; - mActiveInteractor = interactor; + } + + public int deliverNewSessionLocked(int callingPid, int callingUid, IBinder token, + IVoiceInteractionSession session, IVoiceInteractor interactor) { try { + if (mActiveSession == null || token != mActiveSession.mToken) { + Slog.w(TAG, "deliverNewSession does not match active session"); + return ActivityManager.START_CANCELED; + } + mActiveSession.mSession = session; + mActiveSession.mInteractor = interactor; return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid, - intent, resolvedType, mActiveSession, mActiveInteractor, + mActiveSession.mIntent, mActiveSession.mResolvedType, + mActiveSession.mSession, mActiveSession.mInteractor, 0, null, null, null, mUser); } catch (RemoteException e) { throw new IllegalStateException("Unexpected remote error", e); } } - void startLocked() { - Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); - intent.setComponent(mComponent); - try { - ServiceInfo si = mContext.getPackageManager().getServiceInfo(mComponent, 0); - if (!android.Manifest.permission.BIND_VOICE_INTERACTION.equals(si.permission)) { - Slog.w(TAG, "Not using voice interaction service " + mComponent - + ": does not require permission " - + android.Manifest.permission.BIND_VOICE_INTERACTION); - return; + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!mValid) { + pw.print(" NOT VALID: "); + if (mInfo == null) { + pw.println("no info"); + } else { + pw.println(mInfo.getParseError()); } - } catch (PackageManager.NameNotFoundException e) { - Slog.w(TAG, "Unable to find voice interaction service: " + mComponent, e); return; } - mContext.bindServiceAsUser(intent, mConnection, + pw.print(" mComponent="); pw.println(mComponent.flattenToShortString()); + pw.print(" Session service="); pw.println(mInfo.getSessionService()); + pw.print(" Settings activity="); pw.println(mInfo.getSettingsActivity()); + pw.print(" mBound="); pw.print(mBound); pw.print(" mService="); pw.println(mService); + if (mActiveSession != null) { + pw.println(" Active session:"); + mActiveSession.dump(" ", pw); + } + } + + void startLocked() { + Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE); + intent.setComponent(mComponent); + mBound = mContext.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, new UserHandle(mUser)); - mBound = true; + if (!mBound) { + Slog.w(TAG, "Failed binding to voice interaction service " + mComponent); + } } void shutdownLocked() { diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml index 9c5acf9..ac0f701 100644 --- a/tests/VoiceInteraction/AndroidManifest.xml +++ b/tests/VoiceInteraction/AndroidManifest.xml @@ -12,10 +12,16 @@ <service android:name="MainInteractionService" android:permission="android.permission.BIND_VOICE_INTERACTION" android:process=":interactor"> + <meta-data android:name="android.voice_interaction" + android:resource="@xml/interaction_service" /> <intent-filter> <action android:name="android.service.voice.VoiceInteractionService" /> </intent-filter> </service> + <service android:name="MainInteractionSessionService" + android:permission="android.permission.BIND_VOICE_INTERACTION" + android:process=":session"> + </service> <activity android:name="TestInteractionActivity" android:label="Voice Interaction Target"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/tests/VoiceInteraction/res/xml/interaction_service.xml b/tests/VoiceInteraction/res/xml/interaction_service.xml new file mode 100644 index 0000000..45bd994d --- /dev/null +++ b/tests/VoiceInteraction/res/xml/interaction_service.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * 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. + */ +--> + +<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android" + android:sessionService="com.android.test.voiceinteraction.MainInteractionSessionService" /> diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java index 35702f1..008d97b 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java @@ -31,8 +31,7 @@ public class MainInteractionService extends VoiceInteractionService { @Override public int onStartCommand(Intent intent, int flags, int startId) { - startVoiceActivity(new Intent(this, TestInteractionActivity.class), - new MainInteractionSession(this)); + startVoiceActivity(new Intent(this, TestInteractionActivity.class), null); stopSelf(startId); return START_NOT_STICKY; } diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java index adc0df4..0fc563b 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java @@ -24,8 +24,11 @@ import android.util.Log; public class MainInteractionSession extends VoiceInteractionSession { static final String TAG = "MainInteractionSession"; - MainInteractionSession(Context context) { + final Bundle mArgs; + + MainInteractionSession(Context context, Bundle args) { super(context); + mArgs = args; } @Override @@ -42,7 +45,7 @@ public class MainInteractionSession extends VoiceInteractionSession { @Override public void onCommand(Caller caller, Request request, String command, Bundle extras) { Log.i(TAG, "onCommand: command=" + command + " extras=" + extras); - request.sendCommandResult(null); + request.sendCommandResult(true, null); } @Override diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java new file mode 100644 index 0000000..8864d71 --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java @@ -0,0 +1,28 @@ +/* + * 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 com.android.test.voiceinteraction; + +import android.os.Bundle; +import android.service.voice.VoiceInteractionSession; +import android.service.voice.VoiceInteractionSessionService; + +public class MainInteractionSessionService extends VoiceInteractionSessionService { + @Override + public VoiceInteractionSession onNewSession(Bundle args) { + return new MainInteractionSession(this, args); + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java index 016a80e..9c772ff 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java @@ -30,28 +30,30 @@ public class TestInteractionActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.test_interaction); if (!isVoiceInteraction()) { Log.w(TAG, "Not running as a voice interaction!"); finish(); return; } + setContentView(R.layout.test_interaction); + mInteractor = getVoiceInteractor(); - mInteractor.startConfirmation(new VoiceInteractor.Callback() { + VoiceInteractor.ConfirmationRequest req = new VoiceInteractor.ConfirmationRequest( + "This is a confirmation", null) { @Override - public void onConfirmationResult(VoiceInteractor.Request request, boolean confirmed, - Bundle result) { - Log.i(TAG, "Confirmation result: confirmed=" + confirmed + " result=" + result); - finish(); + public void onCancel() { + Log.i(TAG, "Canceled!"); + getActivity().finish(); } @Override - public void onCancel(VoiceInteractor.Request request) { - Log.i(TAG, "Canceled!"); - finish(); + public void onConfirmationResult(boolean confirmed, Bundle result) { + Log.i(TAG, "Confirmation result: confirmed=" + confirmed + " result=" + result); + getActivity().finish(); } - }, "This is a confirmation", null); + }; + mInteractor.submitRequest(req); } @Override |