Merge "Fade Transition sometimes disappeared improperly."
diff --git a/Android.mk b/Android.mk
index adc9ef1..852247c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -155,6 +155,7 @@
core/java/android/net/INetworkManagementEventObserver.aidl \
core/java/android/net/INetworkPolicyListener.aidl \
core/java/android/net/INetworkPolicyManager.aidl \
+ core/java/android/net/INetworkScoreService.aidl \
core/java/android/net/INetworkStatsService.aidl \
core/java/android/net/INetworkStatsSession.aidl \
core/java/android/net/nsd/INsdManager.aidl \
@@ -179,6 +180,8 @@
core/java/android/os/IUserManager.aidl \
core/java/android/os/IVibratorService.aidl \
core/java/android/service/notification/INotificationListener.aidl \
+ core/java/android/service/notification/IConditionListener.aidl \
+ core/java/android/service/notification/IConditionProvider.aidl \
core/java/android/print/ILayoutResultCallback.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
core/java/android/print/IPrintDocumentAdapter.aidl \
@@ -196,6 +199,8 @@
core/java/android/service/dreams/IDreamService.aidl \
core/java/android/service/trust/ITrustAgentService.aidl \
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/wallpaper/IWallpaperConnection.aidl \
core/java/android/service/wallpaper/IWallpaperEngine.aidl \
core/java/android/service/wallpaper/IWallpaperService.aidl \
@@ -229,6 +234,10 @@
core/java/com/android/internal/app/IBatteryStats.aidl \
core/java/com/android/internal/app/IProcessStats.aidl \
core/java/com/android/internal/app/IUsageStats.aidl \
+ core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
+ core/java/com/android/internal/app/IVoiceInteractor.aidl \
+ core/java/com/android/internal/app/IVoiceInteractorCallback.aidl \
+ core/java/com/android/internal/app/IVoiceInteractorRequest.aidl \
core/java/com/android/internal/app/IMediaContainerService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
@@ -288,11 +297,14 @@
media/java/android/media/IRemoteDisplayProvider.aidl \
media/java/android/media/IRemoteVolumeObserver.aidl \
media/java/android/media/IRingtonePlayer.aidl \
- media/java/android/media/session/IMediaController.aidl \
- media/java/android/media/session/IMediaControllerCallback.aidl \
- media/java/android/media/session/IMediaSession.aidl \
- media/java/android/media/session/IMediaSessionCallback.aidl \
- media/java/android/media/session/IMediaSessionManager.aidl \
+ media/java/android/media/routeprovider/IRouteConnection.aidl \
+ media/java/android/media/routeprovider/IRouteProvider.aidl \
+ media/java/android/media/routeprovider/IRouteProviderCallback.aidl \
+ media/java/android/media/session/ISessionController.aidl \
+ media/java/android/media/session/ISessionControllerCallback.aidl \
+ media/java/android/media/session/ISession.aidl \
+ media/java/android/media/session/ISessionCallback.aidl \
+ media/java/android/media/session/ISessionManager.aidl \
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index ffdac4e..c6f6a62 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -189,6 +189,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java/android/media/IMedia*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/view/IMagnificationCallbacks*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/media/java/android/media/)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.txt b/api/current.txt
index e13b3c2..4fef0d0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27,9 +27,11 @@
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+ field public static final java.lang.String BIND_ROUTE_PROVIDER = "android.permission.BIND_ROUTE_PROVIDER";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TRUST_AGENT_SERVICE = "android.permission.BIND_TRUST_AGENT_SERVICE";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+ field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
@@ -283,6 +285,7 @@
field public static final int allContactsName = 16843468; // 0x10102cc
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
+ field public static final int allowEmbedded = 16843765; // 0x10103f5
field public static final int allowParallelSyncs = 16843570; // 0x1010332
field public static final int allowSingleTap = 16843353; // 0x1010259
field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -699,7 +702,6 @@
field public static final int l_resource_pad25 = 16843768; // 0x10103f8
field public static final int l_resource_pad26 = 16843767; // 0x10103f7
field public static final int l_resource_pad27 = 16843766; // 0x10103f6
- field public static final int l_resource_pad28 = 16843765; // 0x10103f5
field public static final int l_resource_pad3 = 16843790; // 0x101040e
field public static final int l_resource_pad4 = 16843789; // 0x101040d
field public static final int l_resource_pad5 = 16843788; // 0x101040c
@@ -824,6 +826,7 @@
field public static final int name = 16842755; // 0x1010003
field public static final int navigationMode = 16843471; // 0x10102cf
field public static final int negativeButtonText = 16843254; // 0x10101f6
+ field public static final int nestedScrollingEnabled = 16843843; // 0x1010443
field public static final int nextFocusDown = 16842980; // 0x10100e4
field public static final int nextFocusForward = 16843580; // 0x101033c
field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -1284,8 +1287,8 @@
field public static final int windowActionBar = 16843469; // 0x10102cd
field public static final int windowActionBarOverlay = 16843492; // 0x10102e4
field public static final int windowActionModeOverlay = 16843485; // 0x10102dd
- field public static final int windowAllowEnterTransitionOverlap = 16843848; // 0x1010448
- field public static final int windowAllowExitTransitionOverlap = 16843847; // 0x1010447
+ field public static final int windowAllowEnterTransitionOverlap = 16843849; // 0x1010449
+ field public static final int windowAllowExitTransitionOverlap = 16843848; // 0x1010448
field public static final int windowAnimationStyle = 16842926; // 0x10100ae
field public static final int windowBackground = 16842836; // 0x1010054
field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
@@ -1295,9 +1298,9 @@
field public static final int windowDisablePreview = 16843298; // 0x1010222
field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
field public static final int windowEnterAnimation = 16842932; // 0x10100b4
- field public static final int windowEnterTransition = 16843843; // 0x1010443
+ field public static final int windowEnterTransition = 16843844; // 0x1010444
field public static final int windowExitAnimation = 16842933; // 0x10100b5
- field public static final int windowExitTransition = 16843844; // 0x1010444
+ field public static final int windowExitTransition = 16843845; // 0x1010445
field public static final int windowFrame = 16842837; // 0x1010055
field public static final int windowFullscreen = 16843277; // 0x101020d
field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1308,8 +1311,8 @@
field public static final int windowNoDisplay = 16843294; // 0x101021e
field public static final int windowNoTitle = 16842838; // 0x1010056
field public static final int windowOverscan = 16843727; // 0x10103cf
- field public static final int windowSharedElementEnterTransition = 16843845; // 0x1010445
- field public static final int windowSharedElementExitTransition = 16843846; // 0x1010446
+ field public static final int windowSharedElementEnterTransition = 16843846; // 0x1010446
+ field public static final int windowSharedElementExitTransition = 16843847; // 0x1010447
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -3174,6 +3177,7 @@
method public void finishActivity(int);
method public void finishActivityFromChild(android.app.Activity, int);
method public void finishAffinity();
+ method public void finishAndRemoveTask();
method public void finishFromChild(android.app.Activity);
method public void finishWithTransition();
method public android.app.ActionBar getActionBar();
@@ -3199,6 +3203,7 @@
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
+ method public android.app.VoiceInteractor getVoiceInteractor();
method public final int getVolumeControlStream();
method public android.view.Window getWindow();
method public android.view.WindowManager getWindowManager();
@@ -3210,6 +3215,7 @@
method public boolean isFinishing();
method public boolean isImmersive();
method public boolean isTaskRoot();
+ method public boolean isVoiceInteraction();
method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
method public boolean moveTaskToBack(boolean);
method public boolean navigateUpTo(android.content.Intent);
@@ -4835,6 +4841,23 @@
field public static final int MODE_NIGHT_YES = 2; // 0x2
}
+ 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[] 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.Request {
+ method public void cancel();
+ }
+
public final class WallpaperInfo implements android.os.Parcelable {
ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
@@ -4944,7 +4967,9 @@
public class DevicePolicyManager {
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
+ method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
+ method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5007,6 +5032,9 @@
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0
field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2
+ field public static final int KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 4; // 0x4
+ field public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 16; // 0x10
+ field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8
field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -6926,6 +6954,7 @@
field public static final java.lang.String ACTION_PASTE = "android.intent.action.PASTE";
field public static final java.lang.String ACTION_PICK = "android.intent.action.PICK";
field public static final java.lang.String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY";
+ field public static final java.lang.String ACTION_PICK_DIRECTORY = "android.intent.action.PICK_DIRECTORY";
field public static final java.lang.String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
@@ -6993,6 +7022,7 @@
field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
+ field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
field public static final android.os.Parcelable.Creator CREATOR;
field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -7074,6 +7104,7 @@
field public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 16; // 0x10
field public static final int FLAG_FROM_BACKGROUND = 4; // 0x4
field public static final int FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 64; // 0x40
+ field public static final int FLAG_GRANT_PREFIX_URI_PERMISSION = 128; // 0x80
field public static final int FLAG_GRANT_READ_URI_PERMISSION = 1; // 0x1
field public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 2; // 0x2
field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
@@ -7707,6 +7738,7 @@
method public long getFirstInstallTime();
method public android.graphics.drawable.Drawable getIcon(int);
method public java.lang.CharSequence getLabel();
+ method public java.lang.String getName();
method public android.os.UserHandle getUser();
}
@@ -9705,6 +9737,7 @@
method public void drawRect(android.graphics.Rect, android.graphics.Paint);
method public void drawRect(float, float, float, float, android.graphics.Paint);
method public void drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint);
+ method public void drawRoundRect(float, float, float, float, float, float, android.graphics.Paint);
method public void drawText(char[], int, int, float, float, android.graphics.Paint);
method public void drawText(java.lang.String, float, float, android.graphics.Paint);
method public void drawText(java.lang.String, int, int, float, float, android.graphics.Paint);
@@ -9735,9 +9768,13 @@
method public int save();
method public int save(int);
method public int saveLayer(android.graphics.RectF, android.graphics.Paint, int);
+ method public int saveLayer(android.graphics.RectF, android.graphics.Paint);
method public int saveLayer(float, float, float, float, android.graphics.Paint, int);
+ method public int saveLayer(float, float, float, float, android.graphics.Paint);
method public int saveLayerAlpha(android.graphics.RectF, int, int);
+ method public int saveLayerAlpha(android.graphics.RectF, int);
method public int saveLayerAlpha(float, float, float, float, int, int);
+ method public int saveLayerAlpha(float, float, float, float, int);
method public void scale(float, float);
method public final void scale(float, float, float, float);
method public void setBitmap(android.graphics.Bitmap);
@@ -10013,11 +10050,18 @@
method public void setPaint(android.graphics.Paint);
}
- public class Outline {
+ public final class Outline {
ctor public Outline();
- method public final boolean isValid();
+ ctor public Outline(android.graphics.Outline);
+ method public boolean isValid();
method public void set(android.graphics.Outline);
+ method public void setConvexPath(android.graphics.Path);
+ method public void setOval(int, int, int, int);
+ method public void setOval(android.graphics.Rect);
+ method public void setRect(int, int, int, int);
+ method public void setRect(android.graphics.Rect);
method public void setRoundRect(int, int, int, int, float);
+ method public void setRoundRect(android.graphics.Rect, float);
}
public class Paint {
@@ -10186,6 +10230,7 @@
method public void addArc(android.graphics.RectF, float, float);
method public void addCircle(float, float, float, android.graphics.Path.Direction);
method public void addOval(android.graphics.RectF, android.graphics.Path.Direction);
+ method public void addOval(float, float, float, float, android.graphics.Path.Direction);
method public void addPath(android.graphics.Path, float, float);
method public void addPath(android.graphics.Path);
method public void addPath(android.graphics.Path, android.graphics.Matrix);
@@ -10740,7 +10785,7 @@
method public int getMinimumHeight();
method public int getMinimumWidth();
method public abstract int getOpacity();
- method public android.graphics.Outline getOutline();
+ method public boolean getOutline(android.graphics.Outline);
method public boolean getPadding(android.graphics.Rect);
method public int[] getState();
method public android.graphics.Region getTransparentRegion();
@@ -11113,6 +11158,7 @@
method public android.graphics.drawable.shapes.Shape clone() throws java.lang.CloneNotSupportedException;
method public abstract void draw(android.graphics.Canvas, android.graphics.Paint);
method public final float getHeight();
+ method public boolean getOutline(android.graphics.Outline);
method public final float getWidth();
method public boolean hasAlpha();
method protected void onResize(float, float);
@@ -12119,7 +12165,9 @@
public final class VirtualDisplay {
method public android.view.Display getDisplay();
+ method public android.view.Surface getSurface();
method public void release();
+ method public void setSurface(android.view.Surface);
}
}
@@ -13365,6 +13413,18 @@
ctor public DeniedByServerException(java.lang.String);
}
+ public final class DngCreator {
+ ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult);
+ method public android.media.DngCreator setDescription(java.lang.String);
+ method public android.media.DngCreator setLocation(android.location.Location);
+ method public android.media.DngCreator setOrientation(int);
+ method public android.media.DngCreator setThumbnail(android.graphics.Bitmap);
+ method public android.media.DngCreator setThumbnail(android.media.Image);
+ method public void writeByteBuffer(java.io.OutputStream, java.nio.ByteBuffer, int, long) throws java.io.IOException;
+ method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException;
+ method public void writeInputStream(java.io.OutputStream, java.io.InputStream, int, long) throws java.io.IOException;
+ }
+
public class ExifInterface {
ctor public ExifInterface(java.lang.String) throws java.io.IOException;
method public double getAltitude(double);
@@ -14957,24 +15017,68 @@
}
+package android.media.routeprovider {
+
+ public final class RouteConnection {
+ ctor public RouteConnection(android.media.routeprovider.RouteProviderService, android.media.session.RouteInfo);
+ method public android.media.routeprovider.RouteInterfaceHandler addRouteInterface(java.lang.String);
+ method public android.media.routeprovider.RouteInterfaceHandler getRouteInterface(java.lang.String);
+ method public void shutDown();
+ }
+
+ public final class RouteInterfaceHandler {
+ method public void addListener(android.media.routeprovider.RouteInterfaceHandler.CommandListener, android.os.Handler);
+ method public java.lang.String getName();
+ method public void removeListener(android.media.routeprovider.RouteInterfaceHandler.CommandListener);
+ method public void sendEvent(java.lang.String, android.os.Bundle);
+ method public static void sendResult(android.os.ResultReceiver, int, android.os.Bundle);
+ }
+
+ public static abstract class RouteInterfaceHandler.CommandListener {
+ ctor public RouteInterfaceHandler.CommandListener();
+ method public abstract boolean onCommand(android.media.routeprovider.RouteInterfaceHandler, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ }
+
+ public final class RoutePlaybackControlsHandler {
+ method public void addListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener);
+ method public void addListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener, android.os.Handler);
+ method public static android.media.routeprovider.RoutePlaybackControlsHandler addTo(android.media.routeprovider.RouteConnection);
+ method public void removeListener(android.media.routeprovider.RoutePlaybackControlsHandler.Listener);
+ method public void sendPlaybackChangeEvent(int);
+ }
+
+ public static abstract class RoutePlaybackControlsHandler.Listener extends android.media.routeprovider.RouteInterfaceHandler.CommandListener {
+ ctor public RoutePlaybackControlsHandler.Listener();
+ method public boolean fastForward();
+ method public long getCapabilities();
+ method public long getCurrentPosition();
+ method public final boolean onCommand(android.media.routeprovider.RouteInterfaceHandler, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ method public boolean pause();
+ method public void playNow(java.lang.String, android.os.ResultReceiver);
+ method public boolean resume();
+ }
+
+ public abstract class RouteProviderService extends android.app.Service {
+ ctor public RouteProviderService();
+ method public abstract android.media.routeprovider.RouteConnection connect(android.media.session.RouteInfo, android.media.routeprovider.RouteRequest);
+ method public abstract java.util.List<android.media.session.RouteInfo> getMatchingRoutes(java.util.List<android.media.routeprovider.RouteRequest>);
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public void updateDiscoveryRequests(java.util.List<android.media.routeprovider.RouteRequest>);
+ field public static final java.lang.String SERVICE_INTERFACE = "com.android.media.session.MediaRouteProvider";
+ }
+
+ public final class RouteRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.media.session.RouteOptions getConnectionOptions();
+ method public android.media.session.SessionInfo getSessionInfo();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+}
+
package android.media.session {
- public final class MediaController {
- method public void addCallback(android.media.session.MediaController.Callback);
- method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler);
- method public static android.media.session.MediaController fromToken(android.media.session.MediaSessionToken);
- method public android.media.session.TransportController getTransportController();
- method public void removeCallback(android.media.session.MediaController.Callback);
- method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- method public void sendMediaButton(int);
- }
-
- public static abstract class MediaController.Callback {
- ctor public MediaController.Callback();
- method public void onEvent(java.lang.String, android.os.Bundle);
- method public void onRouteChanged(android.os.Bundle);
- }
-
public final class MediaMetadata implements android.os.Parcelable {
method public int describeContents();
method public android.graphics.Bitmap getBitmap(java.lang.String);
@@ -15015,36 +15119,6 @@
method public android.media.session.MediaMetadata.Builder putString(java.lang.String, java.lang.String);
}
- public final class MediaSession {
- method public void addCallback(android.media.session.MediaSession.Callback);
- method public void addCallback(android.media.session.MediaSession.Callback, android.os.Handler);
- method public android.media.session.MediaSessionToken getSessionToken();
- method public android.media.session.TransportPerformer getTransportPerformer();
- method public void publish();
- method public void release();
- method public void removeCallback(android.media.session.MediaSession.Callback);
- method public void sendEvent(java.lang.String, android.os.Bundle);
- method public android.media.session.TransportPerformer setTransportPerformerEnabled();
- }
-
- public static abstract class MediaSession.Callback {
- ctor public MediaSession.Callback();
- method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- method public void onMediaButton(android.content.Intent);
- method public void onRequestRouteChange(android.os.Bundle);
- }
-
- public final class MediaSessionManager {
- method public android.media.session.MediaSession createSession(java.lang.String);
- method public java.util.List<android.media.session.MediaController> getActiveSessions();
- }
-
- public class MediaSessionToken implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- }
-
public final class PlaybackState implements android.os.Parcelable {
ctor public PlaybackState();
ctor public PlaybackState(android.media.session.PlaybackState);
@@ -15073,6 +15147,7 @@
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int PLAYSTATE_BUFFERING = 6; // 0x6
+ field public static final int PLAYSTATE_CONNECTING = 8; // 0x8
field public static final int PLAYSTATE_ERROR = 7; // 0x7
field public static final int PLAYSTATE_FAST_FORWARDING = 4; // 0x4
field public static final int PLAYSTATE_NONE = 0; // 0x0
@@ -15082,11 +15157,44 @@
field public static final int PLAYSTATE_STOPPED = 1; // 0x1
}
+ public final class Route {
+ method public android.media.session.RouteInterface getInterface(java.lang.String);
+ method public android.media.session.RouteOptions getOptions();
+ method public android.media.session.RouteInfo getRouteInfo();
+ }
+
+ public final class RouteInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.util.List<android.media.session.RouteOptions> getConnectionMethods();
+ method public java.lang.String getId();
+ method public java.lang.String getName();
+ method public java.lang.String getProvider();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public static final class RouteInfo.Builder {
+ ctor public RouteInfo.Builder(android.media.session.RouteInfo);
+ ctor public RouteInfo.Builder();
+ method public android.media.session.RouteInfo.Builder addRouteOptions(android.media.session.RouteOptions);
+ method public android.media.session.RouteInfo build();
+ method public android.media.session.RouteInfo.Builder clearRouteOptions();
+ method public int getOptionsSize();
+ method public android.media.session.RouteInfo.Builder setId(java.lang.String);
+ method public android.media.session.RouteInfo.Builder setName(java.lang.String);
+ }
+
public final class RouteInterface {
method public void addListener(android.media.session.RouteInterface.EventListener);
method public void addListener(android.media.session.RouteInterface.EventListener, android.os.Handler);
method public void removeListener(android.media.session.RouteInterface.EventListener);
- method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ method public boolean sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ field public static final int RESULT_COMMAND_NOT_SUPPORTED = -3; // 0xfffffffd
+ field public static final int RESULT_ERROR = -1; // 0xffffffff
+ field public static final int RESULT_INTERFACE_NOT_SUPPORTED = -2; // 0xfffffffe
+ field public static final int RESULT_NOT_CONNECTED = -5; // 0xfffffffb
+ field public static final int RESULT_ROUTE_IS_STALE = -4; // 0xfffffffc
+ field public static final int RESULT_SUCCESS = 1; // 0x1
}
public static abstract class RouteInterface.EventListener {
@@ -15094,40 +15202,100 @@
method public abstract void onEvent(java.lang.String, android.os.Bundle);
}
- public static abstract class RouteInterface.Stub {
- ctor public RouteInterface.Stub();
- method public abstract java.lang.String getName();
- method public abstract void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- method public final void sendEvent(android.media.session.MediaSession, java.lang.String, android.os.Bundle);
+ public final class RouteOptions implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getConnectionParams();
+ method public java.util.List<java.lang.String> getInterfaceNames();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
}
- public final class RouteTransportControls {
- method public void addListener(android.media.session.RouteTransportControls.Listener);
- method public void addListener(android.media.session.RouteTransportControls.Listener, android.os.Handler);
- method public void fastForward(float);
- method public static android.media.session.RouteTransportControls from(android.media.session.MediaController);
+ public static final class RouteOptions.Builder {
+ ctor public RouteOptions.Builder();
+ method public android.media.session.RouteOptions.Builder addInterface(java.lang.String);
+ method public android.media.session.RouteOptions build();
+ method public android.media.session.RouteOptions.Builder setParameters(android.os.Bundle);
+ }
+
+ public final class RoutePlaybackControls {
+ method public void addListener(android.media.session.RoutePlaybackControls.Listener);
+ method public void addListener(android.media.session.RoutePlaybackControls.Listener, android.os.Handler);
+ method public void fastForward();
+ method public static android.media.session.RoutePlaybackControls from(android.media.session.Route);
method public void getCapabilities(android.os.ResultReceiver);
method public void getCurrentPosition(android.os.ResultReceiver);
method public void pause();
- method public void play();
- method public void removeListener(android.media.session.RouteTransportControls.Listener);
- field public static final java.lang.String NAME = "android.media.session.RouteTransportControls";
+ method public void playNow(java.lang.String);
+ method public void removeListener(android.media.session.RoutePlaybackControls.Listener);
+ method public void resume();
+ field public static final java.lang.String NAME = "android.media.session.RoutePlaybackControls";
}
- public static abstract class RouteTransportControls.Listener {
- ctor public RouteTransportControls.Listener();
- method public void onMetadataUpdate(android.os.Bundle);
+ public static abstract class RoutePlaybackControls.Listener extends android.media.session.RouteInterface.EventListener {
+ ctor public RoutePlaybackControls.Listener();
+ method public final void onEvent(java.lang.String, android.os.Bundle);
+ method public void onMetadataUpdate(android.media.session.MediaMetadata);
method public void onPlaybackStateChange(int);
}
- public static abstract class RouteTransportControls.Stub extends android.media.session.RouteInterface.Stub {
- ctor public RouteTransportControls.Stub(android.media.session.MediaSession);
- method public void fastForward(float);
- method public long getCapabilities();
- method public long getCurrentPosition();
- method public java.lang.String getName();
+ public final class Session {
+ method public void addCallback(android.media.session.Session.Callback);
+ method public void addCallback(android.media.session.Session.Callback, android.os.Handler);
+ method public void connect(android.media.session.RouteInfo, android.media.session.RouteOptions);
+ method public void disconnect(android.media.session.RouteInfo);
+ method public android.media.session.SessionToken getSessionToken();
+ method public android.media.session.TransportPerformer getTransportPerformer();
+ method public void publish();
+ method public void release();
+ method public void removeCallback(android.media.session.Session.Callback);
+ method public void sendEvent(java.lang.String, android.os.Bundle);
+ method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
+ method public android.media.session.TransportPerformer setTransportPerformerEnabled();
+ }
+
+ public static abstract class Session.Callback {
+ ctor public Session.Callback();
method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- method public final void updatePlaybackState(int);
+ method public void onMediaButton(android.content.Intent);
+ method public void onRequestRouteChange(android.media.session.RouteInfo);
+ method public void onRouteConnected(android.media.session.Route);
+ method public void onRouteDisconnected(android.media.session.Route, int);
+ }
+
+ public final class SessionController {
+ method public void addCallback(android.media.session.SessionController.Callback);
+ method public void addCallback(android.media.session.SessionController.Callback, android.os.Handler);
+ method public static android.media.session.SessionController fromToken(android.media.session.SessionToken);
+ method public android.media.session.TransportController getTransportController();
+ method public void removeCallback(android.media.session.SessionController.Callback);
+ method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ method public void sendMediaButton(int);
+ method public void showRoutePicker();
+ }
+
+ public static abstract class SessionController.Callback {
+ ctor public SessionController.Callback();
+ method public void onEvent(java.lang.String, android.os.Bundle);
+ method public void onRouteChanged(android.media.session.RouteInfo);
+ }
+
+ public final class SessionInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.String getId();
+ method public java.lang.String getPackageName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public final class SessionManager {
+ method public android.media.session.Session createSession(java.lang.String);
+ method public java.util.List<android.media.session.SessionController> getActiveSessions();
+ }
+
+ public class SessionToken implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
}
public final class TransportController {
@@ -16696,11 +16864,24 @@
package android.nfc.cardemulation {
+ public final class AidGroup implements android.os.Parcelable {
+ ctor public AidGroup(java.util.ArrayList<java.lang.String>, java.lang.String);
+ method public int describeContents();
+ method public java.util.ArrayList<java.lang.String> getAids();
+ method public java.lang.String getCategory();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int MAX_NUM_AIDS = 256; // 0x100
+ }
+
public final class CardEmulation {
+ method public android.nfc.cardemulation.AidGroup getAidGroupForService(android.content.ComponentName, java.lang.String);
method public static synchronized android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
method public int getSelectionModeForCategory(java.lang.String);
method public boolean isDefaultServiceForAid(android.content.ComponentName, java.lang.String);
method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
+ method public boolean registerAidGroupForService(android.content.ComponentName, android.nfc.cardemulation.AidGroup);
+ method public boolean removeAidGroupForService(android.content.ComponentName, java.lang.String);
field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
field public static final java.lang.String CATEGORY_OTHER = "other";
field public static final java.lang.String CATEGORY_PAYMENT = "payment";
@@ -19139,11 +19320,12 @@
field public static final int L = 10000; // 0x2710
}
- public final class Bundle implements java.lang.Cloneable android.os.Parcelable {
+ public final class Bundle extends android.os.CommonBundle {
ctor public Bundle();
ctor public Bundle(java.lang.ClassLoader);
ctor public Bundle(int);
ctor public Bundle(android.os.Bundle);
+ ctor public Bundle(android.os.PersistableBundle);
method public void clear();
method public java.lang.Object clone();
method public boolean containsKey(java.lang.String);
@@ -19181,6 +19363,7 @@
method public T getParcelable(java.lang.String);
method public android.os.Parcelable[] getParcelableArray(java.lang.String);
method public java.util.ArrayList<T> getParcelableArrayList(java.lang.String);
+ method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
method public java.io.Serializable getSerializable(java.lang.String);
method public short getShort(java.lang.String);
method public short getShort(java.lang.String, short);
@@ -19194,6 +19377,7 @@
method public boolean isEmpty();
method public java.util.Set<java.lang.String> keySet();
method public void putAll(android.os.Bundle);
+ method public void putAll(android.os.PersistableBundle);
method public void putBinder(java.lang.String, android.os.IBinder);
method public void putBoolean(java.lang.String, boolean);
method public void putBooleanArray(java.lang.String, boolean[]);
@@ -19217,6 +19401,7 @@
method public void putParcelable(java.lang.String, android.os.Parcelable);
method public void putParcelableArray(java.lang.String, android.os.Parcelable[]);
method public void putParcelableArrayList(java.lang.String, java.util.ArrayList<? extends android.os.Parcelable>);
+ method public void putPersistableBundle(java.lang.String, android.os.PersistableBundle);
method public void putSerializable(java.lang.String, java.io.Serializable);
method public void putShort(java.lang.String, short);
method public void putShortArray(java.lang.String, short[]);
@@ -19245,6 +19430,9 @@
method public abstract void onCancel();
}
+ abstract class CommonBundle implements java.lang.Cloneable android.os.Parcelable {
+ }
+
public class ConditionVariable {
ctor public ConditionVariable();
ctor public ConditionVariable(boolean);
@@ -19671,6 +19859,8 @@
method public final void readMap(java.util.Map, java.lang.ClassLoader);
method public final T readParcelable(java.lang.ClassLoader);
method public final android.os.Parcelable[] readParcelableArray(java.lang.ClassLoader);
+ method public final android.os.PersistableBundle readPersistableBundle();
+ method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader);
method public final java.io.Serializable readSerializable();
method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader);
method public final android.util.SparseBooleanArray readSparseBooleanArray();
@@ -19711,6 +19901,7 @@
method public final void writeNoException();
method public final void writeParcelable(android.os.Parcelable, int);
method public final void writeParcelableArray(T[], int);
+ method public final void writePersistableBundle(android.os.PersistableBundle);
method public final void writeSerializable(java.io.Serializable);
method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>);
method public final void writeSparseBooleanArray(android.util.SparseBooleanArray);
@@ -19821,6 +20012,51 @@
field public static final int PATTERN_SIMPLE_GLOB = 2; // 0x2
}
+ public final class PersistableBundle extends android.os.CommonBundle {
+ ctor public PersistableBundle();
+ ctor public PersistableBundle(java.lang.ClassLoader);
+ ctor public PersistableBundle(int);
+ ctor public PersistableBundle(android.os.PersistableBundle);
+ method public void clear();
+ method public java.lang.Object clone();
+ method public boolean containsKey(java.lang.String);
+ method public int describeContents();
+ method public java.lang.Object get(java.lang.String);
+ method public java.lang.ClassLoader getClassLoader();
+ method public double getDouble(java.lang.String);
+ method public double getDouble(java.lang.String, double);
+ method public double[] getDoubleArray(java.lang.String);
+ method public int getInt(java.lang.String);
+ method public int getInt(java.lang.String, int);
+ method public int[] getIntArray(java.lang.String);
+ method public long getLong(java.lang.String);
+ method public long getLong(java.lang.String, long);
+ method public long[] getLongArray(java.lang.String);
+ method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
+ method public java.lang.String getString(java.lang.String);
+ method public java.lang.String getString(java.lang.String, java.lang.String);
+ method public java.lang.String[] getStringArray(java.lang.String);
+ method public boolean isEmpty();
+ method public java.util.Set<java.lang.String> keySet();
+ method public void putAll(android.os.PersistableBundle);
+ method public void putDouble(java.lang.String, double);
+ method public void putDoubleArray(java.lang.String, double[]);
+ method public void putInt(java.lang.String, int);
+ method public void putIntArray(java.lang.String, int[]);
+ method public void putLong(java.lang.String, long);
+ method public void putLongArray(java.lang.String, long[]);
+ method public void putPersistableBundle(java.lang.String, android.os.PersistableBundle);
+ method public void putString(java.lang.String, java.lang.String);
+ method public void putStringArray(java.lang.String, java.lang.String[]);
+ method public void readFromParcel(android.os.Parcel);
+ method public void remove(java.lang.String);
+ method public void setClassLoader(java.lang.ClassLoader);
+ method public int size();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final android.os.PersistableBundle EMPTY;
+ }
+
public final class PowerManager {
method public void goToSleep(long);
method public boolean isInteractive();
@@ -22364,16 +22600,21 @@
public final class DocumentsContract {
method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String);
+ method public static android.net.Uri buildChildDocumentsViaUri(android.net.Uri, java.lang.String);
method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String);
+ method public static android.net.Uri buildDocumentViaUri(android.net.Uri, java.lang.String);
method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String);
method public static android.net.Uri buildRootsUri(java.lang.String);
method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
+ method public static android.net.Uri buildViaUri(java.lang.String, java.lang.String);
+ method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
method public static java.lang.String getDocumentId(android.net.Uri);
method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal);
method public static java.lang.String getRootId(android.net.Uri);
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
+ method public static java.lang.String getViaDocumentId(android.net.Uri);
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_INFO = "info";
@@ -22410,6 +22651,7 @@
field public static final java.lang.String COLUMN_TITLE = "title";
field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
+ field public static final int FLAG_SUPPORTS_DIR_SELECTION = 16; // 0x10
field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4
field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8
}
@@ -22422,6 +22664,9 @@
method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException;
method public final java.lang.String getType(android.net.Uri);
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+ method public boolean isChildDocument(java.lang.String, java.lang.String);
+ method public final android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+ method public final android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public abstract android.os.ParcelFileDescriptor openDocument(java.lang.String, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public android.content.res.AssetFileDescriptor openDocumentThumbnail(java.lang.String, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
@@ -22434,6 +22679,7 @@
method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException;
method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException;
+ method public final void revokeDocumentPermission(java.lang.String);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
}
@@ -24355,6 +24601,15 @@
method public void setRed(int, int);
}
+ public final class ScriptIntrinsicResize extends android.renderscript.ScriptIntrinsic {
+ method public static android.renderscript.ScriptIntrinsicResize create(android.renderscript.RenderScript);
+ method public void forEach_bicubic(android.renderscript.Allocation);
+ method public void forEach_bicubic(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions);
+ method public android.renderscript.Script.FieldID getFieldID_Input();
+ method public android.renderscript.Script.KernelID getKernelID_bicubic();
+ method public void setInput(android.renderscript.Allocation);
+ }
+
public final class ScriptIntrinsicYuvToRGB extends android.renderscript.ScriptIntrinsic {
method public static android.renderscript.ScriptIntrinsicYuvToRGB create(android.renderscript.RenderScript, android.renderscript.Element);
method public void forEach(android.renderscript.Allocation);
@@ -24659,6 +24914,36 @@
}
+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);
+ 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";
+ }
+
+ public abstract class VoiceInteractionSession {
+ ctor public VoiceInteractionSession(android.content.Context);
+ ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
+ method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
+ method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+ method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
+ method public abstract boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
+ }
+
+ public static class VoiceInteractionSession.Caller {
+ }
+
+ public static class VoiceInteractionSession.Request {
+ method public void sendCancelResult();
+ method public void sendCommandResult(android.os.Bundle);
+ method public void sendConfirmResult(boolean, android.os.Bundle);
+ }
+
+}
+
package android.service.wallpaper {
public abstract class WallpaperService extends android.app.Service {
@@ -25236,18 +25521,6 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
- public class DataConnectionRealTimeInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getDcPowerState();
- method public long getTime();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator CREATOR;
- field public static int DC_POWER_STATE_HIGH;
- field public static int DC_POWER_STATE_LOW;
- field public static int DC_POWER_STATE_MEDIUM;
- field public static int DC_POWER_STATE_UNKNOWN;
- }
-
public class NeighboringCellInfo implements android.os.Parcelable {
ctor public deprecated NeighboringCellInfo();
ctor public deprecated NeighboringCellInfo(int, int);
@@ -27850,7 +28123,6 @@
public static final class TvInputManager.Session {
method public void release();
- method public void setSurface(android.view.Surface);
method public void setVolume(float);
method public void tune(android.net.Uri);
}
@@ -27872,12 +28144,22 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.tv.TvInputService";
}
- public static abstract class TvInputService.TvInputSessionImpl {
+ public abstract class TvInputService.TvInputSessionImpl {
ctor public TvInputService.TvInputSessionImpl();
+ method public android.view.View onCreateOverlayView();
method public abstract void onRelease();
method public abstract boolean onSetSurface(android.view.Surface);
method public abstract void onSetVolume(float);
method public abstract boolean onTune(android.net.Uri);
+ method public void setOverlayViewEnabled(boolean);
+ }
+
+ public class TvView extends android.view.SurfaceView {
+ ctor public TvView(android.content.Context);
+ ctor public TvView(android.content.Context, android.util.AttributeSet);
+ ctor public TvView(android.content.Context, android.util.AttributeSet, int);
+ method public void bindTvInput(android.content.ComponentName, android.tv.TvInputManager.SessionCreateCallback);
+ method public void unbindTvInput();
}
}
@@ -29769,6 +30051,9 @@
method public boolean dispatchKeyEvent(android.view.KeyEvent);
method public boolean dispatchKeyEventPreIme(android.view.KeyEvent);
method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
+ method public boolean dispatchNestedFling(float, float);
+ method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
+ method public boolean dispatchNestedScroll(int, int, int, int, int[]);
method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
@@ -29918,6 +30203,7 @@
method public float getY();
method public boolean hasFocus();
method public boolean hasFocusable();
+ method public boolean hasNestedScrollingParent();
method public boolean hasOnClickListeners();
method public boolean hasOverlappingRendering();
method public boolean hasTransientState();
@@ -29953,6 +30239,7 @@
method public boolean isLayoutDirectionResolved();
method public boolean isLayoutRequested();
method public boolean isLongClickable();
+ method public boolean isNestedScrollingEnabled();
method public boolean isOpaque();
method protected boolean isPaddingOffsetRequired();
method public boolean isPaddingRelative();
@@ -30104,6 +30391,7 @@
method protected final void setMeasuredDimension(int, int);
method public void setMinimumHeight(int);
method public void setMinimumWidth(int);
+ method public void setNestedScrollingEnabled(boolean);
method public void setNextFocusDownId(int);
method public void setNextFocusForwardId(int);
method public void setNextFocusLeftId(int);
@@ -30168,6 +30456,8 @@
method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
method public void startAnimation(android.view.animation.Animation);
method public final boolean startDrag(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
+ method public boolean startNestedScroll(int);
+ method public void stopNestedScroll();
method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
method public void unscheduleDrawable(android.graphics.drawable.Drawable);
method protected boolean verifyDrawable(android.graphics.drawable.Drawable);
@@ -30256,6 +30546,9 @@
field public static final int SCROLLBAR_POSITION_DEFAULT = 0; // 0x0
field public static final int SCROLLBAR_POSITION_LEFT = 1; // 0x1
field public static final int SCROLLBAR_POSITION_RIGHT = 2; // 0x2
+ field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+ field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+ field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
field protected static final int[] SELECTED_STATE_SET;
field protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET;
field public static final int SOUND_EFFECTS_ENABLED = 134217728; // 0x8000000
@@ -30525,6 +30818,7 @@
method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener();
method public int getLayoutMode();
method public android.animation.LayoutTransition getLayoutTransition();
+ method public int getNestedScrollAxes();
method public int getPersistentDrawingCache();
method public int indexOfChild(android.view.View);
method public final void invalidateChild(android.view.View, android.graphics.Rect);
@@ -30545,8 +30839,14 @@
method public boolean onInterceptHoverEvent(android.view.MotionEvent);
method public boolean onInterceptTouchEvent(android.view.MotionEvent);
method protected abstract void onLayout(boolean, int, int, int, int);
+ method public boolean onNestedFling(android.view.View, float, float);
+ method public void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public void onNestedScroll(android.view.View, int, int, int, int);
+ method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
method protected boolean onRequestFocusInDescendants(int, android.graphics.Rect);
method public boolean onRequestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+ method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
+ method public void onStopNestedScroll(android.view.View);
method public void recomputeViewAttributes(android.view.View);
method public void removeAllViews();
method public void removeAllViewsInLayout();
@@ -30677,6 +30977,12 @@
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
+ method public abstract boolean onNestedFling(android.view.View, float, float);
+ method public abstract void onNestedPreScroll(android.view.View, int, int, int[]);
+ method public abstract void onNestedScroll(android.view.View, int, int, int, int);
+ method public abstract void onNestedScrollAccepted(android.view.View, android.view.View, int);
+ method public abstract boolean onStartNestedScroll(android.view.View, android.view.View, int);
+ method public abstract void onStopNestedScroll(android.view.View);
method public abstract void recomputeViewAttributes(android.view.View);
method public abstract void requestChildFocus(android.view.View, android.view.View);
method public abstract boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
@@ -32615,7 +32921,8 @@
method public void clearSslPreferences();
method public deprecated void clearView();
method public android.webkit.WebBackForwardList copyBackForwardList();
- method public android.print.PrintDocumentAdapter createPrintDocumentAdapter();
+ method public deprecated android.print.PrintDocumentAdapter createPrintDocumentAdapter();
+ method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(java.lang.String);
method public void destroy();
method public void documentHasImages(android.os.Message);
method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 92cb52c..6b55b7b 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -240,6 +240,7 @@
" (to embed a comma into a string escape it using \"\\,\")\n" +
" [-n <COMPONENT>] [-f <FLAGS>]\n" +
" [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
+ " [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" +
" [--debug-log-resolution] [--exclude-stopped-packages]\n" +
" [--include-stopped-packages]\n" +
" [--activity-brought-to-front] [--activity-clear-top]\n" +
@@ -455,6 +456,10 @@
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else if (opt.equals("--grant-write-uri-permission")) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ } else if (opt.equals("--grant-persistable-uri-permission")) {
+ intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+ } else if (opt.equals("--grant-prefix-uri-permission")) {
+ intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
} else if (opt.equals("--exclude-stopped-packages")) {
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
} else if (opt.equals("--include-stopped-packages")) {
@@ -744,6 +749,11 @@
"Error: Activity not started, you do not "
+ "have permission to access it.");
break;
+ case ActivityManager.START_NOT_VOICE_COMPATIBLE:
+ out.println(
+ "Error: Activity not started, voice control not allowed for: "
+ + intent);
+ break;
default:
out.println(
"Error: Activity not started, unknown error code " + res);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 859d83b..3481437 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -219,7 +219,7 @@
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
- LOG_ALWAYS_FATAL("app_process: Unable to deterimine ABI list from property %s.",
+ LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
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 @@
(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 a5a06e3..197eaf8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -22,6 +22,7 @@
import android.util.ArrayMap;
import android.util.SuperNotCalledException;
import android.widget.Toolbar;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.app.ToolbarActionBar;
import com.android.internal.policy.PolicyManager;
@@ -726,6 +727,8 @@
/*package*/ ActionBar mActionBar = null;
private boolean mEnableDefaultActionBarUp;
+ private VoiceInteractor mVoiceInteractor;
+
private CharSequence mTitle;
private int mTitleColor = 0;
@@ -1134,6 +1137,23 @@
}
/**
+ * Check whether this activity is running as part of a voice interaction with the user.
+ * If true, it should perform its interaction with the user through the
+ * {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
+ */
+ public boolean isVoiceInteraction() {
+ return mVoiceInteractor != null;
+ }
+
+ /**
+ * Retrieve the active {@link VoiceInteractor} that the user is going through to
+ * interact with this activity.
+ */
+ public VoiceInteractor getVoiceInteractor() {
+ return mVoiceInteractor;
+ }
+
+ /**
* This is called for activities that set launchMode to "singleTop" in
* their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}
* flag when calling {@link #startActivity}. In either case, when the
@@ -4314,11 +4334,10 @@
}
/**
- * Call this when your activity is done and should be closed. The
- * ActivityResult is propagated back to whoever launched you via
- * onActivityResult().
+ * Finishes the current activity and specifies whether to remove the task associated with this
+ * activity.
*/
- public void finish() {
+ private void finish(boolean finishTask) {
if (mParent == null) {
int resultCode;
Intent resultData;
@@ -4332,7 +4351,7 @@
resultData.prepareToLeaveProcess();
}
if (ActivityManagerNative.getDefault()
- .finishActivity(mToken, resultCode, resultData)) {
+ .finishActivity(mToken, resultCode, resultData, finishTask)) {
mFinished = true;
}
} catch (RemoteException e) {
@@ -4344,6 +4363,15 @@
}
/**
+ * Call this when your activity is done and should be closed. The
+ * ActivityResult is propagated back to whoever launched you via
+ * onActivityResult().
+ */
+ public void finish() {
+ finish(false);
+ }
+
+ /**
* Finish this activity as well as all activities immediately below it
* in the current task that have the same affinity. This is typically
* used when an application can be launched on to another task (such as
@@ -4442,6 +4470,14 @@
}
/**
+ * Call this when your activity is done and should be closed and the task should be completely
+ * removed as a part of finishing the Activity.
+ */
+ public void finishAndRemoveTask() {
+ finish(true);
+ }
+
+ /**
* Called when an activity you launched exits, giving you the requestCode
* you started it with, the resultCode it returned, and any additional
* data from it. The <var>resultCode</var> will be
@@ -5381,7 +5417,7 @@
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attach(context, aThread, instr, token, ident, application, intent, info, title, parent, id,
- lastNonConfigurationInstances, config, null);
+ lastNonConfigurationInstances, config, null, null);
}
final void attach(Context context, ActivityThread aThread,
@@ -5389,7 +5425,7 @@
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
- Configuration config, Bundle options) {
+ Configuration config, Bundle options, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
@@ -5417,6 +5453,8 @@
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
+ mVoiceInteractor = voiceInteractor != null
+ ? new VoiceInteractor(this, voiceInteractor, Looper.myLooper()) : null;
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c027e99..018e949 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -76,6 +76,13 @@
public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
/**
+ * Result for IActivityManager.startActivity: trying to start an activity under voice
+ * control when that activity does not support the VOICE category.
+ * @hide
+ */
+ public static final int START_NOT_VOICE_COMPATIBLE = -7;
+
+ /**
* Result for IActivityManager.startActivity: an error where the
* start had to be canceled.
* @hide
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 44c74d8..b1c37de 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -43,9 +43,11 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
+import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
import android.util.Log;
import android.util.Singleton;
+import com.android.internal.app.IVoiceInteractor;
import java.util.ArrayList;
import java.util.List;
@@ -242,6 +244,33 @@
return true;
}
+ case START_VOICE_ACTIVITY_TRANSACTION:
+ {
+ data.enforceInterface(IActivityManager.descriptor);
+ String callingPackage = data.readString();
+ int callingPid = data.readInt();
+ int callingUid = data.readInt();
+ Intent intent = Intent.CREATOR.createFromParcel(data);
+ String resolvedType = data.readString();
+ IVoiceInteractionSession session = IVoiceInteractionSession.Stub.asInterface(
+ data.readStrongBinder());
+ IVoiceInteractor interactor = IVoiceInteractor.Stub.asInterface(
+ data.readStrongBinder());
+ int startFlags = data.readInt();
+ String profileFile = data.readString();
+ ParcelFileDescriptor profileFd = data.readInt() != 0
+ ? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
+ Bundle options = data.readInt() != 0
+ ? Bundle.CREATOR.createFromParcel(data) : null;
+ int userId = data.readInt();
+ int result = startVoiceActivity(callingPackage, callingPid, callingUid,
+ intent, resolvedType, session, interactor, startFlags,
+ profileFile, profileFd, options, userId);
+ reply.writeNoException();
+ reply.writeInt(result);
+ return true;
+ }
+
case START_NEXT_MATCHING_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
@@ -263,7 +292,8 @@
if (data.readInt() != 0) {
resultData = Intent.CREATOR.createFromParcel(data);
}
- boolean res = finishActivity(token, resultCode, resultData);
+ boolean finishTask = (data.readInt() != 0);
+ boolean res = finishActivity(token, resultCode, resultData, finishTask);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
@@ -2322,6 +2352,42 @@
data.recycle();
return result;
}
+ public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
+ Intent intent, String resolvedType, IVoiceInteractionSession session,
+ IVoiceInteractor interactor, int startFlags, String profileFile,
+ ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeString(callingPackage);
+ data.writeInt(callingPid);
+ data.writeInt(callingUid);
+ intent.writeToParcel(data, 0);
+ data.writeString(resolvedType);
+ data.writeStrongBinder(session.asBinder());
+ data.writeStrongBinder(interactor.asBinder());
+ data.writeInt(startFlags);
+ data.writeString(profileFile);
+ if (profileFd != null) {
+ data.writeInt(1);
+ profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ data.writeInt(0);
+ }
+ if (options != null) {
+ data.writeInt(1);
+ options.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ data.writeInt(userId);
+ mRemote.transact(START_VOICE_ACTIVITY_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int result = reply.readInt();
+ reply.recycle();
+ data.recycle();
+ return result;
+ }
public boolean startNextMatchingActivity(IBinder callingActivity,
Intent intent, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -2342,7 +2408,7 @@
data.recycle();
return result != 0;
}
- public boolean finishActivity(IBinder token, int resultCode, Intent resultData)
+ public boolean finishActivity(IBinder token, int resultCode, Intent resultData, boolean finishTask)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2355,6 +2421,7 @@
} else {
data.writeInt(0);
}
+ data.writeInt(finishTask ? 1 : 0);
mRemote.transact(FINISH_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 965f815..7dc21b4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -94,6 +94,7 @@
import android.renderscript.RenderScript;
import android.security.AndroidKeyStoreProvider;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
@@ -265,6 +266,7 @@
IBinder token;
int ident;
Intent intent;
+ IVoiceInteractor voiceInteractor;
Bundle state;
Activity activity;
Window window;
@@ -603,6 +605,7 @@
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
+ IVoiceInteractor voiceInteractor,
int procState, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
@@ -615,6 +618,7 @@
r.token = token;
r.ident = ident;
r.intent = intent;
+ r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
@@ -2197,7 +2201,8 @@
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
- r.embeddedID, r.lastNonConfigurationInstances, config, options);
+ r.embeddedID, r.lastNonConfigurationInstances, config, options,
+ r.voiceInteractor);
if (customIntent != null) {
activity.mIntent = customIntent;
@@ -2363,7 +2368,7 @@
// manager to stop us.
try {
ActivityManagerNative.getDefault()
- .finishActivity(r.token, Activity.RESULT_CANCELED, null);
+ .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
// Ignore
}
@@ -2984,7 +2989,7 @@
// just end this activity.
try {
ActivityManagerNative.getDefault()
- .finishActivity(token, Activity.RESULT_CANCELED, null);
+ .finishActivity(token, Activity.RESULT_CANCELED, null, false);
} catch (RemoteException ex) {
}
}
@@ -3003,7 +3008,9 @@
int h;
if (w < 0) {
Resources res = r.activity.getResources();
- if (SystemProperties.getBoolean("persist.recents.use_alternate", false)) {
+ Configuration config = res.getConfiguration();
+ boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
+ if (useAlternateRecents) {
int wId = com.android.internal.R.dimen.recents_thumbnail_width;
int hId = com.android.internal.R.dimen.recents_thumbnail_height;
mThumbnailWidth = w = res.getDimensionPixelSize(wId);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 51cb12a..a810134 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -33,17 +33,20 @@
import android.view.Surface;
import android.view.TextureView;
import android.view.TextureView.SurfaceTextureListener;
-import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import dalvik.system.CloseGuard;
+
+import java.lang.ref.WeakReference;
/** @hide */
public class ActivityView extends ViewGroup {
- private final String TAG = "ActivityView";
- private final boolean DEBUG = false;
+ private static final String TAG = "ActivityView";
+ private static final boolean DEBUG = false;
+ DisplayMetrics mMetrics;
private final TextureView mTextureView;
- private IActivityContainer mActivityContainer;
+ private ActivityContainerWrapper mActivityContainer;
private Activity mActivity;
private int mWidth;
private int mHeight;
@@ -75,9 +78,23 @@
throw new IllegalStateException("The ActivityView's Context is not an Activity.");
}
+ try {
+ mActivityContainer = new ActivityContainerWrapper(
+ ActivityManagerNative.getDefault().createActivityContainer(
+ mActivity.getActivityToken(), new ActivityContainerCallback(this)));
+ } catch (RemoteException e) {
+ throw new RuntimeException("ActivityView: Unable to create ActivityContainer. "
+ + e);
+ }
+
mTextureView = new TextureView(context);
mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
addView(mTextureView);
+
+ WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
+ mMetrics = new DisplayMetrics();
+ wm.getDefaultDisplay().getMetrics(mMetrics);
+
if (DEBUG) Log.v(TAG, "ctor()");
}
@@ -86,57 +103,8 @@
mTextureView.layout(0, 0, r - l, b - t);
}
- @Override
- protected void onAttachedToWindow() {
- if (DEBUG) Log.v(TAG, "onAttachedToWindow()");
- super.onAttachedToWindow();
- try {
- final IBinder token = mActivity.getActivityToken();
- mActivityContainer = ActivityManagerNative.getDefault().createActivityContainer(token,
- new ActivityContainerCallback());
- } catch (RemoteException e) {
- throw new IllegalStateException("ActivityView: Unable to create ActivityContainer. "
- + e);
- }
-
- attachToSurfaceWhenReady();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer);
- super.onDetachedFromWindow();
- if (mActivityContainer != null) {
- detach();
- try {
- ActivityManagerNative.getDefault().deleteActivityContainer(mActivityContainer);
- } catch (RemoteException e) {
- }
- mActivityContainer = null;
- }
- }
-
- @Override
- protected void onWindowVisibilityChanged(int visibility) {
- if (DEBUG) Log.v(TAG, "onWindowVisibilityChanged(): visibility=" + visibility);
- super.onWindowVisibilityChanged(visibility);
- switch (visibility) {
- case View.VISIBLE:
- attachToSurfaceWhenReady();
- break;
- case View.INVISIBLE:
- break;
- case View.GONE:
- break;
- }
- }
-
private boolean injectInputEvent(InputEvent event) {
- try {
- return mActivityContainer != null && mActivityContainer.injectEvent(event);
- } catch (RemoteException e) {
- return false;
- }
+ return mActivityContainer != null && mActivityContainer.injectEvent(event);
}
@Override
@@ -154,125 +122,151 @@
return super.onGenericMotionEvent(event);
}
+ @Override
+ public void onAttachedToWindow() {
+ if (DEBUG) Log.v(TAG, "onAttachedToWindow(): mActivityContainer=" + mActivityContainer +
+ " mSurface=" + mSurface);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer +
+ " mSurface=" + mSurface);
+ }
+
public boolean isAttachedToDisplay() {
return mSurface != null;
}
public void startActivity(Intent intent) {
+ if (mActivityContainer == null) {
+ throw new IllegalStateException("Attempt to call startActivity after release");
+ }
if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " +
(isAttachedToDisplay() ? "" : "not") + " attached");
if (mSurface != null) {
- try {
- mActivityContainer.startActivity(intent);
- } catch (RemoteException e) {
- throw new IllegalStateException("ActivityView: Unable to startActivity. " + e);
- }
+ mActivityContainer.startActivity(intent);
} else {
+ mActivityContainer.checkEmbeddedAllowed(intent);
mQueuedIntent = intent;
mQueuedPendingIntent = null;
}
}
- private void startActivityIntentSender(IIntentSender iIntentSender) {
- try {
- mActivityContainer.startActivityIntentSender(iIntentSender);
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "ActivityView: Unable to startActivity from IntentSender. " + e);
- }
- }
-
public void startActivity(IntentSender intentSender) {
+ if (mActivityContainer == null) {
+ throw new IllegalStateException("Attempt to call startActivity after release");
+ }
if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " +
(isAttachedToDisplay() ? "" : "not") + " attached");
final IIntentSender iIntentSender = intentSender.getTarget();
if (mSurface != null) {
- startActivityIntentSender(iIntentSender);
+ mActivityContainer.startActivityIntentSender(iIntentSender);
} else {
+ mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
mQueuedPendingIntent = iIntentSender;
mQueuedIntent = null;
}
}
public void startActivity(PendingIntent pendingIntent) {
+ if (mActivityContainer == null) {
+ throw new IllegalStateException("Attempt to call startActivity after release");
+ }
if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " "
+ (isAttachedToDisplay() ? "" : "not") + " attached");
final IIntentSender iIntentSender = pendingIntent.getTarget();
if (mSurface != null) {
- startActivityIntentSender(iIntentSender);
+ mActivityContainer.startActivityIntentSender(iIntentSender);
} else {
+ mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
mQueuedPendingIntent = iIntentSender;
mQueuedIntent = null;
}
}
+ public void release() {
+ if (DEBUG) Log.v(TAG, "release() mActivityContainer=" + mActivityContainer +
+ " mSurface=" + mSurface);
+ if (mActivityContainer == null) {
+ Log.e(TAG, "Duplicate call to release");
+ return;
+ }
+ mActivityContainer.release();
+ mActivityContainer = null;
+
+ if (mSurface != null) {
+ mSurface.release();
+ mSurface = null;
+ }
+
+ mTextureView.setSurfaceTextureListener(null);
+ }
+
private void attachToSurfaceWhenReady() {
final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
- if (mActivityContainer == null || surfaceTexture == null || mSurface != null) {
+ if (surfaceTexture == null || mSurface != null) {
// Either not ready to attach, or already attached.
return;
}
- WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
- DisplayMetrics metrics = new DisplayMetrics();
- wm.getDefaultDisplay().getMetrics(metrics);
-
mSurface = new Surface(surfaceTexture);
try {
- mActivityContainer.attachToSurface(mSurface, mWidth, mHeight, metrics.densityDpi);
+ mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
} catch (RemoteException e) {
mSurface.release();
mSurface = null;
- throw new IllegalStateException(
- "ActivityView: Unable to create ActivityContainer. " + e);
+ throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e);
}
if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null ||
mQueuedPendingIntent != null ? "" : "no") + " queued intent");
if (mQueuedIntent != null) {
- startActivity(mQueuedIntent);
+ mActivityContainer.startActivity(mQueuedIntent);
mQueuedIntent = null;
} else if (mQueuedPendingIntent != null) {
- startActivityIntentSender(mQueuedPendingIntent);
+ mActivityContainer.startActivityIntentSender(mQueuedPendingIntent);
mQueuedPendingIntent = null;
}
}
- private void detach() {
- if (DEBUG) Log.d(TAG, "detach: attached=" + isAttachedToDisplay());
- if (mSurface != null) {
- try {
- mActivityContainer.detachFromDisplay();
- } catch (RemoteException e) {
- }
- mSurface.release();
- mSurface = null;
- }
- }
-
private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
int height) {
+ if (mActivityContainer == null) {
+ return;
+ }
if (DEBUG) Log.d(TAG, "onSurfaceTextureAvailable: width=" + width + " height="
+ height);
mWidth = width;
mHeight = height;
- if (mActivityContainer != null) {
- attachToSurfaceWhenReady();
- }
+ attachToSurfaceWhenReady();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
int height) {
+ if (mActivityContainer == null) {
+ return;
+ }
if (DEBUG) Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+ if (mActivityContainer == null) {
+ return true;
+ }
if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed");
- detach();
+ mSurface.release();
+ mSurface = null;
+ try {
+ mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to set surface of ActivityContainer. " + e);
+ }
return true;
}
@@ -283,13 +277,113 @@
}
- private class ActivityContainerCallback extends IActivityContainerCallback.Stub {
+ private static class ActivityContainerCallback extends IActivityContainerCallback.Stub {
+ private final WeakReference<ActivityView> mActivityViewWeakReference;
+
+ ActivityContainerCallback(ActivityView activityView) {
+ mActivityViewWeakReference = new WeakReference<ActivityView>(activityView);
+ }
+
@Override
public void setVisible(IBinder container, boolean visible) {
- if (DEBUG) Log.v(TAG, "setVisible(): container=" + container + " visible=" + visible);
- if (visible) {
- } else {
+ if (DEBUG) Log.v(TAG, "setVisible(): container=" + container + " visible=" + visible +
+ " ActivityView=" + mActivityViewWeakReference.get());
+ }
+ }
+
+ private static class ActivityContainerWrapper {
+ private final IActivityContainer mIActivityContainer;
+ private final CloseGuard mGuard = CloseGuard.get();
+
+ ActivityContainerWrapper(IActivityContainer container) {
+ mIActivityContainer = container;
+ mGuard.open("release");
+ }
+
+ void attachToDisplay(int displayId) {
+ try {
+ mIActivityContainer.attachToDisplay(displayId);
+ } catch (RemoteException e) {
}
}
+
+ void setSurface(Surface surface, int width, int height, int density)
+ throws RemoteException {
+ mIActivityContainer.setSurface(surface, width, height, density);
+ }
+
+ int startActivity(Intent intent) {
+ try {
+ return mIActivityContainer.startActivity(intent);
+ } catch (RemoteException e) {
+ throw new RuntimeException("ActivityView: Unable to startActivity. " + e);
+ }
+ }
+
+ int startActivityIntentSender(IIntentSender intentSender) {
+ try {
+ return mIActivityContainer.startActivityIntentSender(intentSender);
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to startActivity from IntentSender. " + e);
+ }
+ }
+
+ void checkEmbeddedAllowed(Intent intent) {
+ try {
+ mIActivityContainer.checkEmbeddedAllowed(intent);
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to startActivity from Intent. " + e);
+ }
+ }
+
+ void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
+ try {
+ mIActivityContainer.checkEmbeddedAllowedIntentSender(intentSender);
+ } catch (RemoteException e) {
+ throw new RuntimeException(
+ "ActivityView: Unable to startActivity from IntentSender. " + e);
+ }
+ }
+
+ int getDisplayId() {
+ try {
+ return mIActivityContainer.getDisplayId();
+ } catch (RemoteException e) {
+ return -1;
+ }
+ }
+
+ boolean injectEvent(InputEvent event) {
+ try {
+ return mIActivityContainer.injectEvent(event);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ void release() {
+ if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
+ try {
+ mIActivityContainer.release();
+ mGuard.close();
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: finalize called");
+ try {
+ if (mGuard != null) {
+ mGuard.warnIfOpen();
+ release();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index f1c632e..fcc7f8e 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -33,6 +33,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
+import com.android.internal.app.IVoiceInteractor;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -136,6 +137,8 @@
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
+ IVoiceInteractor voiceInteractor = IVoiceInteractor.Stub.asInterface(
+ data.readStrongBinder());
int procState = data.readInt();
Bundle state = data.readBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
@@ -147,7 +150,8 @@
? ParcelFileDescriptor.CREATOR.createFromParcel(data) : null;
boolean autoStopProfiler = data.readInt() != 0;
Bundle resumeArgs = data.readBundle();
- scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, procState, state,
+ scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo,
+ voiceInteractor, procState, state,
ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler,
resumeArgs);
return true;
@@ -735,6 +739,7 @@
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
+ IVoiceInteractor voiceInteractor,
int procState, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
@@ -748,6 +753,7 @@
info.writeToParcel(data, 0);
curConfig.writeToParcel(data, 0);
compatInfo.writeToParcel(data, 0);
+ data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
data.writeInt(procState);
data.writeBundle(state);
data.writeTypedList(pendingResults);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 77b5485..fe532bf 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -67,7 +67,7 @@
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaRouter;
-import android.media.session.MediaSessionManager;
+import android.media.session.SessionManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.INetworkPolicyManager;
@@ -639,7 +639,7 @@
registerService(MEDIA_SESSION_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
- return new MediaSessionManager(ctx);
+ return new SessionManager(ctx);
}
});
registerService(TRUST_SERVICE, new ServiceFetcher() {
@@ -1865,17 +1865,26 @@
}
private String uriModeFlagToString(int uriModeFlags) {
- switch (uriModeFlags) {
- case Intent.FLAG_GRANT_READ_URI_PERMISSION |
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
- return "read and write";
- case Intent.FLAG_GRANT_READ_URI_PERMISSION:
- return "read";
- case Intent.FLAG_GRANT_WRITE_URI_PERMISSION:
- return "write";
+ StringBuilder builder = new StringBuilder();
+ if ((uriModeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ builder.append("read and ");
}
- throw new IllegalArgumentException(
- "Unknown permission mode flags: " + uriModeFlags);
+ if ((uriModeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ builder.append("write and ");
+ }
+ if ((uriModeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0) {
+ builder.append("persistable and ");
+ }
+ if ((uriModeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0) {
+ builder.append("prefix and ");
+ }
+
+ if (builder.length() > 5) {
+ builder.setLength(builder.length() - 5);
+ return builder.toString();
+ } else {
+ throw new IllegalArgumentException("Unknown permission mode flags: " + uriModeFlags);
+ }
}
private void enforceForUri(
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
index 5b80e06..52884f7 100644
--- a/core/java/android/app/IActivityContainer.aidl
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -26,10 +26,12 @@
/** @hide */
interface IActivityContainer {
void attachToDisplay(int displayId);
- void attachToSurface(in Surface surface, int width, int height, int density);
- void detachFromDisplay();
+ void setSurface(in Surface surface, int width, int height, int density);
int startActivity(in Intent intent);
int startActivityIntentSender(in IIntentSender intentSender);
+ void checkEmbeddedAllowed(in Intent intent);
+ void checkEmbeddedAllowedIntentSender(in IIntentSender intentSender);
int getDisplayId();
boolean injectEvent(in InputEvent event);
+ void release();
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index bfbd339..6b94c4e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -47,6 +47,8 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.service.voice.IVoiceInteractionSession;
+import com.android.internal.app.IVoiceInteractor;
import java.util.List;
@@ -77,9 +79,13 @@
IntentSender intent, Intent fillInIntent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues, Bundle options) throws RemoteException;
+ public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
+ Intent intent, String resolvedType, IVoiceInteractionSession session,
+ IVoiceInteractor interactor, int flags, String profileFile,
+ ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
public boolean startNextMatchingActivity(IBinder callingActivity,
Intent intent, Bundle options) throws RemoteException;
- public boolean finishActivity(IBinder token, int code, Intent data)
+ public boolean finishActivity(IBinder token, int code, Intent data, boolean finishTask)
throws RemoteException;
public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException;
public boolean finishActivityAffinity(IBinder token) throws RemoteException;
@@ -733,4 +739,5 @@
int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
int SET_ACTIVITY_LABEL_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
+ int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index ac8ac8f..f290e94 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -31,6 +31,8 @@
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
+import android.service.voice.IVoiceInteractionSession;
+import com.android.internal.app.IVoiceInteractor;
import java.io.FileDescriptor;
import java.util.List;
@@ -55,8 +57,9 @@
void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- int procState, Bundle state, List<ResultInfo> pendingResults,
- List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+ IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed,
+ boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle resumeArgs)
throws RemoteException;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index bb6eeda..ad4027d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -18,11 +18,16 @@
package android.app;
import android.app.ITransientNotification;
-import android.service.notification.StatusBarNotification;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Intent;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
+import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenModeConfig;
/** {@hide} */
interface INotificationManager
@@ -49,4 +54,10 @@
StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
String[] getActiveNotificationKeysFromListener(in INotificationListener token);
+
+ ZenModeConfig getZenModeConfig();
+ boolean setZenModeConfig(in ZenModeConfig config);
+ oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
+ oneway void requestZenModeConditions(in IConditionListener callback, boolean requested);
+ oneway void setZenModeCondition(in Uri conditionId);
}
\ No newline at end of file
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 028fa68..e58ccb8 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1428,7 +1428,7 @@
}
/**
- * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
+ * Like {@link #execStartActivity},
* but accepts an array of activities to be started. Note that active
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
@@ -1442,7 +1442,7 @@
}
/**
- * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
+ * Like {@link #execStartActivity},
* but accepts an array of activities to be started. Note that active
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
@@ -1545,8 +1545,7 @@
}
/**
- * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
- * but for starting as a particular user.
+ * Like {@link #execStartActivity}, but for starting as a particular user.
*
* @param who The Context from which the activity is being started.
* @param contextThread The main thread of the Context from which the activity
@@ -1616,7 +1615,8 @@
mUiAutomationConnection = uiAutomationConnection;
}
- /*package*/ static void checkStartActivityResult(int res, Object intent) {
+ /** @hide */
+ public static void checkStartActivityResult(int res, Object intent) {
if (res >= ActivityManager.START_SUCCESS) {
return;
}
@@ -1640,6 +1640,9 @@
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException(
"PendingIntent is not an activity");
+ case ActivityManager.START_NOT_VOICE_COMPATIBLE:
+ throw new SecurityException(
+ "Starting under voice control not allowed for: " + intent);
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index a6a04d1..5cf61a8 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -41,8 +41,6 @@
@Deprecated
public static final int DISABLE_NOTIFICATION_TICKER
= View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER;
- public static final int DISABLE_PRIVATE_NOTIFICATIONS
- = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER;
public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO;
public static final int DISABLE_HOME = View.STATUS_BAR_DISABLE_HOME;
public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT;
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
new file mode 100644
index 0000000..6820dfd
--- /dev/null
+++ b/core/java/android/app/VoiceInteractor.java
@@ -0,0 +1,235 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.IVoiceInteractorCallback;
+import com.android.internal.app.IVoiceInteractorRequest;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+
+import java.util.WeakHashMap;
+
+/**
+ * Interface for an {@link Activity} to interact with the user through voice.
+ */
+public class VoiceInteractor {
+ static final String TAG = "VoiceInteractor";
+ static final boolean DEBUG = true;
+
+ final Context mContext;
+ final IVoiceInteractor mInteractor;
+ final 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_CONFIRMATION_RESULT:
+ 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);
+ break;
+ case MSG_COMMAND_RESULT:
+ if (DEBUG) Log.d(TAG, "onCommandResult: req="
+ + ((IVoiceInteractorRequest)args.arg2).asBinder()
+ + " result=" + args.arg2);
+ ((Callback)args.arg1).onCommandResult(
+ findRequest((IVoiceInteractorRequest) args.arg2),
+ (Bundle) args.arg3);
+ break;
+ case MSG_CANCEL_RESULT:
+ if (DEBUG) Log.d(TAG, "onCancelResult: req="
+ + ((IVoiceInteractorRequest)args.arg2).asBinder());
+ ((Callback)args.arg1).onCancel(
+ findRequest((IVoiceInteractorRequest) args.arg2));
+ break;
+ }
+ }
+ };
+
+ final WeakHashMap<IBinder, Request> mActiveRequests = new WeakHashMap<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;
+
+ Request(IVoiceInteractorRequest requestInterface) {
+ mRequestInterface = requestInterface;
+ }
+
+ public void cancel() {
+ try {
+ mRequestInterface.cancel();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Voice interactor has died", e);
+ }
+ }
+ }
+
+ public static class Callback {
+ VoiceInteractor mInteractor;
+
+ 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));
+ }
+
+ @Override
+ public void deliverCommandResult(IVoiceInteractorRequest request, Bundle result) {
+ mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageOOO(
+ MSG_COMMAND_RESULT, Callback.this, request, result));
+ }
+
+ @Override
+ public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException {
+ mInteractor.mHandlerCaller.sendMessage(mInteractor.mHandlerCaller.obtainMessageOO(
+ MSG_CANCEL_RESULT, Callback.this, request));
+ }
+ };
+
+ public void onConfirmationResult(Request request, boolean confirmed, Bundle result) {
+ }
+
+ public void onCommandResult(Request request, Bundle result) {
+ }
+
+ public void onCancel(Request request) {
+ }
+ }
+
+ VoiceInteractor(Context context, IVoiceInteractor interactor, Looper looper) {
+ mContext = context;
+ 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) {
+ synchronized (mActiveRequests) {
+ Request req = mActiveRequests.get(request.asBinder());
+ if (req == null) {
+ throw new IllegalStateException("Received callback without active request: "
+ + request);
+ }
+ 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) {
+ 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;
+ } catch (RemoteException e) {
+ throw new RuntimeException("Voice interactor has died", e);
+ }
+ }
+
+ /**
+ * Queries the supported commands available from the VoiceinteractionService.
+ * The command is a string that describes the generic operation to be performed.
+ * 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 commands
+ */
+ public boolean[] supportsCommands(String[] commands) {
+ try {
+ boolean[] res = mInteractor.supportsCommands(mContext.getOpPackageName(), commands);
+ if (DEBUG) Log.d(TAG, "supportsCommands: cmds=" + commands + " res=" + res);
+ return res;
+ } catch (RemoteException e) {
+ throw new RuntimeException("Voice interactor has died", e);
+ }
+ }
+}
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.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 @@
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 @@
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 @@
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 @@
}
}
- is = new BufferedInputStream(resources.openRawResource(
- com.android.internal.R.drawable.default_wallpaper));
+ is = new BufferedInputStream(openDefaultWallpaper(mContext));
RectF cropRectF;
@@ -479,8 +486,7 @@
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 @@
* 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/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index db08a41..68ab611 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -33,6 +33,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.service.trust.TrustAgentService;
import android.util.Log;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -1267,7 +1268,7 @@
public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0;
/**
- * Disable all keyguard widgets
+ * Disable all keyguard widgets. Has no effect.
*/
public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1 << 0;
@@ -1277,6 +1278,22 @@
public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 1 << 1;
/**
+ * Disable showing all notifications on secure keyguard screens (e.g. PIN/Pattern/Password)
+ */
+ public static final int KEYGUARD_DISABLE_SECURE_NOTIFICATIONS = 1 << 2;
+
+ /**
+ * Only allow redacted notifications on secure keyguard screens (e.g. PIN/Pattern/Password)
+ */
+ public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 1 << 3;
+
+ /**
+ * Ignore {@link TrustAgentService} state on secure keyguard screens
+ * (e.g. PIN/Pattern/Password).
+ */
+ public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 1 << 4;
+
+ /**
* Disable all current and future keyguard customizations.
*/
public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff;
@@ -1496,7 +1513,8 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param which {@link #KEYGUARD_DISABLE_FEATURES_NONE} (default),
* {@link #KEYGUARD_DISABLE_WIDGETS_ALL}, {@link #KEYGUARD_DISABLE_SECURE_CAMERA},
- * {@link #KEYGUARD_DISABLE_FEATURES_ALL}
+ * {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_TRUST_AGENTS},
+ * {@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS}, {@link #KEYGUARD_DISABLE_FEATURES_ALL}
*/
public void setKeyguardDisabledFeatures(ComponentName admin, int which) {
if (mService != null) {
@@ -1816,6 +1834,27 @@
/**
* @hide
+ * @param userId the userId of a managed profile profile.
+ *
+ * @return whether or not the managed profile is enabled.
+ * @throws IllegalArgumentException if the userId is invalid.
+ */
+ public boolean isProfileEnabled(int userId) throws IllegalArgumentException {
+ if (mService != null) {
+ try {
+ return mService.isProfileEnabled(userId);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed to get status for owner profile.");
+ throw new IllegalArgumentException(
+ "Failed to get status for owner profile.", re);
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * @hide
* @return the human readable name of the organisation associated with this DPM or null if
* one is not set.
* @throws IllegalArgumentException if the userId is invalid.
@@ -1936,4 +1975,48 @@
}
return null;
}
+
+ /**
+ * Called by a profile or device owner to set a user restriction specified
+ * by the key.
+ * <p>
+ * The calling device admin must be a profile or device owner; if it is not,
+ * a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param key The key of the restriction. See the constants in
+ * {@link android.os.UserManager} for the list of keys.
+ */
+ public void addUserRestriction(ComponentName admin, String key) {
+ if (mService != null) {
+ try {
+ mService.setUserRestriction(admin, key, true);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Called by a profile or device owner to clear a user restriction specified
+ * by the key.
+ * <p>
+ * The calling device admin must be a profile or device owner; if it is not,
+ * a security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param key The key of the restriction. See the constants in
+ * {@link android.os.UserManager} for the list of keys.
+ */
+ public void clearUserRestriction(ComponentName admin, String key) {
+ if (mService != null) {
+ try {
+ mService.setUserRestriction(admin, key, false);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 4ed85e9..72b3c20 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -109,6 +109,7 @@
String getProfileOwner(int userHandle);
String getProfileOwnerName(int userHandle);
void setProfileEnabled(in ComponentName who);
+ boolean isProfileEnabled(int userHandle);
boolean installCaCert(in byte[] certBuffer);
void uninstallCaCert(in byte[] certBuffer);
@@ -118,4 +119,6 @@
void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings);
Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
+
+ void setUserRestriction(in ComponentName who, in String key, boolean enable);
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f3c803d..5b41394 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1641,7 +1641,7 @@
*
* @see #getPersistedUriPermissions()
*/
- public void takePersistableUriPermission(Uri uri, int modeFlags) {
+ public void takePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
try {
ActivityManagerNative.getDefault().takePersistableUriPermission(uri, modeFlags);
} catch (RemoteException e) {
@@ -1656,7 +1656,7 @@
*
* @see #getPersistedUriPermissions()
*/
- public void releasePersistableUriPermission(Uri uri, int modeFlags) {
+ public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
try {
ActivityManagerNative.getDefault().releasePersistableUriPermission(uri, modeFlags);
} catch (RemoteException e) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ff92d82..de223a3 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2387,10 +2387,10 @@
/**
* Use with {@link #getSystemService} to retrieve a
- * {@link android.media.session.MediaSessionManager} for managing media Sessions.
+ * {@link android.media.session.SessionManager} for managing media Sessions.
*
* @see #getSystemService
- * @see android.media.session.MediaSessionManager
+ * @see android.media.session.SessionManager
*/
public static final String MEDIA_SESSION_SERVICE = "media_session";
@@ -2442,6 +2442,14 @@
public static final String APPWIDGET_SERVICE = "appwidget";
/**
+ * Official published name of the (internal) voice interaction manager service.
+ *
+ * @hide
+ * @see #getSystemService
+ */
+ public static final String VOICE_INTERACTION_MANAGER_SERVICE = "voiceinteraction";
+
+ /**
* Use with {@link #getSystemService} to retrieve an
* {@link android.app.backup.IBackupManager IBackupManager} for communicating
* with the backup mechanism.
@@ -2791,9 +2799,13 @@
* @param uri The Uri you would like to grant access to.
* @param modeFlags The desired access modes. Any combination of
* {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
- * Intent.FLAG_GRANT_READ_URI_PERMISSION} or
+ * Intent.FLAG_GRANT_READ_URI_PERMISSION},
* {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
- * Intent.FLAG_GRANT_WRITE_URI_PERMISSION}.
+ * Intent.FLAG_GRANT_WRITE_URI_PERMISSION},
+ * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ * Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION}, or
+ * {@link Intent#FLAG_GRANT_PREFIX_URI_PERMISSION
+ * Intent.FLAG_GRANT_PREFIX_URI_PERMISSION}.
*
* @see #revokeUriPermission
*/
@@ -2806,7 +2818,8 @@
* Uri will match all previously granted Uris that are the same or a
* sub-path of the given Uri. That is, revoking "content://foo/target" will
* revoke both "content://foo/target" and "content://foo/target/sub", but not
- * "content://foo".
+ * "content://foo". It will not remove any prefix grants that exist at a
+ * higher level.
*
* @param uri The Uri you would like to revoke access to.
* @param modeFlags The desired access modes. Any combination of
@@ -2817,7 +2830,7 @@
*
* @see #grantUriPermission
*/
- public abstract void revokeUriPermission(Uri uri, @Intent.GrantUriMode int modeFlags);
+ public abstract void revokeUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags);
/**
* Determine whether a particular process and user ID has been granted
@@ -2841,7 +2854,7 @@
* @see #checkCallingUriPermission
*/
public abstract int checkUriPermission(Uri uri, int pid, int uid,
- @Intent.GrantUriMode int modeFlags);
+ @Intent.AccessUriMode int modeFlags);
/**
* Determine whether the calling process and user ID has been
@@ -2864,7 +2877,7 @@
*
* @see #checkUriPermission(Uri, int, int, int)
*/
- public abstract int checkCallingUriPermission(Uri uri, @Intent.GrantUriMode int modeFlags);
+ public abstract int checkCallingUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags);
/**
* Determine whether the calling process of an IPC <em>or you</em> has been granted
@@ -2884,7 +2897,7 @@
* @see #checkCallingUriPermission
*/
public abstract int checkCallingOrSelfUriPermission(Uri uri,
- @Intent.GrantUriMode int modeFlags);
+ @Intent.AccessUriMode int modeFlags);
/**
* Check both a Uri and normal permission. This allows you to perform
@@ -2910,7 +2923,7 @@
*/
public abstract int checkUriPermission(@Nullable Uri uri, @Nullable String readPermission,
@Nullable String writePermission, int pid, int uid,
- @Intent.GrantUriMode int modeFlags);
+ @Intent.AccessUriMode int modeFlags);
/**
* If a particular process and user ID has not been granted
@@ -2932,7 +2945,7 @@
* @see #checkUriPermission(Uri, int, int, int)
*/
public abstract void enforceUriPermission(
- Uri uri, int pid, int uid, @Intent.GrantUriMode int modeFlags, String message);
+ Uri uri, int pid, int uid, @Intent.AccessUriMode int modeFlags, String message);
/**
* If the calling process and user ID has not been granted
@@ -2954,7 +2967,7 @@
* @see #checkCallingUriPermission(Uri, int)
*/
public abstract void enforceCallingUriPermission(
- Uri uri, @Intent.GrantUriMode int modeFlags, String message);
+ Uri uri, @Intent.AccessUriMode int modeFlags, String message);
/**
* If the calling process of an IPC <em>or you</em> has not been
@@ -2973,7 +2986,7 @@
* @see #checkCallingOrSelfUriPermission(Uri, int)
*/
public abstract void enforceCallingOrSelfUriPermission(
- Uri uri, @Intent.GrantUriMode int modeFlags, String message);
+ Uri uri, @Intent.AccessUriMode int modeFlags, String message);
/**
* Enforce both a Uri and normal permission. This allows you to perform
@@ -2998,7 +3011,7 @@
*/
public abstract void enforceUriPermission(
@Nullable Uri uri, @Nullable String readPermission,
- @Nullable String writePermission, int pid, int uid, @Intent.GrantUriMode int modeFlags,
+ @Nullable String writePermission, int pid, int uid, @Intent.AccessUriMode int modeFlags,
@Nullable String message);
/** @hide */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 421956b..ae5437b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -18,6 +18,7 @@
import android.content.pm.ApplicationInfo;
import android.util.ArraySet;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -864,8 +865,9 @@
}
// Migrate any clip data and flags from target.
- int permFlags = target.getFlags()
- & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
+ int permFlags = target.getFlags() & (FLAG_GRANT_READ_URI_PERMISSION
+ | FLAG_GRANT_WRITE_URI_PERMISSION | FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | FLAG_GRANT_PREFIX_URI_PERMISSION);
if (permFlags != 0) {
ClipData targetClipData = target.getClipData();
if (targetClipData == null && target.getData() != null) {
@@ -2698,9 +2700,11 @@
* take the persistable permissions using
* {@link ContentResolver#takePersistableUriPermission(Uri, int)}.
* <p>
- * Callers can restrict document selection to a specific kind of data, such
- * as photos, by setting one or more MIME types in
- * {@link #EXTRA_MIME_TYPES}.
+ * Callers must indicate the acceptable document MIME types through
+ * {@link #setType(String)}. For example, to select photos, use
+ * {@code image/*}. If multiple disjoint MIME types are acceptable, define
+ * them in {@link #EXTRA_MIME_TYPES} and {@link #setType(String)} to
+ * {@literal *}/*.
* <p>
* If the caller can handle multiple returned items (the user performing
* multiple selection), then you can specify {@link #EXTRA_ALLOW_MULTIPLE}
@@ -2710,9 +2714,10 @@
* returned URIs can be opened with
* {@link ContentResolver#openFileDescriptor(Uri, String)}.
* <p>
- * Output: The URI of the item that was picked. This must be a
- * {@code content://} URI so that any receiver can access it. If multiple
- * documents were selected, they are returned in {@link #getClipData()}.
+ * Output: The URI of the item that was picked, returned in
+ * {@link #getData()}. This must be a {@code content://} URI so that any
+ * receiver can access it. If multiple documents were selected, they are
+ * returned in {@link #getClipData()}.
*
* @see DocumentsContract
* @see #ACTION_CREATE_DOCUMENT
@@ -2754,6 +2759,24 @@
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";
+ /**
+ * Activity Action: Allow the user to pick a directory. When invoked, the
+ * system will display the various {@link DocumentsProvider} instances
+ * installed on the device, letting the user navigate through them. Apps can
+ * fully manage documents within the returned directory.
+ * <p>
+ * To gain access to descendant (child, grandchild, etc) documents, use
+ * {@link DocumentsContract#buildDocumentViaUri(Uri, String)} and
+ * {@link DocumentsContract#buildChildDocumentsViaUri(Uri, String)} using
+ * the returned directory URI.
+ * <p>
+ * Output: The URI representing the selected directory.
+ *
+ * @see DocumentsContract
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_PICK_DIRECTORY = "android.intent.action.PICK_DIRECTORY";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -2781,6 +2804,14 @@
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_BROWSABLE = "android.intent.category.BROWSABLE";
/**
+ * Categories for activities that can participate in voice interaction.
+ * An activity that supports this category must be prepared to run with
+ * no UI shown at all (though in some case it may have a UI shown), and
+ * rely on {@link android.app.VoiceInteractor} to interact with the user.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_VOICE = "android.intent.category.VOICE";
+ /**
* Set if the activity should be considered as an alternative action to
* the data the user is currently viewing. See also
* {@link #CATEGORY_SELECTED_ALTERNATIVE} for an alternative action that
@@ -3332,6 +3363,7 @@
* @see #ACTION_GET_CONTENT
* @see #ACTION_OPEN_DOCUMENT
* @see #ACTION_CREATE_DOCUMENT
+ * @see #ACTION_PICK_DIRECTORY
*/
public static final String EXTRA_LOCAL_ONLY =
"android.intent.extra.LOCAL_ONLY";
@@ -3425,11 +3457,29 @@
// Intent flags (see mFlags variable).
/** @hide */
- @IntDef(flag = true,
- value = {FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION})
+ @IntDef(flag = true, value = {
+ FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION,
+ FLAG_GRANT_PERSISTABLE_URI_PERMISSION, FLAG_GRANT_PREFIX_URI_PERMISSION })
@Retention(RetentionPolicy.SOURCE)
public @interface GrantUriMode {}
+ /** @hide */
+ @IntDef(flag = true, value = {
+ FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AccessUriMode {}
+
+ /**
+ * Test if given mode flags specify an access mode, which must be at least
+ * read and/or write.
+ *
+ * @hide
+ */
+ public static boolean isAccessUriMode(int modeFlags) {
+ return (modeFlags & (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) != 0;
+ }
+
/**
* If set, the recipient of this Intent will be granted permission to
* perform read operations on the URI in the Intent's data and any URIs
@@ -3491,6 +3541,17 @@
public static final int FLAG_GRANT_PERSISTABLE_URI_PERMISSION = 0x00000040;
/**
+ * When combined with {@link #FLAG_GRANT_READ_URI_PERMISSION} and/or
+ * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, the URI permission grant
+ * applies to any URI that is a prefix match against the original granted
+ * URI. (Without this flag, the URI must match exactly for access to be
+ * granted.) Another URI is considered a prefix match only when scheme,
+ * authority, and all path segments defined by the prefix are an exact
+ * match.
+ */
+ public static final int FLAG_GRANT_PREFIX_URI_PERMISSION = 0x00000080;
+
+ /**
* If set, the new activity is not kept in the history stack. As soon as
* the user navigates away from it, the activity is finished. This may also
* be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
@@ -3810,9 +3871,9 @@
/**
* @hide Flags that can't be changed with PendingIntent.
*/
- public static final int IMMUTABLE_FLAGS =
- FLAG_GRANT_READ_URI_PERMISSION
- | FLAG_GRANT_WRITE_URI_PERMISSION;
+ public static final int IMMUTABLE_FLAGS = FLAG_GRANT_READ_URI_PERMISSION
+ | FLAG_GRANT_WRITE_URI_PERMISSION | FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | FLAG_GRANT_PREFIX_URI_PERMISSION;
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
@@ -6350,6 +6411,8 @@
*
* @see #FLAG_GRANT_READ_URI_PERMISSION
* @see #FLAG_GRANT_WRITE_URI_PERMISSION
+ * @see #FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ * @see #FLAG_GRANT_PREFIX_URI_PERMISSION
* @see #FLAG_DEBUG_LOG_RESOLUTION
* @see #FLAG_FROM_BACKGROUND
* @see #FLAG_ACTIVITY_BROUGHT_TO_FRONT
@@ -7381,9 +7444,10 @@
// Since we migrated in child, we need to promote ClipData
// and flags to ourselves to grant.
setClipData(target.getClipData());
- addFlags(target.getFlags()
- & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION
- | FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
+ addFlags(target.getFlags() & (FLAG_GRANT_READ_URI_PERMISSION
+ | FLAG_GRANT_WRITE_URI_PERMISSION
+ | FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | FLAG_GRANT_PREFIX_URI_PERMISSION));
return true;
} else {
return false;
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 9916476..c53e545 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -198,7 +198,7 @@
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
- * {@link android.R.attr#primaryUserOnly} attribute.
+ * android.R.attr#primaryUserOnly attribute.
*/
public static final int FLAG_PRIMARY_USER_ONLY = 0x20000000;
/**
@@ -210,6 +210,13 @@
*/
public static final int FLAG_SINGLE_USER = 0x40000000;
/**
+ * @hide Bit in {@link #flags}: If set, this activity may be launched into an
+ * owned ActivityContainer such as that within an ActivityView. If not set and
+ * this activity is launched into such a container a SecurityExcception will be
+ * thrown. Set from the {@link android.R.attr#allowEmbedded} attribute.
+ */
+ public static final int FLAG_ALLOW_EMBEDDED = 0x80000000;
+ /**
* Options that have been set in the activity declaration in the
* manifest.
* These include:
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ae0899f..488e25f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -74,6 +74,9 @@
ActivityInfo getActivityInfo(in ComponentName className, int flags, int userId);
+ boolean activitySupportsIntent(in ComponentName className, in Intent intent,
+ String resolvedType);
+
ActivityInfo getReceiverInfo(in ComponentName className, int flags, int userId);
ServiceInfo getServiceInfo(in ComponentName className, int flags, int userId);
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 92b9146..9087338 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -19,6 +19,8 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Bitmap.Config;
@@ -37,6 +39,8 @@
*/
public class LauncherActivityInfo {
private static final boolean DEBUG = false;
+ private static final String TAG = "LauncherActivityInfo";
+
private final PackageManager mPm;
private final UserManager mUm;
@@ -121,25 +125,42 @@
}
/**
+ * Returns the name for the acitivty from android:name in the manifest.
+ * @return the name from android:name for the acitivity.
+ */
+ public String getName() {
+ return mActivityInfo.name;
+ }
+
+ /**
* Returns the activity icon with badging appropriate for the profile.
* @param density Optional density for the icon, or 0 to use the default density.
* @return A badged icon for the activity.
*/
public Drawable getBadgedIcon(int density) {
- // TODO: Handle density
- if (mUser.equals(android.os.Process.myUserHandle())) {
- return mActivityInfo.loadIcon(mPm);
- }
- Drawable originalIcon = mActivityInfo.loadIcon(mPm);
- if (originalIcon == null) {
- if (DEBUG) {
- Log.w("LauncherActivityInfo", "Couldn't find icon for activity");
+ int iconRes = mActivityInfo.getIconResource();
+ Resources resources = null;
+ Drawable originalIcon = null;
+ try {
+ resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
+ try {
+ if (density != 0) {
+ originalIcon = resources.getDrawableForDensity(iconRes, density);
+ }
+ } catch (Resources.NotFoundException e) {
}
- originalIcon = mPm.getDefaultActivityIcon();
+ } catch (NameNotFoundException nnfe) {
}
+
+ if (originalIcon == null) {
+ originalIcon = mActivityInfo.loadIcon(mPm);
+ }
+
if (originalIcon instanceof BitmapDrawable) {
return mUm.getBadgedDrawableForUser(
originalIcon, mUser);
+ } else {
+ Log.e(TAG, "Unable to create badged icon for " + mActivityInfo);
}
return originalIcon;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d981cc1..484a2a1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1235,7 +1235,6 @@
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
-
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports app widgets.
@@ -1244,6 +1243,17 @@
public static final String FEATURE_APP_WIDGETS = "android.software.app_widgets";
/**
+ * @hide
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports
+ * {@link android.service.voice.VoiceInteractionService} and
+ * {@link android.app.VoiceInteractor}.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VOICE_RECOGNIZERS = "android.software.voice_recognizers";
+
+
+ /**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports a home screen that is replaceable
* by third party applications.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8d8d220..8f19f01 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -50,6 +50,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
@@ -147,8 +148,7 @@
private String[] mSeparateProcesses;
private boolean mOnlyCoreApps;
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
- private static final String SDK_CODENAME = "REL".equals(Build.VERSION.CODENAME)
- ? null : Build.VERSION.CODENAME;
+ private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
private int mParseError = PackageManager.INSTALL_SUCCEEDED;
@@ -1200,10 +1200,18 @@
sa.recycle();
if (minCode != null) {
- if (!minCode.equals(SDK_CODENAME)) {
- if (SDK_CODENAME != null) {
+ boolean allowedCodename = false;
+ for (String codename : SDK_CODENAMES) {
+ if (minCode.equals(codename)) {
+ allowedCodename = true;
+ break;
+ }
+ }
+ if (!allowedCodename) {
+ if (SDK_CODENAMES.length > 0) {
outError[0] = "Requires development platform " + minCode
- + " (current platform is " + SDK_CODENAME + ")";
+ + " (current platform is any of "
+ + Arrays.toString(SDK_CODENAMES) + ")";
} else {
outError[0] = "Requires development platform " + minCode
+ " but this is a release platform.";
@@ -1219,10 +1227,18 @@
}
if (targetCode != null) {
- if (!targetCode.equals(SDK_CODENAME)) {
- if (SDK_CODENAME != null) {
+ boolean allowedCodename = false;
+ for (String codename : SDK_CODENAMES) {
+ if (targetCode.equals(codename)) {
+ allowedCodename = true;
+ break;
+ }
+ }
+ if (!allowedCodename) {
+ if (SDK_CODENAMES.length > 0) {
outError[0] = "Requires development platform " + targetCode
- + " (current platform is " + SDK_CODENAME + ")";
+ + " (current platform is any of "
+ + Arrays.toString(SDK_CODENAMES) + ")";
} else {
outError[0] = "Requires development platform " + targetCode
+ " but this is a release platform.";
@@ -2452,6 +2468,12 @@
a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+ }
+
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 2c53f03..bb290af 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -570,6 +570,14 @@
public static abstract class CaptureListener {
/**
+ * This constant is used to indicate that no images were captured for
+ * the request.
+ *
+ * @hide
+ */
+ public static final int NO_FRAMES_CAPTURED = -1;
+
+ /**
* This method is called when the camera device has started capturing
* the output image for the request, at the beginning of image exposure.
*
@@ -693,9 +701,12 @@
* The CameraDevice sending the callback.
* @param sequenceId
* A sequence ID returned by the {@link #capture} family of functions.
- * @param frameNumber
+ * @param lastFrameNumber
* The last frame number (returned by {@link CaptureResult#getFrameNumber}
* or {@link CaptureFailure#getFrameNumber}) in the capture sequence.
+ * The last frame number may be equal to NO_FRAMES_CAPTURED if no images
+ * were captured for this sequence. This can happen, for example, when a
+ * repeating request or burst is cleared right after being set.
*
* @see CaptureResult#getFrameNumber()
* @see CaptureFailure#getFrameNumber()
@@ -703,7 +714,7 @@
* @see CaptureFailure#getSequenceId()
*/
public void onCaptureSequenceCompleted(CameraDevice camera,
- int sequenceId, int frameNumber) {
+ int sequenceId, int lastFrameNumber) {
// default empty implementation
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index cd44b51..ee2adac 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -292,6 +292,76 @@
return submitCaptureRequest(requests, listener, handler, /*streaming*/false);
}
+ /**
+ * This method checks lastFrameNumber returned from ICameraDeviceUser methods for
+ * starting and stopping repeating request and flushing.
+ *
+ * <p>If lastFrameNumber is NO_FRAMES_CAPTURED, it means that the request was never
+ * sent to HAL. Then onCaptureSequenceCompleted is immediately triggered.
+ * If lastFrameNumber is non-negative, then the requestId and lastFrameNumber pair
+ * is added to the list mFrameNumberRequestPairs.</p>
+ *
+ * @param requestId the request ID of the current repeating request.
+ *
+ * @param lastFrameNumber last frame number returned from binder.
+ */
+ private void checkEarlyTriggerSequenceComplete(
+ final int requestId, final long lastFrameNumber) {
+ // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request
+ // was never sent to HAL. Should trigger onCaptureSequenceCompleted immediately.
+ if (lastFrameNumber == CaptureListener.NO_FRAMES_CAPTURED) {
+ final CaptureListenerHolder holder;
+ int index = mCaptureListenerMap.indexOfKey(requestId);
+ holder = (index >= 0) ? mCaptureListenerMap.valueAt(index) : null;
+ if (holder != null) {
+ mCaptureListenerMap.removeAt(index);
+ if (DEBUG) {
+ Log.v(TAG, String.format(
+ "remove holder for requestId %d, "
+ + "because lastFrame is %d.",
+ requestId, lastFrameNumber));
+ }
+ }
+
+ if (holder != null) {
+ if (DEBUG) {
+ Log.v(TAG, "immediately trigger onCaptureSequenceCompleted because"
+ + " request did not reach HAL");
+ }
+
+ Runnable resultDispatch = new Runnable() {
+ @Override
+ public void run() {
+ if (!CameraDevice.this.isClosed()) {
+ if (DEBUG) {
+ Log.d(TAG, String.format(
+ "early trigger sequence complete for request %d",
+ requestId));
+ }
+ if (lastFrameNumber < Integer.MIN_VALUE
+ || lastFrameNumber > Integer.MAX_VALUE) {
+ throw new AssertionError(lastFrameNumber + " cannot be cast to int");
+ }
+ holder.getListener().onCaptureSequenceCompleted(
+ CameraDevice.this,
+ requestId,
+ (int)lastFrameNumber);
+ }
+ }
+ };
+ holder.getHandler().post(resultDispatch);
+ } else {
+ Log.w(TAG, String.format(
+ "did not register listener to request %d",
+ requestId));
+ }
+ } else {
+ mFrameNumberRequestPairs.add(
+ new SimpleEntry<Long, Integer>(lastFrameNumber,
+ requestId));
+ }
+ }
+
private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener,
Handler handler, boolean repeating) throws CameraAccessException {
@@ -313,7 +383,7 @@
try {
requestId = mRemoteDevice.submitRequestList(requestList, repeating,
/*out*/lastFrameNumberRef);
- if (!repeating) {
+ if (DEBUG) {
Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
}
} catch (CameraRuntimeException e) {
@@ -322,25 +392,21 @@
// impossible
return -1;
}
+
if (listener != null) {
mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener,
requestList, handler, repeating));
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Listen for request " + requestId + " is null");
+ }
}
long lastFrameNumber = lastFrameNumberRef.getNumber();
- /**
- * If it's the first repeating request, then returned lastFrameNumber can be
- * negative. Otherwise, it should always be non-negative.
- */
- if (((lastFrameNumber < 0) && (requestId > 0))
- || ((lastFrameNumber < 0) && (!repeating))) {
- throw new AssertionError(String.format("returned bad frame number %d",
- lastFrameNumber));
- }
+
if (repeating) {
if (mRepeatingRequestId != REQUEST_ID_NONE) {
- mFrameNumberRequestPairs.add(
- new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId));
+ checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
}
mRepeatingRequestId = requestId;
} else {
@@ -395,12 +461,9 @@
LongParcelable lastFrameNumberRef = new LongParcelable();
mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
long lastFrameNumber = lastFrameNumberRef.getNumber();
- if ((lastFrameNumber < 0) && (requestId > 0)) {
- throw new AssertionError(String.format("returned bad frame number %d",
- lastFrameNumber));
- }
- mFrameNumberRequestPairs.add(
- new SimpleEntry<Long, Integer>(lastFrameNumber, requestId));
+
+ checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
+
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
@@ -443,11 +506,7 @@
mRemoteDevice.flush(/*out*/lastFrameNumberRef);
if (mRepeatingRequestId != REQUEST_ID_NONE) {
long lastFrameNumber = lastFrameNumberRef.getNumber();
- if (lastFrameNumber < 0) {
- Log.e(TAG, String.format("returned bad frame number %d", lastFrameNumber));
- }
- mFrameNumberRequestPairs.add(
- new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId));
+ checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
mRepeatingRequestId = REQUEST_ID_NONE;
}
} catch (CameraRuntimeException e) {
@@ -582,8 +641,8 @@
*/
if (frameNumber != mCompletedFrameNumber + 1) {
throw new AssertionError(String.format(
- "result frame number %d comes out of order",
- frameNumber));
+ "result frame number %d comes out of order, should be %d + 1",
+ frameNumber, mCompletedFrameNumber));
}
mCompletedFrameNumber++;
}
@@ -607,11 +666,18 @@
final int requestId = frameNumberRequestPair.getValue();
final CaptureListenerHolder holder;
synchronized (mLock) {
- int index = CameraDevice.this.mCaptureListenerMap.indexOfKey(requestId);
- holder = (index >= 0) ? CameraDevice.this.mCaptureListenerMap.valueAt(index)
+ int index = mCaptureListenerMap.indexOfKey(requestId);
+ holder = (index >= 0) ? mCaptureListenerMap.valueAt(index)
: null;
if (holder != null) {
- CameraDevice.this.mCaptureListenerMap.removeAt(index);
+ mCaptureListenerMap.removeAt(index);
+ if (DEBUG) {
+ Log.v(TAG, String.format(
+ "remove holder for requestId %d, "
+ + "because lastFrame %d is <= %d",
+ requestId, frameNumberRequestPair.getKey(),
+ completedFrameNumber));
+ }
}
}
iter.remove();
@@ -628,11 +694,16 @@
requestId));
}
+ long lastFrameNumber = frameNumberRequestPair.getKey();
+ if (lastFrameNumber < Integer.MIN_VALUE
+ || lastFrameNumber > Integer.MAX_VALUE) {
+ throw new AssertionError(lastFrameNumber
+ + " cannot be cast to int");
+ }
holder.getListener().onCaptureSequenceCompleted(
CameraDevice.this,
requestId,
- // TODO: this is problematic, crop long to int
- frameNumberRequestPair.getKey().intValue());
+ (int)lastFrameNumber);
}
}
};
@@ -705,6 +776,9 @@
}
// Fire onCaptureSequenceCompleted
+ if (DEBUG) {
+ Log.v(TAG, String.format("got error frame %d", resultExtras.getFrameNumber()));
+ }
mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true);
checkAndFireSequenceComplete();
@@ -764,20 +838,40 @@
CaptureResultExtras resultExtras) throws RemoteException {
int requestId = resultExtras.getRequestId();
if (DEBUG) {
- Log.d(TAG, "Received result for id " + requestId);
+ Log.v(TAG, "Received result frame " + resultExtras.getFrameNumber() + " for id "
+ + requestId);
}
- final CaptureListenerHolder holder =
- CameraDevice.this.mCaptureListenerMap.get(requestId);
+ final CaptureListenerHolder holder;
+ synchronized (mLock) {
+ holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
+ }
Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
+ // Update tracker (increment counter) when it's not a partial result.
+ if (!quirkIsPartialResult) {
+ mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
+ }
+
// Check if we have a listener for this
if (holder == null) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "holder is null, early return at frame "
+ + resultExtras.getFrameNumber());
+ }
return;
}
- if (isClosed()) return;
+ if (isClosed()) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "camera is closed, early return at frame "
+ + resultExtras.getFrameNumber());
+ }
+ return;
+ }
final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
@@ -817,7 +911,6 @@
// Fire onCaptureSequenceCompleted
if (!quirkIsPartialResult) {
- mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false);
checkAndFireSequenceComplete();
}
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index a517bc5..79673b3 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -437,6 +437,14 @@
* The behavior of the virtual display depends on the flags that are provided
* to this method. By default, virtual displays are created to be private,
* non-presentation and unsecure. Permissions may be required to use certain flags.
+ * </p><p>
+ * As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may
+ * be attached or detached dynamically using {@link VirtualDisplay#setSurface}.
+ * Previously, the surface had to be non-null when {@link #createVirtualDisplay}
+ * was called and could not be changed for the lifetime of the display.
+ * </p><p>
+ * Detaching the surface that backs a virtual display has a similar effect to
+ * turning off the screen.
* </p>
*
* @param name The name of the virtual display, must be non-empty.
@@ -444,7 +452,7 @@
* @param height The height of the virtual display in pixels, must be greater than 0.
* @param densityDpi The density of the virtual display in dpi, must be greater than 0.
* @param surface The surface to which the content of the virtual display should
- * be rendered, must be non-null.
+ * be rendered, or null if there is none initially.
* @param flags A combination of virtual display flags:
* {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
* {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, or {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 3417430..a8d55e8 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -377,9 +377,6 @@
throw new IllegalArgumentException("width, height, and densityDpi must be "
+ "greater than 0");
}
- if (surface == null) {
- throw new IllegalArgumentException("surface must not be null");
- }
Binder token = new Binder();
int displayId;
@@ -404,7 +401,15 @@
}
return null;
}
- return new VirtualDisplay(this, display, token);
+ return new VirtualDisplay(this, display, token, surface);
+ }
+
+ public void setVirtualDisplaySurface(IBinder token, Surface surface) {
+ try {
+ mDm.setVirtualDisplaySurface(token, surface);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to set virtual display surface.", ex);
+ }
}
public void releaseVirtualDisplay(IBinder token) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 68eb13f..23c58c8 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -63,5 +63,8 @@
String name, int width, int height, int densityDpi, in Surface surface, int flags);
// No permissions required but must be same Uid as the creator.
+ void setVirtualDisplaySurface(in IBinder token, in Surface surface);
+
+ // No permissions required but must be same Uid as the creator.
void releaseVirtualDisplay(in IBinder token);
}
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index 01e5bac..691d6a0 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -17,15 +17,18 @@
import android.os.IBinder;
import android.view.Display;
+import android.view.Surface;
/**
* Represents a virtual display. The content of a virtual display is rendered to a
* {@link android.view.Surface} that you must provide to {@link DisplayManager#createVirtualDisplay
* createVirtualDisplay()}.
- * <p>Because a virtual display renders to a surface provided by the application, it will be
+ * <p>
+ * Because a virtual display renders to a surface provided by the application, it will be
* released automatically when the process terminates and all remaining windows on it will
- * be forcibly removed. However, you should also explicitly call {@link #release} when you're
- * done with it.
+ * be forcibly removed. However, you should also explicitly call {@link #release} when
+ * you're done with it.
+ * </p>
*
* @see DisplayManager#createVirtualDisplay
*/
@@ -33,11 +36,14 @@
private final DisplayManagerGlobal mGlobal;
private final Display mDisplay;
private IBinder mToken;
+ private Surface mSurface;
- VirtualDisplay(DisplayManagerGlobal global, Display display, IBinder token) {
+ VirtualDisplay(DisplayManagerGlobal global, Display display, IBinder token,
+ Surface surface) {
mGlobal = global;
mDisplay = display;
mToken = token;
+ mSurface = surface;
}
/**
@@ -48,6 +54,32 @@
}
/**
+ * Gets the surface that backs the virtual display.
+ */
+ public Surface getSurface() {
+ return mSurface;
+ }
+
+ /**
+ * Sets the surface that backs the virtual display.
+ * <p>
+ * Detaching the surface that backs a virtual display has a similar effect to
+ * turning off the screen.
+ * </p><p>
+ * It is still the caller's responsibility to destroy the surface after it has
+ * been detached.
+ * </p>
+ *
+ * @param surface The surface to set, or null to detach the surface from the virtual display.
+ */
+ public void setSurface(Surface surface) {
+ if (mSurface != surface) {
+ mGlobal.setVirtualDisplaySurface(mToken, surface);
+ mSurface = surface;
+ }
+ }
+
+ /**
* Releases the virtual display and destroys its underlying surface.
* <p>
* All remaining windows on the virtual display will be forcibly removed
@@ -63,6 +95,7 @@
@Override
public String toString() {
- return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken + "}";
+ return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken
+ + ", surface=" + mSurface + "}";
}
}
diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java
index 21de9f5..4c074e9 100644
--- a/core/java/android/hardware/location/GeofenceHardware.java
+++ b/core/java/android/hardware/location/GeofenceHardware.java
@@ -79,7 +79,7 @@
*/
public static final int MONITOR_UNSUPPORTED = 2;
- // The following constants need to match geofence flags in gps.h
+ // The following constants need to match geofence flags in gps.h and fused_location.h
/**
* The constant to indicate that the user has entered the geofence.
*/
@@ -92,7 +92,7 @@
/**
* The constant to indicate that the user is uncertain with respect to a
- * geofence. nn
+ * geofence.
*/
public static final int GEOFENCE_UNCERTAIN = 1<<2L;
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
new file mode 100644
index 0000000..a72d9a0
--- /dev/null
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -0,0 +1,49 @@
+/**
+ * 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.net;
+
+import android.net.ScoredNetwork;
+
+/**
+ * A service for updating network scores from a network scorer application.
+ * @hide
+ */
+interface INetworkScoreService
+{
+ /**
+ * Update scores.
+ * @return whether the update was successful.
+ * @throws SecurityException if the caller is not the current active scorer.
+ */
+ boolean updateScores(in ScoredNetwork[] networks);
+
+ /**
+ * Clear all scores.
+ * @return whether the clear was successful.
+ * @throws SecurityException if the caller is neither the current active scorer nor the scorer
+ * manager.
+ */
+ boolean clearScores();
+
+ /**
+ * Set the active scorer and clear existing scores.
+ * @param packageName the package name of the new scorer to use.
+ * @return true if the operation succeeded, or false if the new package is not a valid scorer.
+ * @throws SecurityException if the caller is not the scorer manager.
+ */
+ boolean setActiveScorer(in String packageName);
+}
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index cc3ad3e..bc19658 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -19,11 +19,19 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Information which identifies a specific network.
*
* @hide
*/
+// NOTE: Ideally, we would abstract away the details of what identifies a network of a specific
+// type, so that all networks appear the same and can be scored without concern to the network type
+// itself. However, because no such cross-type identifier currently exists in the Android framework,
+// and because systems might obtain information about networks from sources other than Android
+// devices, we need to provide identifying details about each specific network type (wifi, cell,
+// etc.) so that clients can pull out these details depending on the type of network.
public class NetworkKey implements Parcelable {
/** A wifi network, for which {@link #wifiKey} will be populated. */
@@ -79,6 +87,21 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ NetworkKey that = (NetworkKey) o;
+
+ return type == that.type && Objects.equals(wifiKey, that.wifiKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, wifiKey);
+ }
+
+ @Override
public String toString() {
switch (type) {
case TYPE_WIFI:
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 3430547..6dd56d9 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -19,6 +19,9 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
/**
* Class that manages communication between network subsystems and a network scorer.
@@ -37,33 +40,33 @@
* and (eventually) calls {@link #updateScores} with the results.
* </ul>
*
- * <p>The system keeps track of a default scorer application; at any time, only this application
+ * <p>The system keeps track of an active scorer application; at any time, only this application
* will receive {@link #ACTION_SCORE_NETWORKS} broadcasts and will be permitted to call
- * {@link #updateScores}. Applications may determine the current default scorer with
- * {@link #getDefaultScorerPackage()} and request to change the default scorer by sending an
- * {@link #ACTION_CHANGE_DEFAULT} broadcast with another scorer.
+ * {@link #updateScores}. Applications may determine the current active scorer with
+ * {@link #getActiveScorerPackage()} and request to change the active scorer by sending an
+ * {@link #ACTION_CHANGE_ACTIVE} broadcast with another scorer.
*
* @hide
*/
public class NetworkScoreManager {
/**
- * Activity action: ask the user to change the default network scorer. This will show a dialog
- * that asks the user whether they want to replace the current default scorer with the one
+ * Activity action: ask the user to change the active network scorer. This will show a dialog
+ * that asks the user whether they want to replace the current active scorer with the one
* specified in {@link #EXTRA_PACKAGE_NAME}. The activity will finish with RESULT_OK if the
- * default was changed or RESULT_CANCELED if it failed for any reason.
+ * active scorer was changed or RESULT_CANCELED if it failed for any reason.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_CHANGE_DEFAULT = "android.net.scoring.CHANGE_DEFAULT";
+ public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
/**
- * Extra used with {@link #ACTION_CHANGE_DEFAULT} to specify the new scorer package. Set with
+ * Extra used with {@link #ACTION_CHANGE_ACTIVE} to specify the new scorer package. Set with
* {@link android.content.Intent#putExtra(String, String)}.
*/
public static final String EXTRA_PACKAGE_NAME = "packageName";
/**
* Broadcast action: new network scores are being requested. This intent will only be delivered
- * to the current default scorer app. That app is responsible for scoring the networks and
+ * to the current active scorer app. That app is responsible for scoring the networks and
* calling {@link #updateScores} when complete. The networks to score are specified in
* {@link #EXTRA_NETWORKS_TO_SCORE}, and will generally consist of all networks which have been
* configured by the user as well as any open networks.
@@ -81,38 +84,82 @@
public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
private final Context mContext;
+ private final INetworkScoreService mService;
/** @hide */
public NetworkScoreManager(Context context) {
mContext = context;
+ IBinder iBinder = ServiceManager.getService(Context.NETWORK_SCORE_SERVICE);
+ mService = INetworkScoreService.Stub.asInterface(iBinder);
}
/**
- * Obtain the package name of the current default network scorer.
+ * Obtain the package name of the current active network scorer.
*
- * At any time, only one scorer application will receive {@link #ACTION_SCORE_NETWORKS}
+ * <p>At any time, only one scorer application will receive {@link #ACTION_SCORE_NETWORKS}
* broadcasts and be allowed to call {@link #updateScores}. Applications may use this method to
* determine the current scorer and offer the user the ability to select a different scorer via
- * the {@link #ACTION_CHANGE_DEFAULT} intent.
- * @return the full package name of the current default scorer, or null if there is no active
+ * the {@link #ACTION_CHANGE_ACTIVE} intent.
+ * @return the full package name of the current active scorer, or null if there is no active
* scorer.
*/
- public String getDefaultScorerPackage() {
- // TODO: Implement.
- return null;
+ public String getActiveScorerPackage() {
+ return NetworkScorerAppManager.getActiveScorer(mContext);
}
/**
* Update network scores.
*
- * This may be called at any time to re-score active networks. Scores will generally be updated
- * quickly, but if this method is called too frequently, the scores may be held and applied at
- * a later time.
+ * <p>This may be called at any time to re-score active networks. Scores will generally be
+ * updated quickly, but if this method is called too frequently, the scores may be held and
+ * applied at a later time.
*
* @param networks the networks which have been scored by the scorer.
- * @throws SecurityException if the caller is not the default scorer.
+ * @return whether the update was successful.
+ * @throws SecurityException if the caller is not the active scorer.
*/
- public void updateScores(ScoredNetwork[] networks) throws SecurityException {
- // TODO: Implement.
+ public boolean updateScores(ScoredNetwork[] networks) throws SecurityException {
+ try {
+ return mService.updateScores(networks);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Clear network scores.
+ *
+ * <p>Should be called when all scores need to be invalidated, i.e. because the scoring
+ * algorithm has changed and old scores can no longer be compared to future scores.
+ *
+ * <p>Note that scores will be cleared automatically when the active scorer changes, as scores
+ * from one scorer cannot be compared to those from another scorer.
+ *
+ * @return whether the clear was successful.
+ * @throws SecurityException if the caller is not the active scorer or privileged.
+ */
+ public boolean clearScores() throws SecurityException {
+ try {
+ return mService.clearScores();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Set the active scorer to a new package and clear existing scores.
+ *
+ * @return true if the operation succeeded, or false if the new package is not a valid scorer.
+ * @throws SecurityException if the caller does not hold the
+ * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission indicating that
+ * it can manage scorer applications.
+ * @hide
+ */
+ public boolean setActiveScorer(String packageName) throws SecurityException {
+ try {
+ return mService.setActiveScorer(packageName);
+ } catch (RemoteException e) {
+ return false;
+ }
}
}
diff --git a/core/java/android/net/NetworkScorerApplication.java b/core/java/android/net/NetworkScorerAppManager.java
similarity index 84%
rename from core/java/android/net/NetworkScorerApplication.java
rename to core/java/android/net/NetworkScorerAppManager.java
index b137ad3..3660e7a 100644
--- a/core/java/android/net/NetworkScorerApplication.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -26,6 +26,7 @@
import android.provider.Settings;
import android.provider.Settings.Global;
import android.text.TextUtils;
+import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
@@ -36,13 +37,14 @@
*
* @hide
*/
-public final class NetworkScorerApplication {
+public final class NetworkScorerAppManager {
+ private static final String TAG = "NetworkScorerAppManager";
private static final Intent SCORE_INTENT =
new Intent(NetworkScoreManager.ACTION_SCORE_NETWORKS);
/** This class cannot be instantiated. */
- private NetworkScorerApplication() {}
+ private NetworkScorerAppManager() {}
/**
* Returns the list of available scorer app package names.
@@ -95,8 +97,7 @@
public static String getActiveScorer(Context context) {
String scorerPackage = Settings.Global.getString(context.getContentResolver(),
Global.NETWORK_SCORER_APP);
- Collection<String> applications = getAllValidScorers(context);
- if (isPackageValidScorer(applications, scorerPackage)) {
+ if (isPackageValidScorer(context, scorerPackage)) {
return scorerPackage;
} else {
return null;
@@ -111,30 +112,37 @@
* @param context the context of the calling application
* @param packageName the packageName of the new scorer to use. If null, scoring will be
* disabled. Otherwise, the scorer will only be set if it is a valid scorer application.
+ * @return true if the scorer was changed, or false if the package is not a valid scorer.
*/
- public static void setActiveScorer(Context context, String packageName) {
+ public static boolean setActiveScorer(Context context, String packageName) {
String oldPackageName = Settings.Global.getString(context.getContentResolver(),
Settings.Global.NETWORK_SCORER_APP);
if (TextUtils.equals(oldPackageName, packageName)) {
// No change.
- return;
+ return true;
}
+ Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
+
if (packageName == null) {
Settings.Global.putString(context.getContentResolver(), Global.NETWORK_SCORER_APP,
null);
+ return true;
} else {
// We only make the change if the new package is valid.
- Collection<String> applications = getAllValidScorers(context);
- if (isPackageValidScorer(applications, packageName)) {
+ if (isPackageValidScorer(context, packageName)) {
Settings.Global.putString(context.getContentResolver(),
Settings.Global.NETWORK_SCORER_APP, packageName);
+ return true;
+ } else {
+ Log.w(TAG, "Requested network scorer is not valid: " + packageName);
+ return false;
}
}
}
/** Determine whether the application with the given UID is the enabled scorer. */
- public static boolean isCallerDefaultScorer(Context context, int callingUid) {
+ public static boolean isCallerActiveScorer(Context context, int callingUid) {
String defaultApp = getActiveScorer(context);
if (defaultApp == null) {
return false;
@@ -149,8 +157,8 @@
}
/** Returns true if the given package is a valid scorer. */
- private static boolean isPackageValidScorer(Collection<String> scorerPackageNames,
- String packageName) {
- return packageName != null && scorerPackageNames.contains(packageName);
+ public static boolean isPackageValidScorer(Context context, String packageName) {
+ Collection<String> applications = getAllValidScorers(context);
+ return packageName != null && applications.contains(packageName);
}
}
diff --git a/core/java/android/net/RssiCurve.java b/core/java/android/net/RssiCurve.java
index 7af7998..33e81c2 100644
--- a/core/java/android/net/RssiCurve.java
+++ b/core/java/android/net/RssiCurve.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* A curve defining the network score over a range of RSSI values.
*
@@ -94,6 +97,30 @@
out.writeByteArray(rssiBuckets);
}
+ /**
+ * Determine if two RSSI curves are defined in the same way.
+ *
+ * <p>Note that two curves can be equivalent but defined differently, e.g. if one bucket in one
+ * curve is split into two buckets in another. For the purpose of this method, these curves are
+ * not considered equal to each other.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ RssiCurve rssiCurve = (RssiCurve) o;
+
+ return start == rssiCurve.start &&
+ bucketWidth == rssiCurve.bucketWidth &&
+ Arrays.equals(rssiBuckets, rssiCurve.rssiBuckets);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(start, bucketWidth, rssiBuckets);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index 8af3c3c..7902313 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* A network identifier along with a score for the quality of that network.
*
@@ -80,6 +82,22 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ScoredNetwork that = (ScoredNetwork) o;
+
+ return Objects.equals(networkKey, that.networkKey) &&
+ Objects.equals(rssiCurve, that.rssiCurve);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(networkKey, rssiCurve);
+ }
+
+ @Override
public String toString() {
return "ScoredNetwork[key=" + networkKey + ",score=" + rssiCurve + "]";
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index a7a8a0a..ce70455 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -21,6 +21,7 @@
import android.os.Parcelable;
import android.os.StrictMode;
import android.util.Log;
+
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -32,8 +33,10 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
import java.util.RandomAccess;
import java.util.Set;
+
import libcore.net.UriCodec;
/**
@@ -2338,4 +2341,29 @@
StrictMode.onFileUriExposed(location);
}
}
+
+ /**
+ * Test if this is a path prefix match against the given Uri. Verifies that
+ * scheme, authority, and atomic path segments match.
+ *
+ * @hide
+ */
+ public boolean isPathPrefixMatch(Uri prefix) {
+ if (!Objects.equals(getScheme(), prefix.getScheme())) return false;
+ if (!Objects.equals(getAuthority(), prefix.getAuthority())) return false;
+
+ List<String> seg = getPathSegments();
+ List<String> prefixSeg = prefix.getPathSegments();
+
+ final int prefixSize = prefixSeg.size();
+ if (seg.size() < prefixSize) return false;
+
+ for (int i = 0; i < prefixSize; i++) {
+ if (!Objects.equals(seg.get(i), prefixSeg.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/core/java/android/net/WifiKey.java b/core/java/android/net/WifiKey.java
index ffcd85a..9e92e89 100644
--- a/core/java/android/net/WifiKey.java
+++ b/core/java/android/net/WifiKey.java
@@ -19,6 +19,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
import java.util.regex.Pattern;
/**
@@ -87,6 +88,21 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ WifiKey wifiKey = (WifiKey) o;
+
+ return Objects.equals(ssid, wifiKey.ssid) && Objects.equals(bssid, wifiKey.bssid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ssid, bssid);
+ }
+
+ @Override
public String toString() {
return "WifiKey[SSID=" + ssid + ",BSSID=" + bssid + "]";
}
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index b8a5ba7..ae9796b 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -17,6 +17,7 @@
package android.nfc;
import android.content.ComponentName;
+import android.nfc.cardemulation.AidGroup;
import android.nfc.cardemulation.ApduServiceInfo;
import android.os.RemoteCallback;
@@ -29,5 +30,8 @@
boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid);
boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
boolean setDefaultForNextTap(int userHandle, in ComponentName service);
+ boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
+ AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
+ boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
List<ApduServiceInfo> getServices(int userHandle, in String category);
}
diff --git a/core/java/android/nfc/cardemulation/AidGroup.aidl b/core/java/android/nfc/cardemulation/AidGroup.aidl
new file mode 100644
index 0000000..56d6fa5
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/AidGroup.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 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.nfc.cardemulation;
+
+parcelable AidGroup;
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
new file mode 100644
index 0000000..2820f40
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -0,0 +1,165 @@
+package android.nfc.cardemulation;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * The AidGroup class represents a group of ISO/IEC 7816-4
+ * Application Identifiers (AIDs) for a specific application
+ * category, along with a description resource describing
+ * the group.
+ */
+public final class AidGroup implements Parcelable {
+ /**
+ * The maximum number of AIDs that can be present in any one group.
+ */
+ public static final int MAX_NUM_AIDS = 256;
+
+ static final String TAG = "AidGroup";
+
+ final ArrayList<String> aids;
+ final String category;
+ final String description;
+
+ /**
+ * Creates a new AidGroup object.
+ *
+ * @param aids The list of AIDs present in the group
+ * @param category The category of this group
+ */
+ public AidGroup(ArrayList<String> aids, String category) {
+ if (aids == null || aids.size() == 0) {
+ throw new IllegalArgumentException("No AIDS in AID group.");
+ }
+ if (aids.size() > MAX_NUM_AIDS) {
+ throw new IllegalArgumentException("Too many AIDs in AID group.");
+ }
+ if (!isValidCategory(category)) {
+ throw new IllegalArgumentException("Category specified is not valid.");
+ }
+ this.aids = aids;
+ this.category = category;
+ this.description = null;
+ }
+
+ AidGroup(String category, String description) {
+ this.aids = new ArrayList<String>();
+ this.category = category;
+ this.description = description;
+ }
+
+ /**
+ * @return the category of this AID group
+ */
+ public String getCategory() {
+ return category;
+ }
+
+ /**
+ * @return the list of AIDs in this group
+ */
+ public ArrayList<String> getAids() {
+ return aids;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder out = new StringBuilder("Category: " + category +
+ ", AIDs:");
+ for (String aid : aids) {
+ out.append(aid);
+ out.append(", ");
+ }
+ return out.toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(category);
+ dest.writeInt(aids.size());
+ if (aids.size() > 0) {
+ dest.writeStringList(aids);
+ }
+ }
+
+ public static final Parcelable.Creator<AidGroup> CREATOR =
+ new Parcelable.Creator<AidGroup>() {
+
+ @Override
+ public AidGroup createFromParcel(Parcel source) {
+ String category = source.readString();
+ int listSize = source.readInt();
+ ArrayList<String> aidList = new ArrayList<String>();
+ if (listSize > 0) {
+ source.readStringList(aidList);
+ }
+ return new AidGroup(aidList, category);
+ }
+
+ @Override
+ public AidGroup[] newArray(int size) {
+ return new AidGroup[size];
+ }
+ };
+
+ /**
+ * @hide
+ * Note: description is not serialized, since it's not localized
+ * and resource identifiers don't make sense to persist.
+ */
+ static public AidGroup createFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String category = parser.getAttributeValue(null, "category");
+ ArrayList<String> aids = new ArrayList<String>();
+ int eventType = parser.getEventType();
+ int minDepth = parser.getDepth();
+ while (eventType != XmlPullParser.END_DOCUMENT && parser.getDepth() >= minDepth) {
+ if (eventType == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ if (tagName.equals("aid")) {
+ String aid = parser.getAttributeValue(null, "value");
+ if (aid != null) {
+ aids.add(aid);
+ }
+ } else {
+ Log.d(TAG, "Ignorning unexpected tag: " + tagName);
+ }
+ }
+ eventType = parser.next();
+ }
+ if (category != null && aids.size() > 0) {
+ return new AidGroup(aids, category);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void writeAsXml(XmlSerializer out) throws IOException {
+ out.attribute(null, "category", category);
+ for (String aid : aids) {
+ out.startTag(null, "aid");
+ out.attribute(null, "value", aid);
+ out.endTag(null, "aid");
+ }
+ }
+
+ boolean isValidCategory(String category) {
+ return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
+ CardEmulation.CATEGORY_OTHER.equals(category);
+ }
+}
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index d7ef4bc..94f35ed 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -35,9 +35,12 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Map;
/**
* @hide
@@ -56,24 +59,19 @@
final String mDescription;
/**
- * Convenience AID list
- */
- final ArrayList<String> mAids;
-
- /**
* Whether this service represents AIDs running on the host CPU
*/
final boolean mOnHost;
/**
- * All AID groups this service handles
+ * Mapping from category to static AID group
*/
- final ArrayList<AidGroup> mAidGroups;
+ final HashMap<String, AidGroup> mStaticAidGroups;
/**
- * Convenience hashmap
+ * Mapping from category to dynamic AID group
*/
- final HashMap<String, AidGroup> mCategoryToGroup;
+ final HashMap<String, AidGroup> mDynamicAidGroups;
/**
* Whether this service should only be started when the device is unlocked.
@@ -86,26 +84,33 @@
final int mBannerResourceId;
/**
+ * The uid of the package the service belongs to
+ */
+ final int mUid;
+ /**
* @hide
*/
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
- ArrayList<AidGroup> aidGroups, boolean requiresUnlock, int bannerResource) {
+ ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
+ boolean requiresUnlock, int bannerResource, int uid) {
this.mService = info;
this.mDescription = description;
- this.mAidGroups = aidGroups;
- this.mAids = new ArrayList<String>();
- this.mCategoryToGroup = new HashMap<String, AidGroup>();
+ this.mStaticAidGroups = new HashMap<String, AidGroup>();
+ this.mDynamicAidGroups = new HashMap<String, AidGroup>();
this.mOnHost = onHost;
this.mRequiresDeviceUnlock = requiresUnlock;
- for (AidGroup aidGroup : aidGroups) {
- this.mCategoryToGroup.put(aidGroup.category, aidGroup);
- this.mAids.addAll(aidGroup.aids);
+ for (AidGroup aidGroup : staticAidGroups) {
+ this.mStaticAidGroups.put(aidGroup.category, aidGroup);
+ }
+ for (AidGroup aidGroup : dynamicAidGroups) {
+ this.mDynamicAidGroups.put(aidGroup.category, aidGroup);
}
this.mBannerResourceId = bannerResource;
+ this.mUid = uid;
}
- public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost)
- throws XmlPullParserException, IOException {
+ public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost) throws
+ XmlPullParserException, IOException {
ServiceInfo si = info.serviceInfo;
XmlResourceParser parser = null;
try {
@@ -163,10 +168,10 @@
sa.recycle();
}
- mAidGroups = new ArrayList<AidGroup>();
- mCategoryToGroup = new HashMap<String, AidGroup>();
- mAids = new ArrayList<String>();
+ mStaticAidGroups = new HashMap<String, AidGroup>();
+ mDynamicAidGroups = new HashMap<String, AidGroup>();
mOnHost = onHost;
+
final int depth = parser.getDepth();
AidGroup currentGroup = null;
@@ -179,14 +184,14 @@
final TypedArray groupAttrs = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AidGroup);
// Get category of AID group
- String groupDescription = groupAttrs.getString(
- com.android.internal.R.styleable.AidGroup_description);
String groupCategory = groupAttrs.getString(
com.android.internal.R.styleable.AidGroup_category);
+ String groupDescription = groupAttrs.getString(
+ com.android.internal.R.styleable.AidGroup_description);
if (!CardEmulation.CATEGORY_PAYMENT.equals(groupCategory)) {
groupCategory = CardEmulation.CATEGORY_OTHER;
}
- currentGroup = mCategoryToGroup.get(groupCategory);
+ currentGroup = mStaticAidGroups.get(groupCategory);
if (currentGroup != null) {
if (!CardEmulation.CATEGORY_OTHER.equals(groupCategory)) {
Log.e(TAG, "Not allowing multiple aid-groups in the " +
@@ -200,9 +205,8 @@
} else if (eventType == XmlPullParser.END_TAG && "aid-group".equals(tagName) &&
currentGroup != null) {
if (currentGroup.aids.size() > 0) {
- if (!mCategoryToGroup.containsKey(currentGroup.category)) {
- mAidGroups.add(currentGroup);
- mCategoryToGroup.put(currentGroup.category, currentGroup);
+ if (!mStaticAidGroups.containsKey(currentGroup.category)) {
+ mStaticAidGroups.put(currentGroup.category, currentGroup);
}
} else {
Log.e(TAG, "Not adding <aid-group> with empty or invalid AIDs");
@@ -216,7 +220,6 @@
toUpperCase();
if (isValidAid(aid) && !currentGroup.aids.contains(aid)) {
currentGroup.aids.add(aid);
- mAids.add(aid);
} else {
Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
}
@@ -228,6 +231,8 @@
} finally {
if (parser != null) parser.close();
}
+ // Set uid
+ mUid = si.applicationInfo.uid;
}
public ComponentName getComponent() {
@@ -235,16 +240,58 @@
mService.serviceInfo.name);
}
+ /**
+ * Returns a consolidated list of AIDs from the AID groups
+ * registered by this service. Note that if a service has both
+ * a static (manifest-based) AID group for a category and a dynamic
+ * AID group, only the dynamically registered AIDs will be returned
+ * for that category.
+ * @return List of AIDs registered by the service
+ */
public ArrayList<String> getAids() {
- return mAids;
+ final ArrayList<String> aids = new ArrayList<String>();
+ for (AidGroup group : getAidGroups()) {
+ aids.addAll(group.aids);
+ }
+ return aids;
}
+ /**
+ * Returns the registered AID group for this category.
+ */
+ public AidGroup getDynamicAidGroupForCategory(String category) {
+ return mDynamicAidGroups.get(category);
+ }
+
+ public boolean removeDynamicAidGroupForCategory(String category) {
+ return (mDynamicAidGroups.remove(category) != null);
+ }
+
+ /**
+ * Returns a consolidated list of AID groups
+ * registered by this service. Note that if a service has both
+ * a static (manifest-based) AID group for a category and a dynamic
+ * AID group, only the dynamically registered AID group will be returned
+ * for that category.
+ * @return List of AIDs registered by the service
+ */
public ArrayList<AidGroup> getAidGroups() {
- return mAidGroups;
+ final ArrayList<AidGroup> groups = new ArrayList<AidGroup>();
+ for (Map.Entry<String, AidGroup> entry : mDynamicAidGroups.entrySet()) {
+ groups.add(entry.getValue());
+ }
+ for (Map.Entry<String, AidGroup> entry : mStaticAidGroups.entrySet()) {
+ if (!mDynamicAidGroups.containsKey(entry.getKey())) {
+ // Consolidate AID groups - don't return static ones
+ // if a dynamic group exists for the category.
+ groups.add(entry.getValue());
+ }
+ }
+ return groups;
}
public boolean hasCategory(String category) {
- return mCategoryToGroup.containsKey(category);
+ return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
}
public boolean isOnHost() {
@@ -259,6 +306,14 @@
return mDescription;
}
+ public int getUid() {
+ return mUid;
+ }
+
+ public void setOrReplaceDynamicAidGroup(AidGroup aidGroup) {
+ mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
+ }
+
public CharSequence loadLabel(PackageManager pm) {
return mService.loadLabel(pm);
}
@@ -304,8 +359,12 @@
StringBuilder out = new StringBuilder("ApduService: ");
out.append(getComponent());
out.append(", description: " + mDescription);
- out.append(", AID Groups: ");
- for (AidGroup aidGroup : mAidGroups) {
+ out.append(", Static AID Groups: ");
+ for (AidGroup aidGroup : mStaticAidGroups.values()) {
+ out.append(aidGroup.toString());
+ }
+ out.append(", Dynamic AID Groups: ");
+ for (AidGroup aidGroup : mDynamicAidGroups.values()) {
out.append(aidGroup.toString());
}
return out.toString();
@@ -336,12 +395,17 @@
mService.writeToParcel(dest, flags);
dest.writeString(mDescription);
dest.writeInt(mOnHost ? 1 : 0);
- dest.writeInt(mAidGroups.size());
- if (mAidGroups.size() > 0) {
- dest.writeTypedList(mAidGroups);
+ dest.writeInt(mStaticAidGroups.size());
+ if (mStaticAidGroups.size() > 0) {
+ dest.writeTypedList(new ArrayList<AidGroup>(mStaticAidGroups.values()));
+ }
+ dest.writeInt(mDynamicAidGroups.size());
+ if (mDynamicAidGroups.size() > 0) {
+ dest.writeTypedList(new ArrayList<AidGroup>(mDynamicAidGroups.values()));
}
dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
dest.writeInt(mBannerResourceId);
+ dest.writeInt(mUid);
};
public static final Parcelable.Creator<ApduServiceInfo> CREATOR =
@@ -351,14 +415,21 @@
ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
String description = source.readString();
boolean onHost = (source.readInt() != 0) ? true : false;
- ArrayList<AidGroup> aidGroups = new ArrayList<AidGroup>();
- int numGroups = source.readInt();
- if (numGroups > 0) {
- source.readTypedList(aidGroups, AidGroup.CREATOR);
+ ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
+ int numStaticGroups = source.readInt();
+ if (numStaticGroups > 0) {
+ source.readTypedList(staticAidGroups, AidGroup.CREATOR);
+ }
+ ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>();
+ int numDynamicGroups = source.readInt();
+ if (numDynamicGroups > 0) {
+ source.readTypedList(dynamicAidGroups, AidGroup.CREATOR);
}
boolean requiresUnlock = (source.readInt() != 0) ? true : false;
int bannerResource = source.readInt();
- return new ApduServiceInfo(info, onHost, description, aidGroups, requiresUnlock, bannerResource);
+ int uid = source.readInt();
+ return new ApduServiceInfo(info, onHost, description, staticAidGroups,
+ dynamicAidGroups, requiresUnlock, bannerResource, uid);
}
@Override
@@ -367,76 +438,22 @@
}
};
- public static class AidGroup implements Parcelable {
- final ArrayList<String> aids;
- final String category;
- final String description;
-
- AidGroup(ArrayList<String> aids, String category, String description) {
- this.aids = aids;
- this.category = category;
- this.description = description;
- }
-
- AidGroup(String category, String description) {
- this.aids = new ArrayList<String>();
- this.category = category;
- this.description = description;
- }
-
- public String getCategory() {
- return category;
- }
-
- public ArrayList<String> getAids() {
- return aids;
- }
-
- @Override
- public String toString() {
- StringBuilder out = new StringBuilder("Category: " + category +
- ", description: " + description + ", AIDs:");
- for (String aid : aids) {
- out.append(aid);
- out.append(", ");
- }
- return out.toString();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(category);
- dest.writeString(description);
- dest.writeInt(aids.size());
- if (aids.size() > 0) {
- dest.writeStringList(aids);
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(" " + getComponent() +
+ " (Description: " + getDescription() + ")");
+ pw.println(" Static AID groups:");
+ for (AidGroup group : mStaticAidGroups.values()) {
+ pw.println(" Category: " + group.category);
+ for (String aid : group.aids) {
+ pw.println(" AID: " + aid);
}
}
-
- public static final Parcelable.Creator<ApduServiceInfo.AidGroup> CREATOR =
- new Parcelable.Creator<ApduServiceInfo.AidGroup>() {
-
- @Override
- public AidGroup createFromParcel(Parcel source) {
- String category = source.readString();
- String description = source.readString();
- int listSize = source.readInt();
- ArrayList<String> aidList = new ArrayList<String>();
- if (listSize > 0) {
- source.readStringList(aidList);
- }
- return new AidGroup(aidList, category, description);
+ pw.println(" Dynamic AID groups:");
+ for (AidGroup group : mDynamicAidGroups.values()) {
+ pw.println(" Category: " + group.category);
+ for (String aid : group.aids) {
+ pw.println(" AID: " + aid);
}
-
- @Override
- public AidGroup[] newArray(int size) {
- return new AidGroup[size];
- }
- };
+ }
}
}
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 58d9616..41f039c 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -168,6 +168,10 @@
if (manager == null) {
// Get card emu service
INfcCardEmulation service = adapter.getCardEmulationService();
+ if (service == null) {
+ Log.e(TAG, "This device does not implement the INfcCardEmulation interface.");
+ throw new UnsupportedOperationException();
+ }
manager = new CardEmulation(context, service);
sCardEmus.put(context, manager);
}
@@ -271,6 +275,109 @@
}
/**
+ * Registers a group of AIDs for the specified service.
+ *
+ * <p>If an AID group for that category was previously
+ * registered for this service (either statically
+ * through the manifest, or dynamically by using this API),
+ * that AID group will be replaced with this one.
+ *
+ * <p>Note that you can only register AIDs for a service that
+ * is running under the same UID as you are. Typically
+ * this means you need to call this from the same
+ * package as the service itself, though UIDs can also
+ * be shared between packages using shared UIDs.
+ *
+ * @param service The component name of the service
+ * @param aidGroup The group of AIDs to be registered
+ * @return whether the registration was successful.
+ */
+ public boolean registerAidGroupForService(ComponentName service, AidGroup aidGroup) {
+ try {
+ return sService.registerAidGroupForService(UserHandle.myUserId(), service, aidGroup);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.registerAidGroupForService(UserHandle.myUserId(), service,
+ aidGroup);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Retrieves the currently registered AID group for the specified
+ * category for a service.
+ *
+ * <p>Note that this will only return AID groups that were dynamically
+ * registered using {@link #registerAidGroupForService(ComponentName, AidGroup)}
+ * method. It will *not* return AID groups that were statically registered
+ * in the manifest.
+ *
+ * @param service The component name of the service
+ * @param category The category of the AID group to be returned, e.g. {@link #CATEGORY_PAYMENT}
+ * @return The AID group, or null if it couldn't be found
+ */
+ public AidGroup getAidGroupForService(ComponentName service, String category) {
+ try {
+ return sService.getAidGroupForService(UserHandle.myUserId(), service, category);
+ } catch (RemoteException e) {
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return null;
+ }
+ try {
+ return sService.getAidGroupForService(UserHandle.myUserId(), service, category);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Removes a registered AID group for the specified category for the
+ * service provided.
+ *
+ * <p>Note that this will only remove AID groups that were dynamically
+ * registered using the {@link #registerAidGroupForService(ComponentName, AidGroup)}
+ * method. It will *not* remove AID groups that were statically registered in
+ * the manifest. If a dynamically registered AID group is removed using
+ * this method, and a statically registered AID group for the same category
+ * exists in the manifest, that AID group will become active again.
+ *
+ * @param service The component name of the service
+ * @param category The category of the AID group to be removed, e.g. {@link #CATEGORY_PAYMENT}
+ * @return whether the group was successfully removed.
+ */
+ public boolean removeAidGroupForService(ComponentName service, String category) {
+ try {
+ return sService.removeAidGroupForService(UserHandle.myUserId(), service, category);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.removeAidGroupForService(UserHandle.myUserId(), service, category);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
* @hide
*/
public boolean setDefaultServiceForCategory(ComponentName service, String category) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 426f21e..f05ddde 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -130,8 +130,8 @@
// NOTE: Update this list if you add/change any stats above.
// These characters are supposed to represent "total", "last", "current",
// and "unplugged". They were shortened for efficiency sake.
- private static final String[] STAT_NAMES = { "t", "l", "c", "u" };
-
+ private static final String[] STAT_NAMES = { "l", "c", "u" };
+
/**
* Bump the version on this if the checkin format changes.
*/
@@ -186,7 +186,7 @@
* Returns the count associated with this Counter for the
* selected type of statistics.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
*/
public abstract int getCountLocked(int which);
@@ -205,7 +205,7 @@
* Returns the count associated with this Counter for the
* selected type of statistics.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
*/
public abstract long getCountLocked(int which);
@@ -224,7 +224,7 @@
* Returns the count associated with this Timer for the
* selected type of statistics.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
*/
public abstract int getCountLocked(int which);
@@ -233,7 +233,7 @@
* selected type of statistics.
*
* @param elapsedRealtimeUs current elapsed realtime of system in microseconds
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
* @return a time in microseconds
*/
public abstract long getTotalTimeLocked(long elapsedRealtimeUs, int which);
@@ -385,27 +385,27 @@
/**
* Returns the total time (in 1/100 sec) spent executing in user code.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long getUserTime(int which);
/**
* Returns the total time (in 1/100 sec) spent executing in system code.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long getSystemTime(int which);
/**
* Returns the number of times the process has been started.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract int getStarts(int which);
/**
* Returns the cpu time spent in microseconds while the process was in the foreground.
- * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @return foreground cpu time in microseconds
*/
public abstract long getForegroundTime(int which);
@@ -414,7 +414,7 @@
* Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
* @param speedStep the index of the CPU speed. This is not the actual speed of the
* CPU.
- * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @see BatteryStats#getCpuSpeedSteps()
*/
public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
@@ -433,7 +433,7 @@
* Returns the number of times this package has done something that could wake up the
* device from sleep.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract int getWakeups(int which);
@@ -451,7 +451,7 @@
* Returns the amount of time spent started.
*
* @param batteryUptime elapsed uptime on battery in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @return
*/
public abstract long getStartTime(long batteryUptime, int which);
@@ -459,14 +459,14 @@
/**
* Returns the total number of times startService() has been called.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract int getStarts(int which);
/**
* Returns the total number times the service has been launched.
*
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract int getLaunches(int which);
}
@@ -1285,7 +1285,7 @@
* Returns the total, last, or current battery uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeBatteryUptime(long curTime, int which);
@@ -1293,7 +1293,7 @@
* Returns the total, last, or current battery realtime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeBatteryRealtime(long curTime, int which);
@@ -1301,7 +1301,7 @@
* Returns the total, last, or current battery screen off uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeBatteryScreenOffUptime(long curTime, int which);
@@ -1309,7 +1309,7 @@
* Returns the total, last, or current battery screen off realtime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeBatteryScreenOffRealtime(long curTime, int which);
@@ -1317,18 +1317,38 @@
* Returns the total, last, or current uptime in microseconds.
*
* @param curTime the current elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeUptime(long curTime, int which);
/**
* Returns the total, last, or current realtime in microseconds.
- * *
+ *
* @param curTime the current elapsed realtime in microseconds.
- * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
public abstract long computeRealtime(long curTime, int which);
-
+
+ /**
+ * Compute an approximation for how much run time (in microseconds) is remaining on
+ * the battery. Returns -1 if no time can be computed: either there is not
+ * enough current data to make a decision, or the battery is currently
+ * charging.
+ *
+ * @param curTime The current elepsed realtime in microseconds.
+ */
+ public abstract long computeBatteryTimeRemaining(long curTime);
+
+ /**
+ * Compute an approximation for how much time (in microseconds) remains until the battery
+ * is fully charged. Returns -1 if no time can be computed: either there is not
+ * enough current data to make a decision, or the battery is currently
+ * discharging.
+ *
+ * @param curTime The current elepsed realtime in microseconds.
+ */
+ public abstract long computeChargeTimeRemaining(long curTime);
+
public abstract Map<String, ? extends LongCounter> getWakeupReasonStats();
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
@@ -1430,7 +1450,7 @@
* @param timer a Timer object contining the wakelock times.
* @param elapsedRealtimeUs the current on-battery time in microseconds.
* @param name the name of the wakelock.
- * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @param linePrefix a String to be prepended to each line of output.
* @return the line prefix
*/
@@ -1464,7 +1484,7 @@
* @param timer a Timer object contining the wakelock times.
* @param elapsedRealtimeUs the current time in microseconds.
* @param name the name of the wakelock.
- * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT.
+ * @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @param linePrefix a String to be prepended to each line of output.
* @return the line prefix
*/
@@ -1682,7 +1702,7 @@
}
}
- BatteryStatsHelper helper = new BatteryStatsHelper(context);
+ BatteryStatsHelper helper = new BatteryStatsHelper(context, false);
helper.create(this);
helper.refreshStats(which, UserHandle.USER_ALL);
List<BatterySipper> sippers = helper.getUsageList();
@@ -1929,6 +1949,8 @@
final long whichBatteryScreenOffUptime = computeBatteryScreenOffUptime(rawUptime, which);
final long whichBatteryScreenOffRealtime = computeBatteryScreenOffRealtime(rawRealtime,
which);
+ final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime);
+ final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime);
StringBuilder sb = new StringBuilder(128);
@@ -1963,7 +1985,20 @@
sb.append("realtime, ");
formatTimeMs(sb, totalUptime / 1000);
sb.append("uptime");
- pw.println(sb.toString());
+ if (batteryTimeRemaining >= 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Battery time remaining: ");
+ formatTimeMs(sb, batteryTimeRemaining / 1000);
+ pw.println(sb.toString());
+ }
+ if (chargeTimeRemaining >= 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Charge time remaining: ");
+ formatTimeMs(sb, chargeTimeRemaining / 1000);
+ pw.println(sb.toString());
+ }
pw.print(" Start clock time: ");
pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
@@ -2268,7 +2303,7 @@
pw.println();
}
- BatteryStatsHelper helper = new BatteryStatsHelper(context);
+ BatteryStatsHelper helper = new BatteryStatsHelper(context, false);
helper.create(this);
helper.refreshStats(which, UserHandle.USER_ALL);
List<BatterySipper> sippers = helper.getUsageList();
@@ -2861,29 +2896,21 @@
int oldTemp = -1;
int oldVolt = -1;
long lastTime = -1;
+ long firstTime = -1;
- public void printNextItem(PrintWriter pw, HistoryItem rec, long now, boolean checkin,
+ public void printNextItem(PrintWriter pw, HistoryItem rec, long baseTime, boolean checkin,
boolean verbose) {
if (!checkin) {
pw.print(" ");
- if (now >= 0) {
- TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
- } else {
- TimeUtils.formatDuration(rec.time, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
- }
+ TimeUtils.formatDuration(rec.time - baseTime, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
pw.print(" (");
pw.print(rec.numReadInts);
pw.print(") ");
} else {
if (lastTime < 0) {
- if (now >= 0) {
- pw.print("@");
- pw.print(rec.time-now);
- } else {
- pw.print(rec.time);
- }
+ pw.print(rec.time - baseTime);
} else {
- pw.print(rec.time-lastTime);
+ pw.print(rec.time - lastTime);
}
lastTime = rec.time;
}
@@ -3132,10 +3159,27 @@
pw.println("):");
HistoryPrinter hprinter = new HistoryPrinter();
long lastTime = -1;
+ long baseTime = -1;
+ boolean printed = false;
while (getNextHistoryLocked(rec)) {
lastTime = rec.time;
+ if (baseTime < 0) {
+ baseTime = lastTime;
+ }
if (rec.time >= histStart) {
- hprinter.printNextItem(pw, rec, histStart >= 0 ? -1 : now, false,
+ if (histStart >= 0 && !printed) {
+ if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
+ printed = true;
+ } else if (rec.currentTime != 0) {
+ printed = true;
+ byte cmd = rec.cmd;
+ rec.cmd = HistoryItem.CMD_CURRENT_TIME;
+ hprinter.printNextItem(pw, rec, baseTime, false,
+ (flags&DUMP_VERBOSE) != 0);
+ rec.cmd = cmd;
+ }
+ }
+ hprinter.printNextItem(pw, rec, baseTime, false,
(flags&DUMP_VERBOSE) != 0);
}
}
@@ -3152,8 +3196,12 @@
try {
pw.println("Old battery History:");
HistoryPrinter hprinter = new HistoryPrinter();
+ long baseTime = -1;
while (getNextOldHistoryLocked(rec)) {
- hprinter.printNextItem(pw, rec, now, false, (flags&DUMP_VERBOSE) != 0);
+ if (baseTime < 0) {
+ baseTime = rec.time;
+ }
+ hprinter.printNextItem(pw, rec, baseTime, false, (flags&DUMP_VERBOSE) != 0);
}
pw.println();
} finally {
@@ -3226,20 +3274,42 @@
pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
pw.print(HISTORY_STRING_POOL); pw.print(',');
pw.print(i);
- pw.print(',');
- pw.print(getHistoryTagPoolString(i));
- pw.print(',');
+ pw.print(",");
pw.print(getHistoryTagPoolUid(i));
+ pw.print(",\"");
+ String str = getHistoryTagPoolString(i);
+ str = str.replace("\\", "\\\\");
+ str = str.replace("\"", "\\\"");
+ pw.print(str);
+ pw.print("\"");
pw.println();
}
HistoryPrinter hprinter = new HistoryPrinter();
long lastTime = -1;
+ long baseTime = -1;
+ boolean printed = false;
while (getNextHistoryLocked(rec)) {
lastTime = rec.time;
+ if (baseTime < 0) {
+ baseTime = lastTime;
+ }
if (rec.time >= histStart) {
+ if (histStart >= 0 && !printed) {
+ if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
+ printed = true;
+ } else if (rec.currentTime != 0) {
+ printed = true;
+ byte cmd = rec.cmd;
+ rec.cmd = HistoryItem.CMD_CURRENT_TIME;
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(HISTORY_DATA); pw.print(',');
+ hprinter.printNextItem(pw, rec, baseTime, true, false);
+ rec.cmd = cmd;
+ }
+ }
pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
pw.print(HISTORY_DATA); pw.print(',');
- hprinter.printNextItem(pw, rec, histStart >= 0 ? -1 : now, true, false);
+ hprinter.printNextItem(pw, rec, baseTime, true, false);
}
}
if (histStart >= 0) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 63e15a9..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";
@@ -118,14 +123,22 @@
*/
public static final String CODENAME = getString("ro.build.version.codename");
+ private static final String[] ALL_CODENAMES
+ = getString("ro.build.version.all_codenames").split(",");
+
/**
- * The SDK version to use when accessing resources.
- * Use the current SDK version code. If we are a development build,
- * also allow the previous SDK version + 1.
* @hide
*/
- public static final int RESOURCES_SDK_INT = SDK_INT
- + ("REL".equals(CODENAME) ? 0 : 1);
+ public static final String[] ACTIVE_CODENAMES = "REL".equals(ALL_CODENAMES[0])
+ ? new String[0] : ALL_CODENAMES;
+
+ /**
+ * The SDK version to use when accessing resources.
+ * Use the current SDK version code. For every active development codename
+ * we are operating under, we bump the assumed resource platform version by 1.
+ * @hide
+ */
+ public static final int RESOURCES_SDK_INT = SDK_INT + ACTIVE_CODENAMES.length;
}
/**
@@ -487,7 +500,7 @@
* new changes in behavior:</p>
* <ul>
* <li> {@link android.content.Context#bindService Context.bindService} now
- * requires an explicit Intent, and will throw an exception if given an explicit
+ * requires an explicit Intent, and will throw an exception if given an implicit
* Intent.</li>
* </ul>
*/
@@ -501,7 +514,43 @@
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/os/Bundle.java b/core/java/android/os/Bundle.java
index af57507..c85e418 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -17,7 +17,6 @@
package android.os;
import android.util.ArrayMap;
-import android.util.Log;
import android.util.SparseArray;
import java.io.Serializable;
@@ -29,47 +28,25 @@
* A mapping from String values to various Parcelable types.
*
*/
-public final class Bundle implements Parcelable, Cloneable {
- private static final String TAG = "Bundle";
- static final boolean DEBUG = false;
+public final class Bundle extends CommonBundle {
public static final Bundle EMPTY;
-
- static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
static final Parcel EMPTY_PARCEL;
static {
EMPTY = new Bundle();
EMPTY.mMap = ArrayMap.EMPTY;
- EMPTY_PARCEL = Parcel.obtain();
+ EMPTY_PARCEL = CommonBundle.EMPTY_PARCEL;
}
- // Invariant - exactly one of mMap / mParcelledData will be null
- // (except inside a call to unparcel)
-
- /* package */ ArrayMap<String, Object> mMap = null;
-
- /*
- * If mParcelledData is non-null, then mMap will be null and the
- * data are stored as a Parcel containing a Bundle. When the data
- * are unparcelled, mParcelledData willbe set to null.
- */
- /* package */ Parcel mParcelledData = null;
-
private boolean mHasFds = false;
private boolean mFdsKnown = true;
private boolean mAllowFds = true;
/**
- * The ClassLoader used when unparcelling data from mParcelledData.
- */
- private ClassLoader mClassLoader;
-
- /**
* Constructs a new, empty Bundle.
*/
public Bundle() {
- mMap = new ArrayMap<String, Object>();
- mClassLoader = getClass().getClassLoader();
+ super();
}
/**
@@ -79,11 +56,17 @@
* @param parcelledData a Parcel containing a Bundle
*/
Bundle(Parcel parcelledData) {
- readFromParcel(parcelledData);
+ super(parcelledData);
+
+ mHasFds = mParcelledData.hasFileDescriptors();
+ mFdsKnown = true;
}
/* package */ Bundle(Parcel parcelledData, int length) {
- readFromParcelInner(parcelledData, length);
+ super(parcelledData, length);
+
+ mHasFds = mParcelledData.hasFileDescriptors();
+ mFdsKnown = true;
}
/**
@@ -94,8 +77,7 @@
* inside of the Bundle.
*/
public Bundle(ClassLoader loader) {
- mMap = new ArrayMap<String, Object>();
- mClassLoader = loader;
+ super(loader);
}
/**
@@ -105,8 +87,7 @@
* @param capacity the initial capacity of the Bundle
*/
public Bundle(int capacity) {
- mMap = new ArrayMap<String, Object>(capacity);
- mClassLoader = getClass().getClassLoader();
+ super(capacity);
}
/**
@@ -116,27 +97,20 @@
* @param b a Bundle to be copied.
*/
public Bundle(Bundle b) {
- if (b.mParcelledData != null) {
- if (b.mParcelledData == EMPTY_PARCEL) {
- mParcelledData = EMPTY_PARCEL;
- } else {
- mParcelledData = Parcel.obtain();
- mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
- mParcelledData.setDataPosition(0);
- }
- } else {
- mParcelledData = null;
- }
-
- if (b.mMap != null) {
- mMap = new ArrayMap<String, Object>(b.mMap);
- } else {
- mMap = null;
- }
+ super(b);
mHasFds = b.mHasFds;
mFdsKnown = b.mFdsKnown;
- mClassLoader = b.mClassLoader;
+ }
+
+ /**
+ * Constructs a Bundle containing a copy of the mappings from the given
+ * PersistableBundle.
+ *
+ * @param b a Bundle to be copied.
+ */
+ public Bundle(PersistableBundle b) {
+ super(b);
}
/**
@@ -145,37 +119,17 @@
* @hide
*/
public static Bundle forPair(String key, String value) {
- // TODO: optimize this case.
Bundle b = new Bundle(1);
b.putString(key, value);
return b;
}
/**
- * TODO: optimize this later (getting just the value part of a Bundle
- * with a single pair) once Bundle.forPair() above is implemented
- * with a special single-value Map implementation/serialization.
- *
- * Note: value in single-pair Bundle may be null.
- *
* @hide
*/
+ @Override
public String getPairValue() {
- unparcel();
- int size = mMap.size();
- if (size > 1) {
- Log.w(TAG, "getPairValue() used on Bundle with multiple pairs.");
- }
- if (size == 0) {
- return null;
- }
- Object o = mMap.valueAt(0);
- try {
- return (String) o;
- } catch (ClassCastException e) {
- typeWarning("getPairValue()", o, "String", e);
- return null;
- }
+ return super.getPairValue();
}
/**
@@ -184,15 +138,17 @@
* @param loader An explicit ClassLoader to use when instantiating objects
* inside of the Bundle.
*/
+ @Override
public void setClassLoader(ClassLoader loader) {
- mClassLoader = loader;
+ super.setClassLoader(loader);
}
/**
* Return the ClassLoader currently associated with this Bundle.
*/
+ @Override
public ClassLoader getClassLoader() {
- return mClassLoader;
+ return super.getClassLoader();
}
/** @hide */
@@ -212,52 +168,11 @@
}
/**
- * If the underlying data are stored as a Parcel, unparcel them
- * using the currently assigned class loader.
- */
- /* package */ synchronized void unparcel() {
- if (mParcelledData == null) {
- if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
- + ": no parcelled data");
- return;
- }
-
- if (mParcelledData == EMPTY_PARCEL) {
- if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
- + ": empty");
- if (mMap == null) {
- mMap = new ArrayMap<String, Object>(1);
- } else {
- mMap.erase();
- }
- mParcelledData = null;
- return;
- }
-
- int N = mParcelledData.readInt();
- if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
- + ": reading " + N + " maps");
- if (N < 0) {
- return;
- }
- if (mMap == null) {
- mMap = new ArrayMap<String, Object>(N);
- } else {
- mMap.erase();
- mMap.ensureCapacity(N);
- }
- mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
- mParcelledData.recycle();
- mParcelledData = null;
- if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
- + " final map: " + mMap);
- }
-
- /**
* @hide
*/
+ @Override
public boolean isParcelled() {
- return mParcelledData != null;
+ return super.isParcelled();
}
/**
@@ -265,25 +180,26 @@
*
* @return the number of mappings as an int.
*/
+ @Override
public int size() {
- unparcel();
- return mMap.size();
+ return super.size();
}
/**
* Returns true if the mapping of this Bundle is empty, false otherwise.
*/
+ @Override
public boolean isEmpty() {
- unparcel();
- return mMap.isEmpty();
+ return super.isEmpty();
}
/**
* Removes all elements from the mapping of this Bundle.
*/
+ @Override
public void clear() {
- unparcel();
- mMap.clear();
+ super.clear();
+
mHasFds = false;
mFdsKnown = true;
}
@@ -295,9 +211,9 @@
* @param key a String key
* @return true if the key is part of the mapping, false otherwise
*/
+ @Override
public boolean containsKey(String key) {
- unparcel();
- return mMap.containsKey(key);
+ return super.containsKey(key);
}
/**
@@ -306,9 +222,9 @@
* @param key a String key
* @return an Object, or null
*/
+ @Override
public Object get(String key) {
- unparcel();
- return mMap.get(key);
+ return super.get(key);
}
/**
@@ -316,24 +232,33 @@
*
* @param key a String key
*/
+ @Override
public void remove(String key) {
- unparcel();
- mMap.remove(key);
+ super.remove(key);
}
/**
* Inserts all mappings from the given Bundle into this Bundle.
*
- * @param map a Bundle
+ * @param bundle a Bundle
*/
- public void putAll(Bundle map) {
+ public void putAll(Bundle bundle) {
unparcel();
- map.unparcel();
- mMap.putAll(map.mMap);
+ bundle.unparcel();
+ mMap.putAll(bundle.mMap);
// fd state is now known if and only if both bundles already knew
- mHasFds |= map.mHasFds;
- mFdsKnown = mFdsKnown && map.mFdsKnown;
+ mHasFds |= bundle.mHasFds;
+ mFdsKnown = mFdsKnown && bundle.mFdsKnown;
+ }
+
+ /**
+ * Inserts all mappings from the given PersistableBundle into this Bundle.
+ *
+ * @param bundle a PersistableBundle
+ */
+ public void putAll(PersistableBundle bundle) {
+ super.putAll(bundle);
}
/**
@@ -341,9 +266,9 @@
*
* @return a Set of String keys
*/
+ @Override
public Set<String> keySet() {
- unparcel();
- return mMap.keySet();
+ return super.keySet();
}
/**
@@ -352,7 +277,7 @@
public boolean hasFileDescriptors() {
if (!mFdsKnown) {
boolean fdFound = false; // keep going until we find one or run out of data
-
+
if (mParcelledData != null) {
if (mParcelledData.hasFileDescriptors()) {
fdFound = true;
@@ -390,8 +315,7 @@
ArrayList array = (ArrayList) obj;
// an ArrayList here might contain either Strings or
// Parcelables; only look inside for Parcelables
- if ((array.size() > 0)
- && (array.get(0) instanceof Parcelable)) {
+ if (!array.isEmpty() && (array.get(0) instanceof Parcelable)) {
for (int n = array.size() - 1; n >= 0; n--) {
Parcelable p = (Parcelable) array.get(n);
if (p != null && ((p.describeContents()
@@ -410,7 +334,7 @@
}
return mHasFds;
}
-
+
/**
* Inserts a Boolean value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
@@ -418,9 +342,9 @@
* @param key a String, or null
* @param value a Boolean, or null
*/
+ @Override
public void putBoolean(String key, boolean value) {
- unparcel();
- mMap.put(key, value);
+ super.putBoolean(key, value);
}
/**
@@ -430,9 +354,9 @@
* @param key a String, or null
* @param value a byte
*/
+ @Override
public void putByte(String key, byte value) {
- unparcel();
- mMap.put(key, value);
+ super.putByte(key, value);
}
/**
@@ -442,9 +366,9 @@
* @param key a String, or null
* @param value a char, or null
*/
+ @Override
public void putChar(String key, char value) {
- unparcel();
- mMap.put(key, value);
+ super.putChar(key, value);
}
/**
@@ -454,9 +378,9 @@
* @param key a String, or null
* @param value a short
*/
+ @Override
public void putShort(String key, short value) {
- unparcel();
- mMap.put(key, value);
+ super.putShort(key, value);
}
/**
@@ -466,9 +390,9 @@
* @param key a String, or null
* @param value an int, or null
*/
+ @Override
public void putInt(String key, int value) {
- unparcel();
- mMap.put(key, value);
+ super.putInt(key, value);
}
/**
@@ -478,9 +402,9 @@
* @param key a String, or null
* @param value a long
*/
+ @Override
public void putLong(String key, long value) {
- unparcel();
- mMap.put(key, value);
+ super.putLong(key, value);
}
/**
@@ -490,9 +414,9 @@
* @param key a String, or null
* @param value a float
*/
+ @Override
public void putFloat(String key, float value) {
- unparcel();
- mMap.put(key, value);
+ super.putFloat(key, value);
}
/**
@@ -502,9 +426,9 @@
* @param key a String, or null
* @param value a double
*/
+ @Override
public void putDouble(String key, double value) {
- unparcel();
- mMap.put(key, value);
+ super.putDouble(key, value);
}
/**
@@ -514,9 +438,9 @@
* @param key a String, or null
* @param value a String, or null
*/
+ @Override
public void putString(String key, String value) {
- unparcel();
- mMap.put(key, value);
+ super.putString(key, value);
}
/**
@@ -526,9 +450,9 @@
* @param key a String, or null
* @param value a CharSequence, or null
*/
+ @Override
public void putCharSequence(String key, CharSequence value) {
- unparcel();
- mMap.put(key, value);
+ super.putCharSequence(key, value);
}
/**
@@ -567,7 +491,7 @@
* @param value an ArrayList of Parcelable objects, or null
*/
public void putParcelableArrayList(String key,
- ArrayList<? extends Parcelable> value) {
+ ArrayList<? extends Parcelable> value) {
unparcel();
mMap.put(key, value);
mFdsKnown = false;
@@ -602,9 +526,9 @@
* @param key a String, or null
* @param value an ArrayList<Integer> object, or null
*/
+ @Override
public void putIntegerArrayList(String key, ArrayList<Integer> value) {
- unparcel();
- mMap.put(key, value);
+ super.putIntegerArrayList(key, value);
}
/**
@@ -614,9 +538,9 @@
* @param key a String, or null
* @param value an ArrayList<String> object, or null
*/
+ @Override
public void putStringArrayList(String key, ArrayList<String> value) {
- unparcel();
- mMap.put(key, value);
+ super.putStringArrayList(key, value);
}
/**
@@ -626,9 +550,9 @@
* @param key a String, or null
* @param value an ArrayList<CharSequence> object, or null
*/
+ @Override
public void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) {
- unparcel();
- mMap.put(key, value);
+ super.putCharSequenceArrayList(key, value);
}
/**
@@ -638,9 +562,9 @@
* @param key a String, or null
* @param value a Serializable object, or null
*/
+ @Override
public void putSerializable(String key, Serializable value) {
- unparcel();
- mMap.put(key, value);
+ super.putSerializable(key, value);
}
/**
@@ -650,9 +574,9 @@
* @param key a String, or null
* @param value a boolean array object, or null
*/
+ @Override
public void putBooleanArray(String key, boolean[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putBooleanArray(key, value);
}
/**
@@ -662,9 +586,9 @@
* @param key a String, or null
* @param value a byte array object, or null
*/
+ @Override
public void putByteArray(String key, byte[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putByteArray(key, value);
}
/**
@@ -674,9 +598,9 @@
* @param key a String, or null
* @param value a short array object, or null
*/
+ @Override
public void putShortArray(String key, short[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putShortArray(key, value);
}
/**
@@ -686,9 +610,9 @@
* @param key a String, or null
* @param value a char array object, or null
*/
+ @Override
public void putCharArray(String key, char[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putCharArray(key, value);
}
/**
@@ -698,9 +622,9 @@
* @param key a String, or null
* @param value an int array object, or null
*/
+ @Override
public void putIntArray(String key, int[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putIntArray(key, value);
}
/**
@@ -710,9 +634,9 @@
* @param key a String, or null
* @param value a long array object, or null
*/
+ @Override
public void putLongArray(String key, long[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putLongArray(key, value);
}
/**
@@ -722,9 +646,9 @@
* @param key a String, or null
* @param value a float array object, or null
*/
+ @Override
public void putFloatArray(String key, float[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putFloatArray(key, value);
}
/**
@@ -734,9 +658,9 @@
* @param key a String, or null
* @param value a double array object, or null
*/
+ @Override
public void putDoubleArray(String key, double[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putDoubleArray(key, value);
}
/**
@@ -746,9 +670,9 @@
* @param key a String, or null
* @param value a String array object, or null
*/
+ @Override
public void putStringArray(String key, String[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putStringArray(key, value);
}
/**
@@ -758,9 +682,9 @@
* @param key a String, or null
* @param value a CharSequence array object, or null
*/
+ @Override
public void putCharSequenceArray(String key, CharSequence[] value) {
- unparcel();
- mMap.put(key, value);
+ super.putCharSequenceArray(key, value);
}
/**
@@ -776,6 +700,17 @@
}
/**
+ * Inserts a PersistableBundle value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Bundle object, or null
+ */
+ public void putPersistableBundle(String key, PersistableBundle value) {
+ super.putPersistableBundle(key, value);
+ }
+
+ /**
* Inserts an {@link IBinder} value into the mapping of this Bundle, replacing
* any existing value for the given key. Either key or value may be null.
*
@@ -817,33 +752,9 @@
* @param key a String
* @return a boolean value
*/
+ @Override
public boolean getBoolean(String key) {
- unparcel();
- if (DEBUG) Log.d(TAG, "Getting boolean in "
- + Integer.toHexString(System.identityHashCode(this)));
- return getBoolean(key, false);
- }
-
- // Log a message if the value was non-null but not of the expected type
- private void typeWarning(String key, Object value, String className,
- Object defaultValue, ClassCastException e) {
- StringBuilder sb = new StringBuilder();
- sb.append("Key ");
- sb.append(key);
- sb.append(" expected ");
- sb.append(className);
- sb.append(" but value was a ");
- sb.append(value.getClass().getName());
- sb.append(". The default value ");
- sb.append(defaultValue);
- sb.append(" was returned.");
- Log.w(TAG, sb.toString());
- Log.w(TAG, "Attempt to cast generated internal exception:", e);
- }
-
- private void typeWarning(String key, Object value, String className,
- ClassCastException e) {
- typeWarning(key, value, className, "<null>", e);
+ return super.getBoolean(key);
}
/**
@@ -854,18 +765,9 @@
* @param defaultValue Value to return if key does not exist
* @return a boolean value
*/
+ @Override
public boolean getBoolean(String key, boolean defaultValue) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return defaultValue;
- }
- try {
- return (Boolean) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Boolean", defaultValue, e);
- return defaultValue;
- }
+ return super.getBoolean(key, defaultValue);
}
/**
@@ -875,9 +777,9 @@
* @param key a String
* @return a byte value
*/
+ @Override
public byte getByte(String key) {
- unparcel();
- return getByte(key, (byte) 0);
+ return super.getByte(key);
}
/**
@@ -888,18 +790,9 @@
* @param defaultValue Value to return if key does not exist
* @return a byte value
*/
+ @Override
public Byte getByte(String key, byte defaultValue) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return defaultValue;
- }
- try {
- return (Byte) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Byte", defaultValue, e);
- return defaultValue;
- }
+ return super.getByte(key, defaultValue);
}
/**
@@ -909,9 +802,9 @@
* @param key a String
* @return a char value
*/
+ @Override
public char getChar(String key) {
- unparcel();
- return getChar(key, (char) 0);
+ return super.getChar(key);
}
/**
@@ -922,18 +815,9 @@
* @param defaultValue Value to return if key does not exist
* @return a char value
*/
+ @Override
public char getChar(String key, char defaultValue) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return defaultValue;
- }
- try {
- return (Character) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Character", defaultValue, e);
- return defaultValue;
- }
+ return super.getChar(key, defaultValue);
}
/**
@@ -943,9 +827,9 @@
* @param key a String
* @return a short value
*/
+ @Override
public short getShort(String key) {
- unparcel();
- return getShort(key, (short) 0);
+ return super.getShort(key);
}
/**
@@ -956,18 +840,9 @@
* @param defaultValue Value to return if key does not exist
* @return a short value
*/
+ @Override
public short getShort(String key, short defaultValue) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return defaultValue;
- }
- try {
- return (Short) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Short", defaultValue, e);
- return defaultValue;
- }
+ return super.getShort(key, defaultValue);
}
/**
@@ -977,9 +852,9 @@
* @param key a String
* @return an int value
*/
+ @Override
public int getInt(String key) {
- unparcel();
- return getInt(key, 0);
+ return super.getInt(key);
}
/**
@@ -990,18 +865,9 @@
* @param defaultValue Value to return if key does not exist
* @return an int value
*/
+ @Override
public int getInt(String key, int defaultValue) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return defaultValue;
- }
- try {
- return (Integer) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Integer", defaultValue, e);
- return defaultValue;
- }
+ return super.getInt(key, defaultValue);
}
/**
@@ -1011,9 +877,9 @@
* @param key a String
* @return a long value
*/
+ @Override
public long getLong(String key) {
- unparcel();
- return getLong(key, 0L);
+ return super.getLong(key);
}
/**
@@ -1024,18 +890,9 @@
* @param defaultValue Value to return if key does not exist
* @return a long value
*/
+ @Override
public long getLong(String key, long defaultValue) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return defaultValue;
- }
- try {
- return (Long) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Long", defaultValue, e);
- return defaultValue;
- }
+ return super.getLong(key, defaultValue);
}
/**
@@ -1045,9 +902,9 @@
* @param key a String
* @return a float value
*/
+ @Override
public float getFloat(String key) {
- unparcel();
- return getFloat(key, 0.0f);
+ return super.getFloat(key);
}
/**
@@ -1058,18 +915,9 @@
* @param defaultValue Value to return if key does not exist
* @return a float value
*/
+ @Override
public float getFloat(String key, float defaultValue) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return defaultValue;
- }
- try {
- return (Float) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Float", defaultValue, e);
- return defaultValue;
- }
+ return super.getFloat(key, defaultValue);
}
/**
@@ -1079,9 +927,9 @@
* @param key a String
* @return a double value
*/
+ @Override
public double getDouble(String key) {
- unparcel();
- return getDouble(key, 0.0);
+ return super.getDouble(key);
}
/**
@@ -1092,18 +940,9 @@
* @param defaultValue Value to return if key does not exist
* @return a double value
*/
+ @Override
public double getDouble(String key, double defaultValue) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return defaultValue;
- }
- try {
- return (Double) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Double", defaultValue, e);
- return defaultValue;
- }
+ return super.getDouble(key, defaultValue);
}
/**
@@ -1114,15 +953,9 @@
* @param key a String, or null
* @return a String value, or null
*/
+ @Override
public String getString(String key) {
- unparcel();
- final Object o = mMap.get(key);
- try {
- return (String) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "String", e);
- return null;
- }
+ return super.getString(key);
}
/**
@@ -1134,9 +967,9 @@
* @return the String value associated with the given key, or defaultValue
* if no valid String object is currently mapped to that key.
*/
+ @Override
public String getString(String key, String defaultValue) {
- final String s = getString(key);
- return (s == null) ? defaultValue : s;
+ return super.getString(key, defaultValue);
}
/**
@@ -1147,15 +980,9 @@
* @param key a String, or null
* @return a CharSequence value, or null
*/
+ @Override
public CharSequence getCharSequence(String key) {
- unparcel();
- final Object o = mMap.get(key);
- try {
- return (CharSequence) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "CharSequence", e);
- return null;
- }
+ return super.getCharSequence(key);
}
/**
@@ -1167,9 +994,9 @@
* @return the CharSequence value associated with the given key, or defaultValue
* if no valid CharSequence object is currently mapped to that key.
*/
+ @Override
public CharSequence getCharSequence(String key, CharSequence defaultValue) {
- final CharSequence cs = getCharSequence(key);
- return (cs == null) ? defaultValue : cs;
+ return super.getCharSequence(key, defaultValue);
}
/**
@@ -1200,6 +1027,18 @@
* value is explicitly associated with the key.
*
* @param key a String, or null
+ * @return a PersistableBundle value, or null
+ */
+ public PersistableBundle getPersistableBundle(String key) {
+ return super.getPersistableBundle(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
* @return a Parcelable value, or null
*/
public <T extends Parcelable> T getParcelable(String key) {
@@ -1291,18 +1130,9 @@
* @param key a String, or null
* @return a Serializable value, or null
*/
+ @Override
public Serializable getSerializable(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (Serializable) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "Serializable", e);
- return null;
- }
+ return super.getSerializable(key);
}
/**
@@ -1313,18 +1143,9 @@
* @param key a String, or null
* @return an ArrayList<String> value, or null
*/
+ @Override
public ArrayList<Integer> getIntegerArrayList(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (ArrayList<Integer>) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "ArrayList<Integer>", e);
- return null;
- }
+ return super.getIntegerArrayList(key);
}
/**
@@ -1335,18 +1156,9 @@
* @param key a String, or null
* @return an ArrayList<String> value, or null
*/
+ @Override
public ArrayList<String> getStringArrayList(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (ArrayList<String>) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "ArrayList<String>", e);
- return null;
- }
+ return super.getStringArrayList(key);
}
/**
@@ -1357,18 +1169,9 @@
* @param key a String, or null
* @return an ArrayList<CharSequence> value, or null
*/
+ @Override
public ArrayList<CharSequence> getCharSequenceArrayList(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (ArrayList<CharSequence>) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "ArrayList<CharSequence>", e);
- return null;
- }
+ return super.getCharSequenceArrayList(key);
}
/**
@@ -1379,18 +1182,9 @@
* @param key a String, or null
* @return a boolean[] value, or null
*/
+ @Override
public boolean[] getBooleanArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (boolean[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "byte[]", e);
- return null;
- }
+ return super.getBooleanArray(key);
}
/**
@@ -1401,18 +1195,9 @@
* @param key a String, or null
* @return a byte[] value, or null
*/
+ @Override
public byte[] getByteArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (byte[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "byte[]", e);
- return null;
- }
+ return super.getByteArray(key);
}
/**
@@ -1423,18 +1208,9 @@
* @param key a String, or null
* @return a short[] value, or null
*/
+ @Override
public short[] getShortArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (short[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "short[]", e);
- return null;
- }
+ return super.getShortArray(key);
}
/**
@@ -1445,18 +1221,9 @@
* @param key a String, or null
* @return a char[] value, or null
*/
+ @Override
public char[] getCharArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (char[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "char[]", e);
- return null;
- }
+ return super.getCharArray(key);
}
/**
@@ -1467,18 +1234,9 @@
* @param key a String, or null
* @return an int[] value, or null
*/
+ @Override
public int[] getIntArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (int[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "int[]", e);
- return null;
- }
+ return super.getIntArray(key);
}
/**
@@ -1489,18 +1247,9 @@
* @param key a String, or null
* @return a long[] value, or null
*/
+ @Override
public long[] getLongArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (long[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "long[]", e);
- return null;
- }
+ return super.getLongArray(key);
}
/**
@@ -1511,18 +1260,9 @@
* @param key a String, or null
* @return a float[] value, or null
*/
+ @Override
public float[] getFloatArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (float[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "float[]", e);
- return null;
- }
+ return super.getFloatArray(key);
}
/**
@@ -1533,18 +1273,9 @@
* @param key a String, or null
* @return a double[] value, or null
*/
+ @Override
public double[] getDoubleArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (double[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "double[]", e);
- return null;
- }
+ return super.getDoubleArray(key);
}
/**
@@ -1555,18 +1286,9 @@
* @param key a String, or null
* @return a String[] value, or null
*/
+ @Override
public String[] getStringArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (String[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "String[]", e);
- return null;
- }
+ return super.getStringArray(key);
}
/**
@@ -1577,18 +1299,9 @@
* @param key a String, or null
* @return a CharSequence[] value, or null
*/
+ @Override
public CharSequence[] getCharSequenceArray(String key) {
- unparcel();
- Object o = mMap.get(key);
- if (o == null) {
- return null;
- }
- try {
- return (CharSequence[]) o;
- } catch (ClassCastException e) {
- typeWarning(key, o, "CharSequence[]", e);
- return null;
- }
+ return super.getCharSequenceArray(key);
}
/**
@@ -1641,10 +1354,12 @@
public static final Parcelable.Creator<Bundle> CREATOR =
new Parcelable.Creator<Bundle>() {
+ @Override
public Bundle createFromParcel(Parcel in) {
return in.readBundle();
}
+ @Override
public Bundle[] newArray(int size) {
return new Bundle[size];
}
@@ -1653,6 +1368,7 @@
/**
* Report the nature of this Parcelable's contents
*/
+ @Override
public int describeContents() {
int mask = 0;
if (hasFileDescriptors()) {
@@ -1660,44 +1376,17 @@
}
return mask;
}
-
+
/**
* Writes the Bundle contents to a Parcel, typically in order for
* it to be passed through an IBinder connection.
* @param parcel The parcel to copy this bundle to.
*/
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
try {
- if (mParcelledData != null) {
- if (mParcelledData == EMPTY_PARCEL) {
- parcel.writeInt(0);
- } else {
- int length = mParcelledData.dataSize();
- parcel.writeInt(length);
- parcel.writeInt(BUNDLE_MAGIC);
- parcel.appendFrom(mParcelledData, 0, length);
- }
- } else {
- // Special case for empty bundles.
- if (mMap == null || mMap.size() <= 0) {
- parcel.writeInt(0);
- return;
- }
- int lengthPos = parcel.dataPosition();
- parcel.writeInt(-1); // dummy, will hold length
- parcel.writeInt(BUNDLE_MAGIC);
-
- int startPos = parcel.dataPosition();
- parcel.writeArrayMapInternal(mMap);
- int endPos = parcel.dataPosition();
-
- // Backpatch length
- parcel.setDataPosition(lengthPos);
- int length = endPos - startPos;
- parcel.writeInt(length);
- parcel.setDataPosition(endPos);
- }
+ super.writeToParcelInner(parcel, flags);
} finally {
parcel.restoreAllowFds(oldAllowFds);
}
@@ -1709,41 +1398,8 @@
* @param parcel The parcel to overwrite this bundle from.
*/
public void readFromParcel(Parcel parcel) {
- int length = parcel.readInt();
- if (length < 0) {
- throw new RuntimeException("Bad length in parcel: " + length);
- }
- readFromParcelInner(parcel, length);
- }
-
- void readFromParcelInner(Parcel parcel, int length) {
- if (length == 0) {
- // Empty Bundle or end of data.
- mParcelledData = EMPTY_PARCEL;
- mHasFds = false;
- mFdsKnown = true;
- return;
- }
- int magic = parcel.readInt();
- if (magic != BUNDLE_MAGIC) {
- //noinspection ThrowableInstanceNeverThrown
- throw new IllegalStateException("Bad magic number for Bundle: 0x"
- + Integer.toHexString(magic));
- }
-
- // Advance within this Parcel
- int offset = parcel.dataPosition();
- parcel.setDataPosition(offset + length);
-
- Parcel p = Parcel.obtain();
- p.setDataPosition(0);
- p.appendFrom(parcel, offset, length);
- if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this))
- + ": " + length + " bundle bytes starting at " + offset);
- p.setDataPosition(0);
-
- mParcelledData = p;
- mHasFds = p.hasFileDescriptors();
+ super.readFromParcelInner(parcel);
+ mHasFds = mParcelledData.hasFileDescriptors();
mFdsKnown = true;
}
@@ -1759,4 +1415,5 @@
}
return "Bundle[" + mMap.toString() + "]";
}
+
}
diff --git a/core/java/android/os/CommonBundle.java b/core/java/android/os/CommonBundle.java
new file mode 100644
index 0000000..e11f170
--- /dev/null
+++ b/core/java/android/os/CommonBundle.java
@@ -0,0 +1,1384 @@
+/*
+ * 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.os;
+
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A mapping from String values to various types.
+ */
+abstract class CommonBundle implements Parcelable, Cloneable {
+ private static final String TAG = "Bundle";
+ static final boolean DEBUG = false;
+
+ static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+ static final Parcel EMPTY_PARCEL;
+
+ static {
+ EMPTY_PARCEL = Parcel.obtain();
+ }
+
+ // Invariant - exactly one of mMap / mParcelledData will be null
+ // (except inside a call to unparcel)
+
+ ArrayMap<String, Object> mMap = null;
+
+ /*
+ * If mParcelledData is non-null, then mMap will be null and the
+ * data are stored as a Parcel containing a Bundle. When the data
+ * are unparcelled, mParcelledData willbe set to null.
+ */
+ Parcel mParcelledData = null;
+
+ /**
+ * The ClassLoader used when unparcelling data from mParcelledData.
+ */
+ private ClassLoader mClassLoader;
+
+ /**
+ * Constructs a new, empty Bundle that uses a specific ClassLoader for
+ * instantiating Parcelable and Serializable objects.
+ *
+ * @param loader An explicit ClassLoader to use when instantiating objects
+ * inside of the Bundle.
+ * @param capacity Initial size of the ArrayMap.
+ */
+ CommonBundle(ClassLoader loader, int capacity) {
+ mMap = capacity > 0 ?
+ new ArrayMap<String, Object>(capacity) : new ArrayMap<String, Object>();
+ mClassLoader = loader == null ? getClass().getClassLoader() : loader;
+ }
+
+ /**
+ * Constructs a new, empty Bundle.
+ */
+ CommonBundle() {
+ this((ClassLoader) null, 0);
+ }
+
+ /**
+ * Constructs a Bundle whose data is stored as a Parcel. The data
+ * will be unparcelled on first contact, using the assigned ClassLoader.
+ *
+ * @param parcelledData a Parcel containing a Bundle
+ */
+ CommonBundle(Parcel parcelledData) {
+ readFromParcelInner(parcelledData);
+ }
+
+ CommonBundle(Parcel parcelledData, int length) {
+ readFromParcelInner(parcelledData, length);
+ }
+
+ /**
+ * Constructs a new, empty Bundle that uses a specific ClassLoader for
+ * instantiating Parcelable and Serializable objects.
+ *
+ * @param loader An explicit ClassLoader to use when instantiating objects
+ * inside of the Bundle.
+ */
+ CommonBundle(ClassLoader loader) {
+ this(loader, 0);
+ }
+
+ /**
+ * Constructs a new, empty Bundle sized to hold the given number of
+ * elements. The Bundle will grow as needed.
+ *
+ * @param capacity the initial capacity of the Bundle
+ */
+ CommonBundle(int capacity) {
+ this((ClassLoader) null, capacity);
+ }
+
+ /**
+ * Constructs a Bundle containing a copy of the mappings from the given
+ * Bundle.
+ *
+ * @param b a Bundle to be copied.
+ */
+ CommonBundle(CommonBundle b) {
+ if (b.mParcelledData != null) {
+ if (b.mParcelledData == EMPTY_PARCEL) {
+ mParcelledData = EMPTY_PARCEL;
+ } else {
+ mParcelledData = Parcel.obtain();
+ mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
+ mParcelledData.setDataPosition(0);
+ }
+ } else {
+ mParcelledData = null;
+ }
+
+ if (b.mMap != null) {
+ mMap = new ArrayMap<String, Object>(b.mMap);
+ } else {
+ mMap = null;
+ }
+
+ mClassLoader = b.mClassLoader;
+ }
+
+ /**
+ * TODO: optimize this later (getting just the value part of a Bundle
+ * with a single pair) once Bundle.forPair() above is implemented
+ * with a special single-value Map implementation/serialization.
+ *
+ * Note: value in single-pair Bundle may be null.
+ *
+ * @hide
+ */
+ String getPairValue() {
+ unparcel();
+ int size = mMap.size();
+ if (size > 1) {
+ Log.w(TAG, "getPairValue() used on Bundle with multiple pairs.");
+ }
+ if (size == 0) {
+ return null;
+ }
+ Object o = mMap.valueAt(0);
+ try {
+ return (String) o;
+ } catch (ClassCastException e) {
+ typeWarning("getPairValue()", o, "String", e);
+ return null;
+ }
+ }
+
+ /**
+ * Changes the ClassLoader this Bundle uses when instantiating objects.
+ *
+ * @param loader An explicit ClassLoader to use when instantiating objects
+ * inside of the Bundle.
+ */
+ void setClassLoader(ClassLoader loader) {
+ mClassLoader = loader;
+ }
+
+ /**
+ * Return the ClassLoader currently associated with this Bundle.
+ */
+ ClassLoader getClassLoader() {
+ return mClassLoader;
+ }
+
+ /**
+ * If the underlying data are stored as a Parcel, unparcel them
+ * using the currently assigned class loader.
+ */
+ /* package */ synchronized void unparcel() {
+ if (mParcelledData == null) {
+ if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ + ": no parcelled data");
+ return;
+ }
+
+ if (mParcelledData == EMPTY_PARCEL) {
+ if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ + ": empty");
+ if (mMap == null) {
+ mMap = new ArrayMap<String, Object>(1);
+ } else {
+ mMap.erase();
+ }
+ mParcelledData = null;
+ return;
+ }
+
+ int N = mParcelledData.readInt();
+ if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ + ": reading " + N + " maps");
+ if (N < 0) {
+ return;
+ }
+ if (mMap == null) {
+ mMap = new ArrayMap<String, Object>(N);
+ } else {
+ mMap.erase();
+ mMap.ensureCapacity(N);
+ }
+ mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
+ mParcelledData.recycle();
+ mParcelledData = null;
+ if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ + " final map: " + mMap);
+ }
+
+ /**
+ * @hide
+ */
+ boolean isParcelled() {
+ return mParcelledData != null;
+ }
+
+ /**
+ * Returns the number of mappings contained in this Bundle.
+ *
+ * @return the number of mappings as an int.
+ */
+ int size() {
+ unparcel();
+ return mMap.size();
+ }
+
+ /**
+ * Returns true if the mapping of this Bundle is empty, false otherwise.
+ */
+ boolean isEmpty() {
+ unparcel();
+ return mMap.isEmpty();
+ }
+
+ /**
+ * Removes all elements from the mapping of this Bundle.
+ */
+ void clear() {
+ unparcel();
+ mMap.clear();
+ }
+
+ /**
+ * Returns true if the given key is contained in the mapping
+ * of this Bundle.
+ *
+ * @param key a String key
+ * @return true if the key is part of the mapping, false otherwise
+ */
+ boolean containsKey(String key) {
+ unparcel();
+ return mMap.containsKey(key);
+ }
+
+ /**
+ * Returns the entry with the given key as an object.
+ *
+ * @param key a String key
+ * @return an Object, or null
+ */
+ Object get(String key) {
+ unparcel();
+ return mMap.get(key);
+ }
+
+ /**
+ * Removes any entry with the given key from the mapping of this Bundle.
+ *
+ * @param key a String key
+ */
+ void remove(String key) {
+ unparcel();
+ mMap.remove(key);
+ }
+
+ /**
+ * Inserts all mappings from the given PersistableBundle into this CommonBundle.
+ *
+ * @param bundle a PersistableBundle
+ */
+ void putAll(PersistableBundle bundle) {
+ unparcel();
+ bundle.unparcel();
+ mMap.putAll(bundle.mMap);
+ }
+
+ /**
+ * Returns a Set containing the Strings used as keys in this Bundle.
+ *
+ * @return a Set of String keys
+ */
+ Set<String> keySet() {
+ unparcel();
+ return mMap.keySet();
+ }
+
+ /**
+ * Inserts a Boolean value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Boolean, or null
+ */
+ void putBoolean(String key, boolean value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a byte value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a byte
+ */
+ void putByte(String key, byte value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a char value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a char, or null
+ */
+ void putChar(String key, char value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a short value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a short
+ */
+ void putShort(String key, short value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts an int value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value an int, or null
+ */
+ void putInt(String key, int value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a long value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a long
+ */
+ void putLong(String key, long value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a float value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a float
+ */
+ void putFloat(String key, float value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a double value into the mapping of this Bundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a double
+ */
+ void putDouble(String key, double value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a String value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a String, or null
+ */
+ void putString(String key, String value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a CharSequence value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a CharSequence, or null
+ */
+ void putCharSequence(String key, CharSequence value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts an ArrayList<Integer> value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an ArrayList<Integer> object, or null
+ */
+ void putIntegerArrayList(String key, ArrayList<Integer> value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts an ArrayList<String> value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an ArrayList<String> object, or null
+ */
+ void putStringArrayList(String key, ArrayList<String> value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts an ArrayList<CharSequence> value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an ArrayList<CharSequence> object, or null
+ */
+ void putCharSequenceArrayList(String key, ArrayList<CharSequence> value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a Serializable value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Serializable object, or null
+ */
+ void putSerializable(String key, Serializable value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a boolean array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a boolean array object, or null
+ */
+ void putBooleanArray(String key, boolean[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a byte array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a byte array object, or null
+ */
+ void putByteArray(String key, byte[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a short array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a short array object, or null
+ */
+ void putShortArray(String key, short[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a char array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a char array object, or null
+ */
+ void putCharArray(String key, char[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts an int array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an int array object, or null
+ */
+ void putIntArray(String key, int[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a long array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a long array object, or null
+ */
+ void putLongArray(String key, long[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a float array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a float array object, or null
+ */
+ void putFloatArray(String key, float[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a double array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a double array object, or null
+ */
+ void putDoubleArray(String key, double[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a String array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a String array object, or null
+ */
+ void putStringArray(String key, String[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a CharSequence array value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a CharSequence array object, or null
+ */
+ void putCharSequenceArray(String key, CharSequence[] value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Inserts a PersistableBundle value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Bundle object, or null
+ */
+ void putPersistableBundle(String key, PersistableBundle value) {
+ unparcel();
+ mMap.put(key, value);
+ }
+
+ /**
+ * Returns the value associated with the given key, or false if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a boolean value
+ */
+ boolean getBoolean(String key) {
+ unparcel();
+ if (DEBUG) Log.d(TAG, "Getting boolean in "
+ + Integer.toHexString(System.identityHashCode(this)));
+ return getBoolean(key, false);
+ }
+
+ // Log a message if the value was non-null but not of the expected type
+ void typeWarning(String key, Object value, String className,
+ Object defaultValue, ClassCastException e) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Key ");
+ sb.append(key);
+ sb.append(" expected ");
+ sb.append(className);
+ sb.append(" but value was a ");
+ sb.append(value.getClass().getName());
+ sb.append(". The default value ");
+ sb.append(defaultValue);
+ sb.append(" was returned.");
+ Log.w(TAG, sb.toString());
+ Log.w(TAG, "Attempt to cast generated internal exception:", e);
+ }
+
+ void typeWarning(String key, Object value, String className,
+ ClassCastException e) {
+ typeWarning(key, value, className, "<null>", e);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a boolean value
+ */
+ boolean getBoolean(String key, boolean defaultValue) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return defaultValue;
+ }
+ try {
+ return (Boolean) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Boolean", defaultValue, e);
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or (byte) 0 if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a byte value
+ */
+ byte getByte(String key) {
+ unparcel();
+ return getByte(key, (byte) 0);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a byte value
+ */
+ Byte getByte(String key, byte defaultValue) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return defaultValue;
+ }
+ try {
+ return (Byte) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Byte", defaultValue, e);
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or (char) 0 if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a char value
+ */
+ char getChar(String key) {
+ unparcel();
+ return getChar(key, (char) 0);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a char value
+ */
+ char getChar(String key, char defaultValue) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return defaultValue;
+ }
+ try {
+ return (Character) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Character", defaultValue, e);
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or (short) 0 if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a short value
+ */
+ short getShort(String key) {
+ unparcel();
+ return getShort(key, (short) 0);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a short value
+ */
+ short getShort(String key, short defaultValue) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return defaultValue;
+ }
+ try {
+ return (Short) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Short", defaultValue, e);
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or 0 if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return an int value
+ */
+ int getInt(String key) {
+ unparcel();
+ return getInt(key, 0);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return an int value
+ */
+ int getInt(String key, int defaultValue) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return defaultValue;
+ }
+ try {
+ return (Integer) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Integer", defaultValue, e);
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or 0L if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a long value
+ */
+ long getLong(String key) {
+ unparcel();
+ return getLong(key, 0L);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a long value
+ */
+ long getLong(String key, long defaultValue) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return defaultValue;
+ }
+ try {
+ return (Long) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Long", defaultValue, e);
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or 0.0f if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a float value
+ */
+ float getFloat(String key) {
+ unparcel();
+ return getFloat(key, 0.0f);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a float value
+ */
+ float getFloat(String key, float defaultValue) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return defaultValue;
+ }
+ try {
+ return (Float) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Float", defaultValue, e);
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or 0.0 if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a double value
+ */
+ double getDouble(String key) {
+ unparcel();
+ return getDouble(key, 0.0);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a double value
+ */
+ double getDouble(String key, double defaultValue) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return defaultValue;
+ }
+ try {
+ return (Double) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Double", defaultValue, e);
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a String value, or null
+ */
+ String getString(String key) {
+ unparcel();
+ final Object o = mMap.get(key);
+ try {
+ return (String) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "String", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String, or null
+ * @param defaultValue Value to return if key does not exist
+ * @return the String value associated with the given key, or defaultValue
+ * if no valid String object is currently mapped to that key.
+ */
+ String getString(String key, String defaultValue) {
+ final String s = getString(key);
+ return (s == null) ? defaultValue : s;
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a CharSequence value, or null
+ */
+ CharSequence getCharSequence(String key) {
+ unparcel();
+ final Object o = mMap.get(key);
+ try {
+ return (CharSequence) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "CharSequence", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String, or null
+ * @param defaultValue Value to return if key does not exist
+ * @return the CharSequence value associated with the given key, or defaultValue
+ * if no valid CharSequence object is currently mapped to that key.
+ */
+ CharSequence getCharSequence(String key, CharSequence defaultValue) {
+ final CharSequence cs = getCharSequence(key);
+ return (cs == null) ? defaultValue : cs;
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a Bundle value, or null
+ */
+ PersistableBundle getPersistableBundle(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (PersistableBundle) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Bundle", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a Serializable value, or null
+ */
+ Serializable getSerializable(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (Serializable) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "Serializable", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return an ArrayList<String> value, or null
+ */
+ ArrayList<Integer> getIntegerArrayList(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (ArrayList<Integer>) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "ArrayList<Integer>", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return an ArrayList<String> value, or null
+ */
+ ArrayList<String> getStringArrayList(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (ArrayList<String>) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "ArrayList<String>", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return an ArrayList<CharSequence> value, or null
+ */
+ ArrayList<CharSequence> getCharSequenceArrayList(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (ArrayList<CharSequence>) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "ArrayList<CharSequence>", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a boolean[] value, or null
+ */
+ boolean[] getBooleanArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (boolean[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "byte[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a byte[] value, or null
+ */
+ byte[] getByteArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (byte[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "byte[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a short[] value, or null
+ */
+ short[] getShortArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (short[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "short[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a char[] value, or null
+ */
+ char[] getCharArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (char[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "char[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return an int[] value, or null
+ */
+ int[] getIntArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (int[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "int[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a long[] value, or null
+ */
+ long[] getLongArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (long[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "long[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a float[] value, or null
+ */
+ float[] getFloatArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (float[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "float[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a double[] value, or null
+ */
+ double[] getDoubleArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (double[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "double[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a String[] value, or null
+ */
+ String[] getStringArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (String[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "String[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a CharSequence[] value, or null
+ */
+ CharSequence[] getCharSequenceArray(String key) {
+ unparcel();
+ Object o = mMap.get(key);
+ if (o == null) {
+ return null;
+ }
+ try {
+ return (CharSequence[]) o;
+ } catch (ClassCastException e) {
+ typeWarning(key, o, "CharSequence[]", e);
+ return null;
+ }
+ }
+
+ /**
+ * Writes the Bundle contents to a Parcel, typically in order for
+ * it to be passed through an IBinder connection.
+ * @param parcel The parcel to copy this bundle to.
+ */
+ void writeToParcelInner(Parcel parcel, int flags) {
+ if (mParcelledData != null) {
+ if (mParcelledData == EMPTY_PARCEL) {
+ parcel.writeInt(0);
+ } else {
+ int length = mParcelledData.dataSize();
+ parcel.writeInt(length);
+ parcel.writeInt(BUNDLE_MAGIC);
+ parcel.appendFrom(mParcelledData, 0, length);
+ }
+ } else {
+ // Special case for empty bundles.
+ if (mMap == null || mMap.size() <= 0) {
+ parcel.writeInt(0);
+ return;
+ }
+ int lengthPos = parcel.dataPosition();
+ parcel.writeInt(-1); // dummy, will hold length
+ parcel.writeInt(BUNDLE_MAGIC);
+
+ int startPos = parcel.dataPosition();
+ parcel.writeArrayMapInternal(mMap);
+ int endPos = parcel.dataPosition();
+
+ // Backpatch length
+ parcel.setDataPosition(lengthPos);
+ int length = endPos - startPos;
+ parcel.writeInt(length);
+ parcel.setDataPosition(endPos);
+ }
+ }
+
+ /**
+ * Reads the Parcel contents into this Bundle, typically in order for
+ * it to be passed through an IBinder connection.
+ * @param parcel The parcel to overwrite this bundle from.
+ */
+ void readFromParcelInner(Parcel parcel) {
+ int length = parcel.readInt();
+ if (length < 0) {
+ throw new RuntimeException("Bad length in parcel: " + length);
+ }
+ readFromParcelInner(parcel, length);
+ }
+
+ private void readFromParcelInner(Parcel parcel, int length) {
+ if (length == 0) {
+ // Empty Bundle or end of data.
+ mParcelledData = EMPTY_PARCEL;
+ return;
+ }
+ int magic = parcel.readInt();
+ if (magic != BUNDLE_MAGIC) {
+ //noinspection ThrowableInstanceNeverThrown
+ throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ + Integer.toHexString(magic));
+ }
+
+ // Advance within this Parcel
+ int offset = parcel.dataPosition();
+ parcel.setDataPosition(offset + length);
+
+ Parcel p = Parcel.obtain();
+ p.setDataPosition(0);
+ p.appendFrom(parcel, offset, length);
+ if (DEBUG) Log.d(TAG, "Retrieving " + Integer.toHexString(System.identityHashCode(this))
+ + ": " + length + " bundle bytes starting at " + offset);
+ p.setDataPosition(0);
+
+ mParcelledData = p;
+ }
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e96398a..e98a26b 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -42,6 +42,7 @@
private static final String ENV_SECONDARY_STORAGE = "SECONDARY_STORAGE";
private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
private static final String ENV_OEM_ROOT = "OEM_ROOT";
+ private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
/** {@hide} */
public static final String DIR_ANDROID = "Android";
@@ -57,6 +58,7 @@
private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
+ private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
private static final File DIR_MEDIA_STORAGE = getDirectory(ENV_MEDIA_STORAGE, "/data/media");
private static final String CANONCIAL_EMULATED_STORAGE_TARGET = getCanonicalPathOrNull(
@@ -225,6 +227,15 @@
}
/**
+ * Return root directory of the "vendor" partition that holds vendor-provided
+ * software that should persist across simple reflashing of the "system" partition.
+ * @hide
+ */
+ public static File getVendorDirectory() {
+ return DIR_VENDOR_ROOT;
+ }
+
+ /**
* Gets the system directory available for secure storage.
* If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
* Otherwise, it returns the unencrypted /data/system directory.
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index dc18dee..1089f27 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -370,8 +370,8 @@
* attacks.
*/
public static boolean contains(File dir, File file) {
- String dirPath = dir.getPath();
- String filePath = file.getPath();
+ String dirPath = dir.getAbsolutePath();
+ String filePath = file.getAbsolutePath();
if (dirPath.equals(filePath)) {
return true;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 1192a45..c3f7370 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -34,7 +34,7 @@
void setUserIcon(int userHandle, in Bitmap icon);
Bitmap getUserIcon(int userHandle);
List<UserInfo> getUsers(boolean excludeDying);
- List<UserInfo> getProfiles(int userHandle);
+ List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
UserInfo getUserInfo(int userHandle);
boolean isRestricted();
void setGuestEnabled(boolean enable);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 8e0ff08..95cb9f3 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -223,6 +223,7 @@
private static final int VAL_SPARSEBOOLEANARRAY = 22;
private static final int VAL_BOOLEANARRAY = 23;
private static final int VAL_CHARSEQUENCEARRAY = 24;
+ private static final int VAL_PERSISTABLEBUNDLE = 25;
// The initial int32 in a Binder call's reply Parcel header:
private static final int EX_SECURITY = -1;
@@ -638,6 +639,19 @@
}
/**
+ * Flatten a PersistableBundle into the parcel at the current dataPosition(),
+ * growing dataCapacity() if needed.
+ */
+ public final void writePersistableBundle(PersistableBundle val) {
+ if (val == null) {
+ writeInt(-1);
+ return;
+ }
+
+ val.writeToParcel(this, 0);
+ }
+
+ /**
* Flatten a List into the parcel at the current dataPosition(), growing
* dataCapacity() if needed. The List values are written using
* {@link #writeValue} and must follow the specification there.
@@ -1256,6 +1270,9 @@
} else if (v instanceof Byte) {
writeInt(VAL_BYTE);
writeInt((Byte) v);
+ } else if (v instanceof PersistableBundle) {
+ writeInt(VAL_PERSISTABLEBUNDLE);
+ writePersistableBundle((PersistableBundle) v);
} else {
Class<?> clazz = v.getClass();
if (clazz.isArray() && clazz.getComponentType() == Object.class) {
@@ -1633,6 +1650,35 @@
}
/**
+ * Read and return a new Bundle object from the parcel at the current
+ * dataPosition(). Returns null if the previously written Bundle object was
+ * null.
+ */
+ public final PersistableBundle readPersistableBundle() {
+ return readPersistableBundle(null);
+ }
+
+ /**
+ * Read and return a new Bundle object from the parcel at the current
+ * dataPosition(), using the given class loader to initialize the class
+ * loader of the Bundle for later retrieval of Parcelable objects.
+ * Returns null if the previously written Bundle object was null.
+ */
+ public final PersistableBundle readPersistableBundle(ClassLoader loader) {
+ int length = readInt();
+ if (length < 0) {
+ if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
+ return null;
+ }
+
+ final PersistableBundle bundle = new PersistableBundle(this, length);
+ if (loader != null) {
+ bundle.setClassLoader(loader);
+ }
+ return bundle;
+ }
+
+ /**
* Read and return a byte[] object from the parcel.
*/
public final byte[] createByteArray() {
@@ -2082,6 +2128,9 @@
case VAL_BUNDLE:
return readBundle(loader); // loading will be deferred
+ case VAL_PERSISTABLEBUNDLE:
+ return readPersistableBundle(loader);
+
default:
int off = dataPosition() - 4;
throw new RuntimeException(
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 86dc8b4..24bf05e 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -42,6 +42,7 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.net.DatagramSocket;
import java.net.Socket;
import java.nio.ByteOrder;
@@ -698,6 +699,9 @@
} catch (ErrnoException e) {
// Reporting status is best-effort
Log.w(TAG, "Failed to report status: " + e);
+ } catch (InterruptedIOException e) {
+ // Reporting status is best-effort
+ Log.w(TAG, "Failed to report status: " + e);
}
} finally {
@@ -728,6 +732,9 @@
Log.d(TAG, "Failed to read status; assuming dead: " + e);
return new Status(Status.DEAD);
}
+ } catch (InterruptedIOException e) {
+ Log.d(TAG, "Failed to read status; assuming dead: " + e);
+ return new Status(Status.DEAD);
}
}
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
new file mode 100644
index 0000000..c2cd3be
--- /dev/null
+++ b/core/java/android/os/PersistableBundle.java
@@ -0,0 +1,555 @@
+/*
+ * 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.os;
+
+import android.util.ArrayMap;
+
+import java.util.Set;
+
+/**
+ * A mapping from String values to various types that can be saved to persistent and later
+ * restored.
+ *
+ */
+public final class PersistableBundle extends CommonBundle {
+ public static final PersistableBundle EMPTY;
+ static final Parcel EMPTY_PARCEL;
+
+ static {
+ EMPTY = new PersistableBundle();
+ EMPTY.mMap = ArrayMap.EMPTY;
+ EMPTY_PARCEL = CommonBundle.EMPTY_PARCEL;
+ }
+
+ /**
+ * Constructs a new, empty PersistableBundle.
+ */
+ public PersistableBundle() {
+ super();
+ }
+
+ /**
+ * Constructs a PersistableBundle whose data is stored as a Parcel. The data
+ * will be unparcelled on first contact, using the assigned ClassLoader.
+ *
+ * @param parcelledData a Parcel containing a PersistableBundle
+ */
+ PersistableBundle(Parcel parcelledData) {
+ super(parcelledData);
+ }
+
+ /* package */ PersistableBundle(Parcel parcelledData, int length) {
+ super(parcelledData, length);
+ }
+
+ /**
+ * Constructs a new, empty PersistableBundle that uses a specific ClassLoader for
+ * instantiating Parcelable and Serializable objects.
+ *
+ * @param loader An explicit ClassLoader to use when instantiating objects
+ * inside of the PersistableBundle.
+ */
+ public PersistableBundle(ClassLoader loader) {
+ super(loader);
+ }
+
+ /**
+ * Constructs a new, empty PersistableBundle sized to hold the given number of
+ * elements. The PersistableBundle will grow as needed.
+ *
+ * @param capacity the initial capacity of the PersistableBundle
+ */
+ public PersistableBundle(int capacity) {
+ super(capacity);
+ }
+
+ /**
+ * Constructs a PersistableBundle containing a copy of the mappings from the given
+ * PersistableBundle.
+ *
+ * @param b a PersistableBundle to be copied.
+ */
+ public PersistableBundle(PersistableBundle b) {
+ super(b);
+ }
+
+ /**
+ * Make a PersistableBundle for a single key/value pair.
+ *
+ * @hide
+ */
+ public static PersistableBundle forPair(String key, String value) {
+ PersistableBundle b = new PersistableBundle(1);
+ b.putString(key, value);
+ return b;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public String getPairValue() {
+ return super.getPairValue();
+ }
+
+ /**
+ * Changes the ClassLoader this PersistableBundle uses when instantiating objects.
+ *
+ * @param loader An explicit ClassLoader to use when instantiating objects
+ * inside of the PersistableBundle.
+ */
+ @Override
+ public void setClassLoader(ClassLoader loader) {
+ super.setClassLoader(loader);
+ }
+
+ /**
+ * Return the ClassLoader currently associated with this PersistableBundle.
+ */
+ @Override
+ public ClassLoader getClassLoader() {
+ return super.getClassLoader();
+ }
+
+ /**
+ * Clones the current PersistableBundle. The internal map is cloned, but the keys and
+ * values to which it refers are copied by reference.
+ */
+ @Override
+ public Object clone() {
+ return new PersistableBundle(this);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isParcelled() {
+ return super.isParcelled();
+ }
+
+ /**
+ * Returns the number of mappings contained in this PersistableBundle.
+ *
+ * @return the number of mappings as an int.
+ */
+ @Override
+ public int size() {
+ return super.size();
+ }
+
+ /**
+ * Returns true if the mapping of this PersistableBundle is empty, false otherwise.
+ */
+ @Override
+ public boolean isEmpty() {
+ return super.isEmpty();
+ }
+
+ /**
+ * Removes all elements from the mapping of this PersistableBundle.
+ */
+ @Override
+ public void clear() {
+ super.clear();
+ }
+
+ /**
+ * Returns true if the given key is contained in the mapping
+ * of this PersistableBundle.
+ *
+ * @param key a String key
+ * @return true if the key is part of the mapping, false otherwise
+ */
+ @Override
+ public boolean containsKey(String key) {
+ return super.containsKey(key);
+ }
+
+ /**
+ * Returns the entry with the given key as an object.
+ *
+ * @param key a String key
+ * @return an Object, or null
+ */
+ @Override
+ public Object get(String key) {
+ return super.get(key);
+ }
+
+ /**
+ * Removes any entry with the given key from the mapping of this PersistableBundle.
+ *
+ * @param key a String key
+ */
+ @Override
+ public void remove(String key) {
+ super.remove(key);
+ }
+
+ /**
+ * Inserts all mappings from the given PersistableBundle into this Bundle.
+ *
+ * @param bundle a PersistableBundle
+ */
+ public void putAll(PersistableBundle bundle) {
+ super.putAll(bundle);
+ }
+
+ /**
+ * Returns a Set containing the Strings used as keys in this PersistableBundle.
+ *
+ * @return a Set of String keys
+ */
+ @Override
+ public Set<String> keySet() {
+ return super.keySet();
+ }
+
+ /**
+ * Inserts an int value into the mapping of this PersistableBundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value an int, or null
+ */
+ @Override
+ public void putInt(String key, int value) {
+ super.putInt(key, value);
+ }
+
+ /**
+ * Inserts a long value into the mapping of this PersistableBundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a long
+ */
+ @Override
+ public void putLong(String key, long value) {
+ super.putLong(key, value);
+ }
+
+ /**
+ * Inserts a double value into the mapping of this PersistableBundle, replacing
+ * any existing value for the given key.
+ *
+ * @param key a String, or null
+ * @param value a double
+ */
+ @Override
+ public void putDouble(String key, double value) {
+ super.putDouble(key, value);
+ }
+
+ /**
+ * Inserts a String value into the mapping of this PersistableBundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a String, or null
+ */
+ @Override
+ public void putString(String key, String value) {
+ super.putString(key, value);
+ }
+
+ /**
+ * Inserts an int array value into the mapping of this PersistableBundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value an int array object, or null
+ */
+ @Override
+ public void putIntArray(String key, int[] value) {
+ super.putIntArray(key, value);
+ }
+
+ /**
+ * Inserts a long array value into the mapping of this PersistableBundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a long array object, or null
+ */
+ @Override
+ public void putLongArray(String key, long[] value) {
+ super.putLongArray(key, value);
+ }
+
+ /**
+ * Inserts a double array value into the mapping of this PersistableBundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a double array object, or null
+ */
+ @Override
+ public void putDoubleArray(String key, double[] value) {
+ super.putDoubleArray(key, value);
+ }
+
+ /**
+ * Inserts a String array value into the mapping of this PersistableBundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a String array object, or null
+ */
+ @Override
+ public void putStringArray(String key, String[] value) {
+ super.putStringArray(key, value);
+ }
+
+ /**
+ * Inserts a PersistableBundle value into the mapping of this Bundle, replacing
+ * any existing value for the given key. Either key or value may be null.
+ *
+ * @param key a String, or null
+ * @param value a Bundle object, or null
+ */
+ public void putPersistableBundle(String key, PersistableBundle value) {
+ super.putPersistableBundle(key, value);
+ }
+
+ /**
+ * Returns the value associated with the given key, or 0 if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return an int value
+ */
+ @Override
+ public int getInt(String key) {
+ return super.getInt(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return an int value
+ */
+ @Override
+ public int getInt(String key, int defaultValue) {
+ return super.getInt(key, defaultValue);
+ }
+
+ /**
+ * Returns the value associated with the given key, or 0L if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a long value
+ */
+ @Override
+ public long getLong(String key) {
+ return super.getLong(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a long value
+ */
+ @Override
+ public long getLong(String key, long defaultValue) {
+ return super.getLong(key, defaultValue);
+ }
+
+ /**
+ * Returns the value associated with the given key, or 0.0 if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @return a double value
+ */
+ @Override
+ public double getDouble(String key) {
+ return super.getDouble(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String
+ * @param defaultValue Value to return if key does not exist
+ * @return a double value
+ */
+ @Override
+ public double getDouble(String key, double defaultValue) {
+ return super.getDouble(key, defaultValue);
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a String value, or null
+ */
+ @Override
+ public String getString(String key) {
+ return super.getString(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or defaultValue if
+ * no mapping of the desired type exists for the given key.
+ *
+ * @param key a String, or null
+ * @param defaultValue Value to return if key does not exist
+ * @return the String value associated with the given key, or defaultValue
+ * if no valid String object is currently mapped to that key.
+ */
+ @Override
+ public String getString(String key, String defaultValue) {
+ return super.getString(key, defaultValue);
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a Bundle value, or null
+ */
+ @Override
+ public PersistableBundle getPersistableBundle(String key) {
+ return super.getPersistableBundle(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return an int[] value, or null
+ */
+ @Override
+ public int[] getIntArray(String key) {
+ return super.getIntArray(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a long[] value, or null
+ */
+ @Override
+ public long[] getLongArray(String key) {
+ return super.getLongArray(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a double[] value, or null
+ */
+ @Override
+ public double[] getDoubleArray(String key) {
+ return super.getDoubleArray(key);
+ }
+
+ /**
+ * Returns the value associated with the given key, or null if
+ * no mapping of the desired type exists for the given key or a null
+ * value is explicitly associated with the key.
+ *
+ * @param key a String, or null
+ * @return a String[] value, or null
+ */
+ @Override
+ public String[] getStringArray(String key) {
+ return super.getStringArray(key);
+ }
+
+ public static final Parcelable.Creator<PersistableBundle> CREATOR =
+ new Parcelable.Creator<PersistableBundle>() {
+ @Override
+ public PersistableBundle createFromParcel(Parcel in) {
+ return in.readPersistableBundle();
+ }
+
+ @Override
+ public PersistableBundle[] newArray(int size) {
+ return new PersistableBundle[size];
+ }
+ };
+
+ /**
+ * Report the nature of this Parcelable's contents
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Writes the PersistableBundle contents to a Parcel, typically in order for
+ * it to be passed through an IBinder connection.
+ * @param parcel The parcel to copy this bundle to.
+ */
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ final boolean oldAllowFds = parcel.pushAllowFds(false);
+ try {
+ super.writeToParcelInner(parcel, flags);
+ } finally {
+ parcel.restoreAllowFds(oldAllowFds);
+ }
+ }
+
+ /**
+ * Reads the Parcel contents into this PersistableBundle, typically in order for
+ * it to be passed through an IBinder connection.
+ * @param parcel The parcel to overwrite this bundle from.
+ */
+ public void readFromParcel(Parcel parcel) {
+ super.readFromParcelInner(parcel);
+ }
+
+ @Override
+ synchronized public String toString() {
+ if (mParcelledData != null) {
+ if (mParcelledData == EMPTY_PARCEL) {
+ return "PersistableBundle[EMPTY_PARCEL]";
+ } else {
+ return "PersistableBundle[mParcelledData.dataSize=" +
+ mParcelledData.dataSize() + "]";
+ }
+ }
+ return "PersistableBundle[" + mMap.toString() + "]";
+ }
+
+}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index f671ed9..cdde4c7 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -375,6 +375,7 @@
final ConditionVariable condition = new ConditionVariable();
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 8aef9bd..1fe9337 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -336,7 +336,7 @@
/**
* @hide
* Sets the value of a specific restriction on a specific user.
- * Requires the {@link android.Manifest.permission#MANAGE_USERS} permission.
+ * Requires the MANAGE_USERS permission.
* @param key the key of the restriction
* @param value the value for the restriction
* @param userHandle the user whose restriction is to be changed.
@@ -462,6 +462,8 @@
/**
* Returns list of the profiles of userHandle including
* userHandle itself.
+ * Note that it this returns both enabled and not enabled profiles. See
+ * {@link #getUserProfiles()} if you need only the enabled ones.
*
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userHandle profiles of this user will be returned.
@@ -470,7 +472,7 @@
*/
public List<UserInfo> getProfiles(int userHandle) {
try {
- return mService.getProfiles(userHandle);
+ return mService.getProfiles(userHandle, false /* enabledOnly */);
} catch (RemoteException re) {
Log.w(TAG, "Could not get user list", re);
return null;
@@ -484,7 +486,14 @@
*/
public List<UserHandle> getUserProfiles() {
ArrayList<UserHandle> profiles = new ArrayList<UserHandle>();
- List<UserInfo> users = getProfiles(UserHandle.myUserId());
+ List<UserInfo> users = new ArrayList<UserInfo>();
+ try {
+ // TODO: Switch enabledOnly to true once client apps are updated
+ users = mService.getProfiles(UserHandle.myUserId(), false /* enabledOnly */);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not get user list", re);
+ return null;
+ }
for (UserInfo info : users) {
UserHandle userHandle = new UserHandle(info.id);
profiles.add(userHandle);
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 325b2e6..ff16f6c 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -329,6 +329,11 @@
if (preferenceScreen != null) {
preferenceScreen.bind(getListView());
}
+ onBindPreferences();
+ }
+
+ /** @hide */
+ protected void onBindPreferences() {
}
/** @hide */
diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java
index 9b41ff0..381a5f0 100644
--- a/core/java/android/preference/PreferenceGroupAdapter.java
+++ b/core/java/android/preference/PreferenceGroupAdapter.java
@@ -20,7 +20,6 @@
import java.util.Collections;
import java.util.List;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.preference.Preference.OnPreferenceChangeInternalListener;
@@ -243,6 +242,7 @@
if (position == mHighlightedPosition && mHighlightedDrawable != null) {
result.setBackgroundDrawable(mHighlightedDrawable);
}
+ result.setTag(preference.getKey());
return result;
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index f0520b5..9a768e0 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -57,6 +57,10 @@
* <p>
* To create a document provider, extend {@link DocumentsProvider}, which
* provides a foundational implementation of this contract.
+ * <p>
+ * All client apps must hold a valid URI permission grant to access documents,
+ * typically issued when a user makes a selection through
+ * {@link Intent#ACTION_OPEN_DOCUMENT} or {@link Intent#ACTION_CREATE_DOCUMENT}.
*
* @see DocumentsProvider
*/
@@ -69,6 +73,8 @@
// content://com.example/root/sdcard/search/?query=pony
// content://com.example/document/12/
// content://com.example/document/12/children/
+ // content://com.example/via/12/document/24/
+ // content://com.example/via/12/document/24/children/
private DocumentsContract() {
}
@@ -425,6 +431,14 @@
public static final int FLAG_SUPPORTS_SEARCH = 1 << 3;
/**
+ * Flag indicating that this root supports directory selection.
+ *
+ * @see #COLUMN_FLAGS
+ * @see DocumentsProvider#isChildDocument(String, String)
+ */
+ public static final int FLAG_SUPPORTS_DIR_SELECTION = 1 << 4;
+
+ /**
* Flag indicating that this root is currently empty. This may be used
* to hide the root when opening documents, but the root will still be
* shown when creating documents and {@link #FLAG_SUPPORTS_CREATE} is
@@ -484,12 +498,15 @@
/** {@hide} */
public static final String EXTRA_THUMBNAIL_SIZE = "thumbnail_size";
+ /** {@hide} */
+ public static final String EXTRA_URI = "uri";
private static final String PATH_ROOT = "root";
private static final String PATH_RECENT = "recent";
private static final String PATH_DOCUMENT = "document";
private static final String PATH_CHILDREN = "children";
private static final String PATH_SEARCH = "search";
+ private static final String PATH_VIA = "via";
private static final String PARAM_QUERY = "query";
private static final String PARAM_MANAGE = "manage";
@@ -532,6 +549,17 @@
}
/**
+ * Build URI representing access to descendant documents of the given
+ * {@link Document#COLUMN_DOCUMENT_ID}.
+ *
+ * @see #getViaDocumentId(Uri)
+ */
+ public static Uri buildViaUri(String authority, String documentId) {
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
+ .appendPath(PATH_VIA).appendPath(documentId).build();
+ }
+
+ /**
* Build URI representing the given {@link Document#COLUMN_DOCUMENT_ID} in a
* document provider. When queried, a provider will return a single row with
* columns defined by {@link Document}.
@@ -545,6 +573,41 @@
}
/**
+ * Build URI representing the given {@link Document#COLUMN_DOCUMENT_ID} in a
+ * document provider. Instead of directly accessing the target document,
+ * gain access via another document. The target document must be a
+ * descendant (child, grandchild, etc) of the via document.
+ * <p>
+ * This is typically used to access documents under a user-selected
+ * directory, since it doesn't require the user to separately confirm each
+ * new document access.
+ *
+ * @param viaUri a related document (directory) that the caller is
+ * leveraging to gain access to the target document. The target
+ * document must be a descendant of this directory.
+ * @param documentId the target document, which the caller may not have
+ * direct access to.
+ * @see Intent#ACTION_PICK_DIRECTORY
+ * @see DocumentsProvider#isChildDocument(String, String)
+ * @see #buildDocumentUri(String, String)
+ */
+ public static Uri buildDocumentViaUri(Uri viaUri, String documentId) {
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(viaUri.getAuthority()).appendPath(PATH_VIA)
+ .appendPath(getViaDocumentId(viaUri)).appendPath(PATH_DOCUMENT)
+ .appendPath(documentId).build();
+ }
+
+ /** {@hide} */
+ public static Uri buildDocumentMaybeViaUri(Uri baseUri, String documentId) {
+ if (isViaUri(baseUri)) {
+ return buildDocumentViaUri(baseUri, documentId);
+ } else {
+ return buildDocumentUri(baseUri.getAuthority(), documentId);
+ }
+ }
+
+ /**
* Build URI representing the children of the given directory in a document
* provider. When queried, a provider will return zero or more rows with
* columns defined by {@link Document}.
@@ -562,6 +625,32 @@
}
/**
+ * Build URI representing the children of the given directory in a document
+ * provider. Instead of directly accessing the target document, gain access
+ * via another document. The target document must be a descendant (child,
+ * grandchild, etc) of the via document.
+ * <p>
+ * This is typically used to access documents under a user-selected
+ * directory, since it doesn't require the user to separately confirm each
+ * new document access.
+ *
+ * @param viaUri a related document (directory) that the caller is
+ * leveraging to gain access to the target document. The target
+ * document must be a descendant of this directory.
+ * @param parentDocumentId the target document, which the caller may not
+ * have direct access to.
+ * @see Intent#ACTION_PICK_DIRECTORY
+ * @see DocumentsProvider#isChildDocument(String, String)
+ * @see #buildChildDocumentsUri(String, String)
+ */
+ public static Uri buildChildDocumentsViaUri(Uri viaUri, String parentDocumentId) {
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(viaUri.getAuthority()).appendPath(PATH_VIA)
+ .appendPath(getViaDocumentId(viaUri)).appendPath(PATH_DOCUMENT)
+ .appendPath(parentDocumentId).appendPath(PATH_CHILDREN).build();
+ }
+
+ /**
* Build URI representing a search for matching documents under a specific
* root in a document provider. When queried, a provider will return zero or
* more rows with columns defined by {@link Document}.
@@ -580,21 +669,31 @@
/**
* Test if the given URI represents a {@link Document} backed by a
* {@link DocumentsProvider}.
+ *
+ * @see #buildDocumentUri(String, String)
+ * @see #buildDocumentViaUri(Uri, String)
*/
public static boolean isDocumentUri(Context context, Uri uri) {
final List<String> paths = uri.getPathSegments();
- if (paths.size() < 2) {
- return false;
+ if (paths.size() >= 2
+ && (PATH_DOCUMENT.equals(paths.get(0)) || PATH_VIA.equals(paths.get(0)))) {
+ return isDocumentsProvider(context, uri.getAuthority());
}
- if (!PATH_DOCUMENT.equals(paths.get(0))) {
- return false;
- }
+ return false;
+ }
+ /** {@hide} */
+ public static boolean isViaUri(Uri uri) {
+ final List<String> paths = uri.getPathSegments();
+ return (paths.size() >= 2 && PATH_VIA.equals(paths.get(0)));
+ }
+
+ private static boolean isDocumentsProvider(Context context, String authority) {
final Intent intent = new Intent(PROVIDER_INTERFACE);
final List<ResolveInfo> infos = context.getPackageManager()
.queryIntentContentProviders(intent, 0);
for (ResolveInfo info : infos) {
- if (uri.getAuthority().equals(info.providerInfo.authority)) {
+ if (authority.equals(info.providerInfo.authority)) {
return true;
}
}
@@ -606,27 +705,40 @@
*/
public static String getRootId(Uri rootUri) {
final List<String> paths = rootUri.getPathSegments();
- if (paths.size() < 2) {
- throw new IllegalArgumentException("Not a root: " + rootUri);
+ if (paths.size() >= 2 && PATH_ROOT.equals(paths.get(0))) {
+ return paths.get(1);
}
- if (!PATH_ROOT.equals(paths.get(0))) {
- throw new IllegalArgumentException("Not a root: " + rootUri);
- }
- return paths.get(1);
+ throw new IllegalArgumentException("Invalid URI: " + rootUri);
}
/**
* Extract the {@link Document#COLUMN_DOCUMENT_ID} from the given URI.
+ *
+ * @see #isDocumentUri(Context, Uri)
*/
public static String getDocumentId(Uri documentUri) {
final List<String> paths = documentUri.getPathSegments();
- if (paths.size() < 2) {
- throw new IllegalArgumentException("Not a document: " + documentUri);
+ if (paths.size() >= 2 && PATH_DOCUMENT.equals(paths.get(0))) {
+ return paths.get(1);
}
- if (!PATH_DOCUMENT.equals(paths.get(0))) {
- throw new IllegalArgumentException("Not a document: " + documentUri);
+ if (paths.size() >= 4 && PATH_VIA.equals(paths.get(0))
+ && PATH_DOCUMENT.equals(paths.get(2))) {
+ return paths.get(3);
}
- return paths.get(1);
+ throw new IllegalArgumentException("Invalid URI: " + documentUri);
+ }
+
+ /**
+ * Extract the via {@link Document#COLUMN_DOCUMENT_ID} from the given URI.
+ *
+ * @see #isViaUri(Uri)
+ */
+ public static String getViaDocumentId(Uri documentUri) {
+ final List<String> paths = documentUri.getPathSegments();
+ if (paths.size() >= 2 && PATH_VIA.equals(paths.get(0))) {
+ return paths.get(1);
+ }
+ throw new IllegalArgumentException("Invalid URI: " + documentUri);
}
/**
@@ -758,7 +870,6 @@
* @param mimeType MIME type of new document
* @param displayName name of new document
* @return newly created document, or {@code null} if failed
- * @hide
*/
public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri,
String mimeType, String displayName) {
@@ -778,13 +889,12 @@
public static Uri createDocument(ContentProviderClient client, Uri parentDocumentUri,
String mimeType, String displayName) throws RemoteException {
final Bundle in = new Bundle();
- in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(parentDocumentUri));
+ in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
in.putString(Document.COLUMN_MIME_TYPE, mimeType);
in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
final Bundle out = client.call(METHOD_CREATE_DOCUMENT, null, in);
- return buildDocumentUri(
- parentDocumentUri.getAuthority(), out.getString(Document.COLUMN_DOCUMENT_ID));
+ return out.getParcelable(DocumentsContract.EXTRA_URI);
}
/**
@@ -811,7 +921,7 @@
public static void deleteDocument(ContentProviderClient client, Uri documentUri)
throws RemoteException {
final Bundle in = new Bundle();
- in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(documentUri));
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
client.call(METHOD_DELETE_DOCUMENT, null, in);
}
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 49816f8..1a7a00f2 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -46,6 +46,7 @@
import libcore.io.IoUtils;
import java.io.FileNotFoundException;
+import java.util.Objects;
/**
* Base class for a document provider. A document provider offers read and write
@@ -125,6 +126,8 @@
private static final int MATCH_SEARCH = 4;
private static final int MATCH_DOCUMENT = 5;
private static final int MATCH_CHILDREN = 6;
+ private static final int MATCH_DOCUMENT_VIA = 7;
+ private static final int MATCH_CHILDREN_VIA = 8;
private String mAuthority;
@@ -144,6 +147,8 @@
mMatcher.addURI(mAuthority, "root/*/search", MATCH_SEARCH);
mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
+ mMatcher.addURI(mAuthority, "via/*/document/*", MATCH_DOCUMENT_VIA);
+ mMatcher.addURI(mAuthority, "via/*/document/*/children", MATCH_CHILDREN_VIA);
// Sanity check our setup
if (!info.exported) {
@@ -161,6 +166,35 @@
}
/**
+ * Test if a document is descendant (child, grandchild, etc) from the given
+ * parent. Providers must override this to support directory selection. You
+ * should avoid making network requests to keep this request fast.
+ *
+ * @param parentDocumentId parent to verify against.
+ * @param documentId child to verify.
+ * @return if given document is a descendant of the given parent.
+ * @see DocumentsContract.Root#FLAG_SUPPORTS_DIR_SELECTION
+ */
+ public boolean isChildDocument(String parentDocumentId, String documentId) {
+ return false;
+ }
+
+ /** {@hide} */
+ private void enforceVia(Uri documentUri) {
+ if (DocumentsContract.isViaUri(documentUri)) {
+ final String parent = DocumentsContract.getViaDocumentId(documentUri);
+ final String child = DocumentsContract.getDocumentId(documentUri);
+ if (Objects.equals(parent, child)) {
+ return;
+ }
+ if (!isChildDocument(parent, child)) {
+ throw new SecurityException(
+ "Document " + child + " is not a descendant of " + parent);
+ }
+ }
+ }
+
+ /**
* Create a new document and return its newly generated
* {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new
* {@link Document#COLUMN_DOCUMENT_ID} to represent the document, which must
@@ -182,9 +216,10 @@
/**
* Delete the requested document. Upon returning, any URI permission grants
- * for the requested document will be revoked. If additional documents were
- * deleted as a side effect of this call, such as documents inside a
- * directory, the implementor is responsible for revoking those permissions.
+ * for the given document will be revoked. If additional documents were
+ * deleted as a side effect of this call (such as documents inside a
+ * directory) the implementor is responsible for revoking those permissions
+ * using {@link #revokeDocumentPermission(String)}.
*
* @param documentId the document to delete.
*/
@@ -420,8 +455,12 @@
return querySearchDocuments(
getRootId(uri), getSearchDocumentsQuery(uri), projection);
case MATCH_DOCUMENT:
+ case MATCH_DOCUMENT_VIA:
+ enforceVia(uri);
return queryDocument(getDocumentId(uri), projection);
case MATCH_CHILDREN:
+ case MATCH_CHILDREN_VIA:
+ enforceVia(uri);
if (DocumentsContract.isManageMode(uri)) {
return queryChildDocumentsForManage(
getDocumentId(uri), projection, sortOrder);
@@ -449,6 +488,8 @@
case MATCH_ROOT:
return DocumentsContract.Root.MIME_TYPE_ITEM;
case MATCH_DOCUMENT:
+ case MATCH_DOCUMENT_VIA:
+ enforceVia(uri);
return getDocumentType(getDocumentId(uri));
default:
return null;
@@ -460,6 +501,49 @@
}
/**
+ * Implementation is provided by the parent class. Can be overridden to
+ * provide additional functionality, but subclasses <em>must</em> always
+ * call the superclass. If the superclass returns {@code null}, the subclass
+ * may implement custom behavior.
+ * <p>
+ * This is typically used to resolve a "via" URI into a concrete document
+ * reference, issuing a narrower single-document URI permission grant along
+ * the way.
+ *
+ * @see DocumentsContract#buildDocumentViaUri(Uri, String)
+ */
+ @Override
+ public Uri canonicalize(Uri uri) {
+ final Context context = getContext();
+ switch (mMatcher.match(uri)) {
+ case MATCH_DOCUMENT_VIA:
+ enforceVia(uri);
+
+ final Uri narrowUri = DocumentsContract.buildDocumentUri(uri.getAuthority(),
+ DocumentsContract.getDocumentId(uri));
+
+ // Caller may only have prefix grant, so extend them a grant to
+ // the narrow Uri. Caller already holds read grant to get here,
+ // so check for any other modes we should extend.
+ int modeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
+ if (context.checkCallingOrSelfUriPermission(uri,
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+ == PackageManager.PERMISSION_GRANTED) {
+ modeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+ }
+ if (context.checkCallingOrSelfUriPermission(uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
+ == PackageManager.PERMISSION_GRANTED) {
+ modeFlags |= Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
+ }
+ context.grantUriPermission(getCallingPackage(), narrowUri, modeFlags);
+ return narrowUri;
+ }
+ return null;
+ }
+
+ /**
* Implementation is provided by the parent class. Throws by default, and
* cannot be overriden.
*
@@ -496,54 +580,47 @@
* provide additional functionality, but subclasses <em>must</em> always
* call the superclass. If the superclass returns {@code null}, the subclass
* may implement custom behavior.
- *
- * @see #openDocument(String, String, CancellationSignal)
- * @see #deleteDocument(String)
*/
@Override
public Bundle call(String method, String arg, Bundle extras) {
- final Context context = getContext();
-
if (!method.startsWith("android:")) {
- // Let non-platform methods pass through
+ // Ignore non-platform methods
return super.call(method, arg, extras);
}
- final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID);
- final Uri documentUri = DocumentsContract.buildDocumentUri(mAuthority, documentId);
+ final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
+ final String authority = documentUri.getAuthority();
+ final String documentId = DocumentsContract.getDocumentId(documentUri);
- // Require that caller can manage requested document
- final boolean callerHasManage =
- context.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DOCUMENTS)
- == PackageManager.PERMISSION_GRANTED;
- enforceWritePermissionInner(documentUri);
+ if (!mAuthority.equals(authority)) {
+ throw new SecurityException(
+ "Requested authority " + authority + " doesn't match provider " + mAuthority);
+ }
+ enforceVia(documentUri);
final Bundle out = new Bundle();
try {
if (METHOD_CREATE_DOCUMENT.equals(method)) {
+ enforceWritePermissionInner(documentUri);
+
final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
final String newDocumentId = createDocument(documentId, mimeType, displayName);
- out.putString(Document.COLUMN_DOCUMENT_ID, newDocumentId);
- // Extend permission grant towards caller if needed
- if (!callerHasManage) {
- final Uri newDocumentUri = DocumentsContract.buildDocumentUri(
- mAuthority, newDocumentId);
- context.grantUriPermission(getCallingPackage(), newDocumentUri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
- }
+ // No need to issue new grants here, since caller either has
+ // manage permission or a prefix grant. We might generate a
+ // "via" style URI if that's how they called us.
+ final Uri newDocumentUri = DocumentsContract.buildDocumentMaybeViaUri(documentUri,
+ newDocumentId);
+ out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
} else if (METHOD_DELETE_DOCUMENT.equals(method)) {
+ enforceWritePermissionInner(documentUri);
deleteDocument(documentId);
// Document no longer exists, clean up any grants
- context.revokeUriPermission(documentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+ revokeDocumentPermission(documentId);
} else {
throw new UnsupportedOperationException("Method not supported " + method);
@@ -555,12 +632,25 @@
}
/**
+ * Revoke any active permission grants for the given
+ * {@link Document#COLUMN_DOCUMENT_ID}, usually called when a document
+ * becomes invalid. Follows the same semantics as
+ * {@link Context#revokeUriPermission(Uri, int)}.
+ */
+ public final void revokeDocumentPermission(String documentId) {
+ final Context context = getContext();
+ context.revokeUriPermission(DocumentsContract.buildDocumentUri(mAuthority, documentId), ~0);
+ context.revokeUriPermission(DocumentsContract.buildViaUri(mAuthority, documentId), ~0);
+ }
+
+ /**
* Implementation is provided by the parent class. Cannot be overriden.
*
* @see #openDocument(String, String, CancellationSignal)
*/
@Override
public final ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+ enforceVia(uri);
return openDocument(getDocumentId(uri), mode, null);
}
@@ -572,17 +662,47 @@
@Override
public final ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
throws FileNotFoundException {
+ enforceVia(uri);
return openDocument(getDocumentId(uri), mode, signal);
}
/**
* Implementation is provided by the parent class. Cannot be overriden.
*
+ * @see #openDocument(String, String, CancellationSignal)
+ */
+ @Override
+ @SuppressWarnings("resource")
+ public final AssetFileDescriptor openAssetFile(Uri uri, String mode)
+ throws FileNotFoundException {
+ enforceVia(uri);
+ final ParcelFileDescriptor fd = openDocument(getDocumentId(uri), mode, null);
+ return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
+ }
+
+ /**
+ * Implementation is provided by the parent class. Cannot be overriden.
+ *
+ * @see #openDocument(String, String, CancellationSignal)
+ */
+ @Override
+ @SuppressWarnings("resource")
+ public final AssetFileDescriptor openAssetFile(Uri uri, String mode, CancellationSignal signal)
+ throws FileNotFoundException {
+ enforceVia(uri);
+ final ParcelFileDescriptor fd = openDocument(getDocumentId(uri), mode, signal);
+ return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
+ }
+
+ /**
+ * Implementation is provided by the parent class. Cannot be overriden.
+ *
* @see #openDocumentThumbnail(String, Point, CancellationSignal)
*/
@Override
public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
throws FileNotFoundException {
+ enforceVia(uri);
if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
return openDocumentThumbnail(getDocumentId(uri), sizeHint, null);
@@ -600,6 +720,7 @@
public final AssetFileDescriptor openTypedAssetFile(
Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
throws FileNotFoundException {
+ enforceVia(uri);
if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
return openDocumentThumbnail(getDocumentId(uri), sizeHint, signal);
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index ae24968..cfab1b3 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -109,14 +109,18 @@
* An intent to perform a search for music media and automatically play content from the
* result when possible. This can be fired, for example, by the result of a voice recognition
* command to listen to music.
- * <p>
- * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string
- * that can contain any type of unstructured music search, like the name of an artist,
- * an album, a song, a genre, or any combination of these.
- * <p>
- * Because this intent includes an open-ended unstructured search string, it makes the most
- * sense for apps that can support large-scale search of music, such as services connected
- * to an online database of music which can be streamed and played on the device.
+ * <p>This intent always includes the {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS}
+ * and {@link android.app.SearchManager#QUERY} extras. The
+ * {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} extra determines the search mode, and
+ * the value of the {@link android.app.SearchManager#QUERY} extra depends on the search mode.
+ * For more information about the search modes for this intent, see
+ * <a href="{@docRoot}guide/components/intents-common.html#PlaySearch">Play music based
+ * on a search query</a> in <a href="{@docRoot}guide/components/intents-common.html">Common
+ * Intents</a>.</p>
+ *
+ * <p>This intent makes the most sense for apps that can support large-scale search of music,
+ * such as services connected to an online database of music which can be streamed and played
+ * on the device.</p>
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1e202ca..ab06230 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -723,6 +723,13 @@
= "android.settings.NOTIFICATION_LISTENER_SETTINGS";
/**
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CONDITION_PROVIDER_SETTINGS
+ = "android.settings.ACTION_CONDITION_PROVIDER_SETTINGS";
+
+ /**
* Activity Action: Show settings for video captioning.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard
@@ -757,6 +764,11 @@
@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
/**
@@ -3311,6 +3323,12 @@
"input_method_selector_visibility";
/**
+ * The currently selected voice interaction service flattened ComponentName.
+ * @hide
+ */
+ public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
+
+ /**
* bluetooth HCI snoop log configuration
* @hide
*/
@@ -4510,6 +4528,11 @@
*/
public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
+ /**
+ * @hide
+ */
+ public static final String ENABLED_CONDITION_PROVIDERS = "enabled_condition_providers";
+
/** @hide */
public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
@@ -5970,6 +5993,12 @@
public static final String SHOW_PROCESSES = "show_processes";
/**
+ * If 1 low power mode is enabled.
+ * @hide
+ */
+ public static final String LOW_POWER_MODE = "low_power";
+
+ /**
* If 1, the activity manager will aggressively finish activities and
* processes as soon as they are no longer needed. If 0, the normal
* extended lifetime is used.
@@ -6120,6 +6149,13 @@
}
/**
+ * Opaque value, changes when persisted zen mode configuration changes.
+ *
+ * @hide
+ */
+ public static final String ZEN_MODE_CONFIG_ETAG = "zen_mode_config_etag";
+
+ /**
* Defines global heads up toggle. One of HEADS_UP_OFF, HEADS_UP_ON.
*
* @hide
diff --git a/core/java/android/service/notification/Condition.aidl b/core/java/android/service/notification/Condition.aidl
new file mode 100644
index 0000000..432852c
--- /dev/null
+++ b/core/java/android/service/notification/Condition.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.notification;
+
+parcelable Condition;
+
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
new file mode 100644
index 0000000..71e3166
--- /dev/null
+++ b/core/java/android/service/notification/Condition.java
@@ -0,0 +1,147 @@
+/**
+ * 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.notification;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Condition information from condition providers.
+ *
+ * @hide
+ */
+public class Condition implements Parcelable {
+
+ public static final String SCHEME = "condition";
+
+ public static final int STATE_FALSE = 0;
+ public static final int STATE_TRUE = 1;
+ public static final int STATE_UNKNOWN = 2;
+ public static final int STATE_ERROR = 3;
+
+ public static final int FLAG_RELEVANT_NOW = 1 << 0;
+ public static final int FLAG_RELEVANT_ALWAYS = 1 << 1;
+
+ public final Uri id;
+ public String caption;
+ public int state;
+ public int flags;
+
+ public Condition(Uri id, String caption, int state, int flags) {
+ if (id == null) throw new IllegalArgumentException("id is required");
+ if (caption == null) throw new IllegalArgumentException("caption is required");
+ if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
+ this.id = id;
+ this.caption = caption;
+ this.state = state;
+ this.flags = flags;
+ }
+
+ private Condition(Parcel source) {
+ this((Uri)source.readParcelable(Condition.class.getClassLoader()),
+ source.readString(),
+ source.readInt(),
+ source.readInt());
+ }
+
+ private static boolean isValidState(int state) {
+ return state >= STATE_FALSE && state <= STATE_ERROR;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(id, 0);
+ dest.writeString(caption);
+ dest.writeInt(state);
+ dest.writeInt(flags);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(Condition.class.getSimpleName()).append('[')
+ .append("id=").append(id)
+ .append(",caption=").append(caption)
+ .append(",state=").append(stateToString(state))
+ .append(",flags=").append(flags)
+ .append(']').toString();
+ }
+
+ public static String stateToString(int state) {
+ if (state == STATE_FALSE) return "STATE_FALSE";
+ if (state == STATE_TRUE) return "STATE_TRUE";
+ if (state == STATE_UNKNOWN) return "STATE_UNKNOWN";
+ if (state == STATE_ERROR) return "STATE_ERROR";
+ throw new IllegalArgumentException("state is invalid: " + state);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Condition)) return false;
+ if (o == this) return true;
+ final Condition other = (Condition) o;
+ return Objects.equals(other.id, id)
+ && Objects.equals(other.caption, caption)
+ && other.state == state
+ && other.flags == flags;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, caption, state, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public Condition copy() {
+ final Parcel parcel = Parcel.obtain();
+ try {
+ writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return new Condition(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ public static Uri.Builder newId(Context context) {
+ return new Uri.Builder().scheme(SCHEME).authority(context.getPackageName());
+ }
+
+ public static boolean isValidId(Uri id, String pkg) {
+ return id != null && id.getScheme().equals(SCHEME) && id.getAuthority().equals(pkg);
+ }
+
+ public static final Parcelable.Creator<Condition> CREATOR
+ = new Parcelable.Creator<Condition>() {
+ @Override
+ public Condition createFromParcel(Parcel source) {
+ return new Condition(source);
+ }
+
+ @Override
+ public Condition[] newArray(int size) {
+ return new Condition[size];
+ }
+ };
+}
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
new file mode 100644
index 0000000..d6ef8f5
--- /dev/null
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -0,0 +1,141 @@
+/*
+ * 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.notification;
+
+import android.annotation.SdkConstant;
+import android.app.INotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * A service that provides conditions about boolean state.
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_CONDITION_PROVIDER_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * <service android:name=".MyConditionProvider"
+ * android:label="@string/service_name"
+ * android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.service.notification.ConditionProviderService" />
+ * </intent-filter>
+ * </service></pre>
+ *
+ * @hide
+ */
+public abstract class ConditionProviderService extends Service {
+ private final String TAG = ConditionProviderService.class.getSimpleName()
+ + "[" + getClass().getSimpleName() + "]";
+
+ private Provider mProvider;
+ private INotificationManager mNoMan;
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE
+ = "android.service.notification.ConditionProviderService";
+
+ abstract public void onConnected();
+ abstract public void onRequestConditions(int relevance);
+ abstract public void onSubscribe(Uri conditionId);
+ abstract public void onUnsubscribe(Uri conditionId);
+
+ private final INotificationManager getNotificationInterface() {
+ if (mNoMan == null) {
+ mNoMan = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ }
+ return mNoMan;
+ }
+
+ public final void notifyCondition(Condition condition) {
+ if (condition == null) return;
+ notifyConditions(new Condition[]{ condition });
+ }
+
+ public final void notifyConditions(Condition... conditions) {
+ if (!isBound() || conditions == null) return;
+ try {
+ getNotificationInterface().notifyConditions(getPackageName(), mProvider, conditions);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (mProvider == null) {
+ mProvider = new Provider();
+ }
+ return mProvider;
+ }
+
+ private boolean isBound() {
+ if (mProvider == null) {
+ Log.w(TAG, "Condition provider service not yet bound.");
+ return false;
+ }
+ return true;
+ }
+
+ private final class Provider extends IConditionProvider.Stub {
+ private final ConditionProviderService mService = ConditionProviderService.this;
+
+ @Override
+ public void onConnected() {
+ try {
+ mService.onConnected();
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onConnected", t);
+ }
+ }
+
+ @Override
+ public void onRequestConditions(int relevance) {
+ try {
+ mService.onRequestConditions(relevance);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onRequestConditions", t);
+ }
+ }
+
+ @Override
+ public void onSubscribe(Uri conditionId) {
+ try {
+ mService.onSubscribe(conditionId);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onSubscribe", t);
+ }
+ }
+
+ @Override
+ public void onUnsubscribe(Uri conditionId) {
+ try {
+ mService.onUnsubscribe(conditionId);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onUnsubscribe", t);
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/notification/IConditionListener.aidl b/core/java/android/service/notification/IConditionListener.aidl
new file mode 100644
index 0000000..01f874f
--- /dev/null
+++ b/core/java/android/service/notification/IConditionListener.aidl
@@ -0,0 +1,25 @@
+/**
+ * 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.notification;
+
+import android.net.Uri;
+import android.service.notification.Condition;
+
+/** @hide */
+oneway interface IConditionListener {
+ void onConditionsReceived(in Condition[] conditions);
+}
\ No newline at end of file
diff --git a/core/java/android/service/notification/IConditionProvider.aidl b/core/java/android/service/notification/IConditionProvider.aidl
new file mode 100644
index 0000000..ada8939
--- /dev/null
+++ b/core/java/android/service/notification/IConditionProvider.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.notification;
+
+import android.net.Uri;
+import android.service.notification.Condition;
+
+/** @hide */
+oneway interface IConditionProvider {
+ void onConnected();
+ void onRequestConditions(int relevance);
+ void onSubscribe(in Uri conditionId);
+ void onUnsubscribe(in Uri conditionId);
+}
\ No newline at end of file
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 @@
}
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/notification/ZenModeConfig.aidl b/core/java/android/service/notification/ZenModeConfig.aidl
new file mode 100644
index 0000000..c73b75e
--- /dev/null
+++ b/core/java/android/service/notification/ZenModeConfig.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.notification;
+
+parcelable ZenModeConfig;
+
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
new file mode 100644
index 0000000..925ddcf
--- /dev/null
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -0,0 +1,234 @@
+/**
+ * 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.notification;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Persisted configuration for zen mode.
+ *
+ * @hide
+ */
+public class ZenModeConfig implements Parcelable {
+
+ public static final String SLEEP_MODE_NIGHTS = "nights";
+ public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights";
+
+ private static final int XML_VERSION = 1;
+ private static final String ZEN_TAG = "zen";
+ private static final String ZEN_ATT_VERSION = "version";
+ private static final String ALLOW_TAG = "allow";
+ private static final String ALLOW_ATT_CALLS = "calls";
+ private static final String ALLOW_ATT_MESSAGES = "messages";
+ private static final String SLEEP_TAG = "sleep";
+ private static final String SLEEP_ATT_MODE = "mode";
+
+ private static final String SLEEP_ATT_START_HR = "startHour";
+ private static final String SLEEP_ATT_START_MIN = "startMin";
+ private static final String SLEEP_ATT_END_HR = "endHour";
+ private static final String SLEEP_ATT_END_MIN = "endMin";
+
+ public boolean allowCalls;
+ public boolean allowMessages;
+
+ public String sleepMode;
+ public int sleepStartHour;
+ public int sleepStartMinute;
+ public int sleepEndHour;
+ public int sleepEndMinute;
+
+ public ZenModeConfig() { }
+
+ public ZenModeConfig(Parcel source) {
+ allowCalls = source.readInt() == 1;
+ allowMessages = source.readInt() == 1;
+ if (source.readInt() == 1) {
+ sleepMode = source.readString();
+ }
+ sleepStartHour = source.readInt();
+ sleepStartMinute = source.readInt();
+ sleepEndHour = source.readInt();
+ sleepEndMinute = source.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(allowCalls ? 1 : 0);
+ dest.writeInt(allowMessages ? 1 : 0);
+ if (sleepMode != null) {
+ dest.writeInt(1);
+ dest.writeString(sleepMode);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(sleepStartHour);
+ dest.writeInt(sleepStartMinute);
+ dest.writeInt(sleepEndHour);
+ dest.writeInt(sleepEndMinute);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
+ .append("allowCalls=").append(allowCalls)
+ .append(",allowMessages=").append(allowMessages)
+ .append(",sleepMode=").append(sleepMode)
+ .append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute)
+ .append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute)
+ .append(']').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ZenModeConfig)) return false;
+ if (o == this) return true;
+ final ZenModeConfig other = (ZenModeConfig) o;
+ return other.allowCalls == allowCalls
+ && other.allowMessages == allowMessages
+ && Objects.equals(other.sleepMode, sleepMode)
+ && other.sleepStartHour == sleepStartHour
+ && other.sleepStartMinute == sleepStartMinute
+ && other.sleepEndHour == sleepEndHour
+ && other.sleepEndMinute == sleepEndMinute;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(allowCalls, allowMessages, sleepMode, sleepStartHour,
+ sleepStartMinute, sleepEndHour, sleepEndMinute);
+ }
+
+ public boolean isValid() {
+ return isValidHour(sleepStartHour) && isValidMinute(sleepStartMinute)
+ && isValidHour(sleepEndHour) && isValidMinute(sleepEndMinute)
+ && (sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS)
+ || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS));
+ }
+
+ public static ZenModeConfig readXml(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int type = parser.getEventType();
+ if (type != XmlPullParser.START_TAG) return null;
+ String tag = parser.getName();
+ if (!ZEN_TAG.equals(tag)) return null;
+ final ZenModeConfig rt = new ZenModeConfig();
+ final int version = Integer.parseInt(parser.getAttributeValue(null, ZEN_ATT_VERSION));
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ tag = parser.getName();
+ if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) return rt;
+ if (type == XmlPullParser.START_TAG) {
+ if (ALLOW_TAG.equals(tag)) {
+ rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
+ rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false);
+ } else if (SLEEP_TAG.equals(tag)) {
+ final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE);
+ rt.sleepMode = (SLEEP_MODE_NIGHTS.equals(mode)
+ || SLEEP_MODE_WEEKNIGHTS.equals(mode)) ? mode : null;
+ final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0);
+ final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0);
+ final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0);
+ final int endMinute = safeInt(parser, SLEEP_ATT_END_MIN, 0);
+ rt.sleepStartHour = isValidHour(startHour) ? startHour : 0;
+ rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
+ rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
+ rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
+ }
+ }
+ }
+ return rt;
+ }
+
+ public void writeXml(XmlSerializer out) throws IOException {
+ out.startTag(null, ZEN_TAG);
+ out.attribute(null, ZEN_ATT_VERSION, Integer.toString(XML_VERSION));
+
+ out.startTag(null, ALLOW_TAG);
+ out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls));
+ out.attribute(null, ALLOW_ATT_MESSAGES, Boolean.toString(allowMessages));
+ out.endTag(null, ALLOW_TAG);
+
+ out.startTag(null, SLEEP_TAG);
+ if (sleepMode != null) {
+ out.attribute(null, SLEEP_ATT_MODE, sleepMode);
+ }
+ out.attribute(null, SLEEP_ATT_START_HR, Integer.toString(sleepStartHour));
+ out.attribute(null, SLEEP_ATT_START_MIN, Integer.toString(sleepStartMinute));
+ out.attribute(null, SLEEP_ATT_END_HR, Integer.toString(sleepEndHour));
+ out.attribute(null, SLEEP_ATT_END_MIN, Integer.toString(sleepEndMinute));
+ out.endTag(null, SLEEP_TAG);
+
+ out.endTag(null, ZEN_TAG);
+ }
+
+ public static boolean isValidHour(int val) {
+ return val >= 0 && val < 24;
+ }
+
+ public static boolean isValidMinute(int val) {
+ return val >= 0 && val < 60;
+ }
+
+ private static boolean safeBoolean(XmlPullParser parser, String att, boolean defValue) {
+ final String val = parser.getAttributeValue(null, att);
+ if (TextUtils.isEmpty(val)) return defValue;
+ return Boolean.valueOf(val);
+ }
+
+ private static int safeInt(XmlPullParser parser, String att, int defValue) {
+ final String val = parser.getAttributeValue(null, att);
+ if (TextUtils.isEmpty(val)) return defValue;
+ return Integer.valueOf(val);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public ZenModeConfig copy() {
+ final Parcel parcel = Parcel.obtain();
+ try {
+ writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return new ZenModeConfig(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ public static final Parcelable.Creator<ZenModeConfig> CREATOR
+ = new Parcelable.Creator<ZenModeConfig>() {
+ @Override
+ public ZenModeConfig createFromParcel(Parcel source) {
+ return new ZenModeConfig(source);
+ }
+
+ @Override
+ public ZenModeConfig[] newArray(int size) {
+ return new ZenModeConfig[size];
+ }
+ };
+}
diff --git a/core/java/android/service/voice/IVoiceInteractionService.aidl b/core/java/android/service/voice/IVoiceInteractionService.aidl
new file mode 100644
index 0000000..e9e2f4c
--- /dev/null
+++ b/core/java/android/service/voice/IVoiceInteractionService.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+/**
+ * @hide
+ */
+oneway interface IVoiceInteractionService {
+}
diff --git a/media/java/android/media/session/IMediaSessionManager.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
similarity index 62%
copy from media/java/android/media/session/IMediaSessionManager.aidl
copy to core/java/android/service/voice/IVoiceInteractionSession.aidl
index 0b4328e..7dbf66b 100644
--- a/media/java/android/media/session/IMediaSessionManager.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -1,4 +1,5 @@
-/* Copyright (C) 2014 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.
@@ -13,16 +14,15 @@
* limitations under the License.
*/
-package android.media.session;
+package android.service.voice;
-import android.media.session.IMediaSession;
-import android.media.session.IMediaSessionCallback;
import android.os.Bundle;
+import com.android.internal.app.IVoiceInteractorCallback;
+import com.android.internal.app.IVoiceInteractorRequest;
+
/**
- * Interface to the MediaSessionManagerService
* @hide
*/
-interface IMediaSessionManager {
- IMediaSession createSession(String packageName, in IMediaSessionCallback cb, String tag);
-}
\ No newline at end of file
+interface IVoiceInteractionSession {
+}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
new file mode 100644
index 0000000..ed93b74
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -0,0 +1,77 @@
+/**
+ * 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.annotation.SdkConstant;
+import android.app.Instrumentation;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import com.android.internal.app.IVoiceInteractionManagerService;
+
+public class VoiceInteractionService extends Service {
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ * To be supported, the service must also require the
+ * {@link android.Manifest.permission#BIND_VOICE_INTERACTION} permission so
+ * that other applications can not abuse it.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE =
+ "android.service.voice.VoiceInteractionService";
+
+ /**
+ * Name under which a VoiceInteractionService component publishes information about itself.
+ * This meta-data should reference an XML resource containing a
+ * <code><{@link
+ * android.R.styleable#VoiceInteractionService voice-interaction-service}></code> tag.
+ */
+ public static final String SERVICE_META_DATA = "android.voice_interaction";
+
+ IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
+ };
+
+ IVoiceInteractionManagerService mSystemService;
+
+ public void startVoiceActivity(Intent intent, VoiceInteractionSession session) {
+ try {
+ int res = mSystemService.startVoiceActivity(intent,
+ intent.resolveType(getContentResolver()),
+ mInterface, session.mSession, session.mInteractor);
+ Instrumentation.checkStartActivityResult(res, intent);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
+ ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mInterface.asBinder();
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
new file mode 100644
index 0000000..59544be
--- /dev/null
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -0,0 +1,195 @@
+/**
+ * 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.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+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;
+import com.android.internal.app.IVoiceInteractorRequest;
+import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
+
+public abstract class VoiceInteractionSession {
+ static final String TAG = "VoiceInteractionSession";
+ static final boolean DEBUG = true;
+
+ final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
+ @Override
+ public IVoiceInteractorRequest startConfirmation(String callingPackage,
+ IVoiceInteractorCallback callback, String prompt, Bundle extras) {
+ Request request = findRequest(callback, true);
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_CONFIRMATION,
+ new Caller(callingPackage, Binder.getCallingUid()), request,
+ prompt, extras));
+ return request.mInterface;
+ }
+
+ @Override
+ public IVoiceInteractorRequest startCommand(String callingPackage,
+ IVoiceInteractorCallback callback, String command, Bundle extras) {
+ Request request = findRequest(callback, true);
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_START_COMMAND,
+ new Caller(callingPackage, Binder.getCallingUid()), request,
+ command, extras));
+ return request.mInterface;
+ }
+
+ @Override
+ public boolean[] supportsCommands(String callingPackage, String[] commands) {
+ Message msg = mHandlerCaller.obtainMessageIOO(MSG_SUPPORTS_COMMANDS,
+ 0, new Caller(callingPackage, Binder.getCallingUid()), commands);
+ SomeArgs args = mHandlerCaller.sendMessageAndWait(msg);
+ if (args != null) {
+ boolean[] res = (boolean[])args.arg1;
+ args.recycle();
+ return res;
+ }
+ return new boolean[commands.length];
+ }
+ };
+
+ final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
+ };
+
+ public static class Request {
+ final IVoiceInteractorRequest mInterface = new IVoiceInteractorRequest.Stub() {
+ @Override
+ public void cancel() throws RemoteException {
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_CANCEL, Request.this));
+ }
+ };
+ final IVoiceInteractorCallback mCallback;
+ final HandlerCaller mHandlerCaller;
+ Request(IVoiceInteractorCallback callback, HandlerCaller handlerCaller) {
+ mCallback = callback;
+ mHandlerCaller = handlerCaller;
+ }
+
+ public void sendConfirmResult(boolean confirmed, Bundle result) {
+ try {
+ if (DEBUG) Log.d(TAG, "sendConfirmResult: req=" + mInterface
+ + " confirmed=" + confirmed + " result=" + result);
+ mCallback.deliverConfirmationResult(mInterface, confirmed, result);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void sendCommandResult(Bundle result) {
+ try {
+ if (DEBUG) Log.d(TAG, "sendCommandResult: req=" + mInterface
+ + " result=" + result);
+ mCallback.deliverCommandResult(mInterface, result);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void sendCancelResult() {
+ try {
+ if (DEBUG) Log.d(TAG, "sendCancelResult: req=" + mInterface);
+ mCallback.deliverCancel(mInterface);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ public static class Caller {
+ final String packageName;
+ final int uid;
+
+ Caller(String _packageName, int _uid) {
+ packageName = _packageName;
+ uid = _uid;
+ }
+ }
+
+ static final int MSG_START_CONFIRMATION = 1;
+ static final int MSG_START_COMMAND = 2;
+ static final int MSG_SUPPORTS_COMMANDS = 3;
+ static final int MSG_CANCEL = 4;
+
+ final Context mContext;
+ final 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_START_CONFIRMATION:
+ if (DEBUG) Log.d(TAG, "onConfirm: req=" + ((Request) args.arg2).mInterface
+ + " prompt=" + args.arg3 + " extras=" + args.arg4);
+ onConfirm((Caller)args.arg1, (Request)args.arg2, (String)args.arg3,
+ (Bundle)args.arg4);
+ break;
+ case MSG_START_COMMAND:
+ if (DEBUG) Log.d(TAG, "onCommand: req=" + ((Request) args.arg2).mInterface
+ + " command=" + args.arg3 + " extras=" + args.arg4);
+ onCommand((Caller) args.arg1, (Request) args.arg2, (String) args.arg3,
+ (Bundle) args.arg4);
+ break;
+ case MSG_SUPPORTS_COMMANDS:
+ if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg2);
+ args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
+ break;
+ case MSG_CANCEL:
+ if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
+ onCancel((Request)args.arg1);
+ break;
+ }
+ }
+ };
+
+ final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<IBinder, Request>();
+
+ public VoiceInteractionSession(Context context) {
+ this(context, new Handler());
+ }
+
+ public VoiceInteractionSession(Context context, Handler handler) {
+ mContext = context;
+ mHandlerCaller = new HandlerCaller(context, handler.getLooper(),
+ mHandlerCallerCallback, true);
+ }
+
+ Request findRequest(IVoiceInteractorCallback callback, boolean newRequest) {
+ synchronized (this) {
+ Request req = mActiveRequests.get(callback.asBinder());
+ if (req != null) {
+ if (newRequest) {
+ throw new IllegalArgumentException("Given request callback " + callback
+ + " is already active");
+ }
+ return req;
+ }
+ req = new Request(callback, mHandlerCaller);
+ mActiveRequests.put(callback.asBinder(), req);
+ return req;
+ }
+ }
+
+ public abstract boolean[] onGetSupportedCommands(Caller caller, String[] commands);
+ public abstract void onConfirm(Caller caller, Request request, String prompt, Bundle extras);
+ public abstract void onCommand(Caller caller, Request request, String command, Bundle extras);
+ public abstract void onCancel(Request request);
+}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 638ef22..f7ac75a 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -653,7 +653,7 @@
int extra;
- if (needMultiply) {
+ if (needMultiply && end != bufEnd) {
double ex = (below - above) * (spacingmult - 1) + spacingadd;
if (ex >= 0) {
extra = (int)(ex + EXTRA_ROUNDING);
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 966b24d..9081234 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -256,11 +256,45 @@
@Override
protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
TransitionValuesMaps endValues) {
+ startValues = removeExcludes(startValues);
+ endValues = removeExcludes(endValues);
for (Transition childTransition : mTransitions) {
childTransition.createAnimators(sceneRoot, startValues, endValues);
}
}
+ private TransitionValuesMaps removeExcludes(TransitionValuesMaps values) {
+ if (mTargetIds.isEmpty() && mTargetIdExcludes == null && mTargetTypeExcludes == null
+ && mTargets.isEmpty()) {
+ return values;
+ }
+ TransitionValuesMaps included = new TransitionValuesMaps();
+ int numValues = values.viewValues.size();
+ for (int i = 0; i < numValues; i++) {
+ View view = values.viewValues.keyAt(i);
+ if (isValidTarget(view, view.getId())) {
+ included.viewValues.put(view, values.viewValues.valueAt(i));
+ }
+ }
+ numValues = values.idValues.size();
+ for (int i = 0; i < numValues; i++) {
+ int id = values.idValues.keyAt(i);
+ TransitionValues transitionValues = values.idValues.valueAt(i);
+ if (isValidTarget(transitionValues.view, id)) {
+ included.idValues.put(id, transitionValues);
+ }
+ }
+ numValues = values.itemIdValues.size();
+ for (int i = 0; i < numValues; i++) {
+ long id = values.itemIdValues.keyAt(i);
+ TransitionValues transitionValues = values.itemIdValues.valueAt(i);
+ if (isValidTarget(transitionValues.view, id)) {
+ included.itemIdValues.put(id, transitionValues);
+ }
+ }
+ return included;
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/tv/ITvInputManager.aidl b/core/java/android/tv/ITvInputManager.aidl
index a927dc9..a4c99e4 100644
--- a/core/java/android/tv/ITvInputManager.aidl
+++ b/core/java/android/tv/ITvInputManager.aidl
@@ -17,6 +17,7 @@
package android.tv;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.net.Uri;
import android.tv.ITvInputClient;
import android.tv.TvInputInfo;
@@ -40,4 +41,9 @@
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
void setVolume(in IBinder sessionToken, float volume, int userId);
void tune(in IBinder sessionToken, in Uri channelUri, int userId);
+
+ void createOverlayView(in IBinder sessionToken, in IBinder windowToken, in Rect frame,
+ int userId);
+ void relayoutOverlayView(in IBinder sessionToken, in Rect frame, int userId);
+ void removeOverlayView(in IBinder sessionToken, int userId);
}
diff --git a/core/java/android/tv/ITvInputService.aidl b/core/java/android/tv/ITvInputService.aidl
index d80f286..672784f 100644
--- a/core/java/android/tv/ITvInputService.aidl
+++ b/core/java/android/tv/ITvInputService.aidl
@@ -17,7 +17,6 @@
package android.tv;
import android.tv.ITvInputServiceCallback;
-import android.tv.ITvInputSession;
import android.tv.ITvInputSessionCallback;
/**
diff --git a/core/java/android/tv/ITvInputSession.aidl b/core/java/android/tv/ITvInputSession.aidl
index d379d2d..32fee4b 100644
--- a/core/java/android/tv/ITvInputSession.aidl
+++ b/core/java/android/tv/ITvInputSession.aidl
@@ -16,6 +16,7 @@
package android.tv;
+import android.graphics.Rect;
import android.net.Uri;
import android.view.Surface;
@@ -31,4 +32,8 @@
// is to introduce some new concepts that will solve a number of problems in audio policy today.
void setVolume(float volume);
void tune(in Uri channelUri);
+
+ void createOverlayView(in IBinder windowToken, in Rect frame);
+ void relayoutOverlayView(in Rect frame);
+ void removeOverlayView();
}
diff --git a/core/java/android/tv/ITvInputSessionWrapper.java b/core/java/android/tv/ITvInputSessionWrapper.java
index 66fe5e1..a6e0877 100644
--- a/core/java/android/tv/ITvInputSessionWrapper.java
+++ b/core/java/android/tv/ITvInputSessionWrapper.java
@@ -17,13 +17,16 @@
package android.tv;
import android.content.Context;
+import android.graphics.Rect;
import android.net.Uri;
+import android.os.IBinder;
import android.os.Message;
import android.tv.TvInputService.TvInputSessionImpl;
import android.util.Log;
import android.view.Surface;
import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
/**
* Implements the internal ITvInputSession interface to convert incoming calls on to it back to
@@ -38,6 +41,9 @@
private static final int DO_SET_SURFACE = 2;
private static final int DO_SET_VOLUME = 3;
private static final int DO_TUNE = 4;
+ private static final int DO_CREATE_OVERLAY_VIEW = 5;
+ private static final int DO_RELAYOUT_OVERLAY_VIEW = 6;
+ private static final int DO_REMOVE_OVERLAY_VIEW = 7;
private TvInputSessionImpl mTvInputSession;
private final HandlerCaller mCaller;
@@ -71,6 +77,20 @@
mTvInputSession.tune((Uri) msg.obj);
return;
}
+ case DO_CREATE_OVERLAY_VIEW: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ mTvInputSession.createOverlayView((IBinder) args.arg1, (Rect) args.arg2);
+ args.recycle();
+ return;
+ }
+ case DO_RELAYOUT_OVERLAY_VIEW: {
+ mTvInputSession.relayoutOverlayView((Rect) msg.obj);
+ return;
+ }
+ case DO_REMOVE_OVERLAY_VIEW: {
+ mTvInputSession.removeOverlayView(true);
+ return;
+ }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
return;
@@ -97,4 +117,20 @@
public void tune(Uri channelUri) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_TUNE, channelUri));
}
+
+ @Override
+ public void createOverlayView(IBinder windowToken, Rect frame) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_OVERLAY_VIEW, windowToken,
+ frame));
+ }
+
+ @Override
+ public void relayoutOverlayView(Rect frame) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RELAYOUT_OVERLAY_VIEW, frame));
+ }
+
+ @Override
+ public void removeOverlayView() {
+ mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_OVERLAY_VIEW));
+ }
}
diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java
index 4cf2b35..05f0b9c 100644
--- a/core/java/android/tv/TvInputManager.java
+++ b/core/java/android/tv/TvInputManager.java
@@ -17,6 +17,7 @@
package android.tv;
import android.content.ComponentName;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@@ -24,6 +25,7 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.Surface;
+import android.view.View;
import java.util.ArrayList;
import java.util.HashMap;
@@ -320,8 +322,8 @@
/** The Session provides the per-session functionality of TV inputs. */
public static final class Session {
private final ITvInputManager mService;
- private final IBinder mToken;
private final int mUserId;
+ private IBinder mToken;
/** @hide */
private Session(ComponentName name, IBinder token, ITvInputManager service, int userId) {
@@ -332,10 +334,16 @@
/**
* Releases this session.
+ *
+ * @throws IllegalStateException if the session has been already released.
*/
public void release() {
+ if (mToken == null) {
+ throw new IllegalStateException("the session has been already released");
+ }
try {
mService.releaseSession(mToken, mUserId);
+ mToken = null;
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -345,8 +353,12 @@
* Sets the {@link android.view.Surface} for this session.
*
* @param surface A {@link android.view.Surface} used to render video.
+ * @throws IllegalStateException if the session has been already released.
*/
- public void setSurface(Surface surface) {
+ void setSurface(Surface surface) {
+ if (mToken == null) {
+ throw new IllegalStateException("the session has been already released");
+ }
// surface can be null.
try {
mService.setSurface(mToken, surface, mUserId);
@@ -360,8 +372,12 @@
*
* @param volume A volume value between 0.0f to 1.0f.
* @throws IllegalArgumentException if the volume value is out of range.
+ * @throws IllegalStateException if the session has been already released.
*/
public void setVolume(float volume) {
+ if (mToken == null) {
+ throw new IllegalStateException("the session has been already released");
+ }
try {
if (volume < 0.0f || volume > 1.0f) {
throw new IllegalArgumentException("volume should be between 0.0f and 1.0f");
@@ -377,16 +393,90 @@
*
* @param channelUri The URI of a channel.
* @throws IllegalArgumentException if the argument is {@code null}.
+ * @throws IllegalStateException if the session has been already released.
*/
public void tune(Uri channelUri) {
if (channelUri == null) {
throw new IllegalArgumentException("channelUri cannot be null");
}
+ if (mToken == null) {
+ throw new IllegalStateException("the session has been already released");
+ }
try {
mService.tune(mToken, channelUri, mUserId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
+
+ /**
+ * Creates an overlay view. Once the overlay view is created, {@link #relayoutOverlayView}
+ * should be called whenever the layout of its containing view is changed.
+ * {@link #removeOverlayView()} should be called to remove the overlay view.
+ * Since a session can have only one overlay view, this method should be called only once
+ * or it can be called again after calling {@link #removeOverlayView()}.
+ *
+ * @param view A view playing TV.
+ * @param frame A position of the overlay view.
+ * @throws IllegalArgumentException if any of the arguments is {@code null}.
+ * @throws IllegalStateException if {@code view} is not attached to a window or
+ * if the session has been already released.
+ */
+ void createOverlayView(View view, Rect frame) {
+ if (view == null) {
+ throw new IllegalArgumentException("view cannot be null");
+ }
+ if (frame == null) {
+ throw new IllegalArgumentException("frame cannot be null");
+ }
+ if (view.getWindowToken() == null) {
+ throw new IllegalStateException("view must be attached to a window");
+ }
+ if (mToken == null) {
+ throw new IllegalStateException("the session has been already released");
+ }
+ try {
+ mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Relayouts the current overlay view.
+ *
+ * @param frame A new position of the overlay view.
+ * @throws IllegalArgumentException if the arguments is {@code null}.
+ * @throws IllegalStateException if the session has been already released.
+ */
+ void relayoutOverlayView(Rect frame) {
+ if (frame == null) {
+ throw new IllegalArgumentException("frame cannot be null");
+ }
+ if (mToken == null) {
+ throw new IllegalStateException("the session has been already released");
+ }
+ try {
+ mService.relayoutOverlayView(mToken, frame, mUserId);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Removes the current overlay view.
+ *
+ * @throws IllegalStateException if the session has been already released.
+ */
+ void removeOverlayView() {
+ if (mToken == null) {
+ throw new IllegalStateException("the session has been already released");
+ }
+ try {
+ mService.removeOverlayView(mToken, mUserId);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
}
diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java
index d7f6c32..80eb407 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/core/java/android/tv/TvInputService.java
@@ -18,7 +18,10 @@
import android.app.Service;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@@ -26,7 +29,10 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
+import android.view.Gravity;
import android.view.Surface;
+import android.view.View;
+import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -125,7 +131,37 @@
/**
* Base class for derived classes to implement to provide {@link TvInputManager.Session}.
*/
- public abstract static class TvInputSessionImpl {
+ public abstract class TvInputSessionImpl {
+ private final WindowManager mWindowManager;
+ private WindowManager.LayoutParams mWindowParams;
+ private View mOverlayView;
+ private boolean mOverlayViewEnabled;
+ private IBinder mWindowToken;
+ private Rect mOverlayFrame;
+
+ public TvInputSessionImpl() {
+ mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+ }
+
+ public void setOverlayViewEnabled(final boolean enable) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (enable == mOverlayViewEnabled) {
+ return;
+ }
+ mOverlayViewEnabled = enable;
+ if (enable) {
+ if (mWindowToken != null) {
+ createOverlayView(mWindowToken, mOverlayFrame);
+ }
+ } else {
+ removeOverlayView(false);
+ }
+ }
+ });
+ }
+
/**
* Called when the session is released.
*/
@@ -157,11 +193,22 @@
public abstract boolean onTune(Uri channelUri);
/**
+ * Called when an application requests to create an overlay view. Each session
+ * implementation can override this method and return its own view.
+ *
+ * @return a view attached to the overlay window
+ */
+ public View onCreateOverlayView() {
+ return null;
+ }
+
+ /**
* This method is called when the application would like to stop using the current input
* session.
*/
void release() {
onRelease();
+ removeOverlayView(true);
}
/**
@@ -186,6 +233,87 @@
onTune(channelUri);
// TODO: Handle failure.
}
+
+ /**
+ * Creates an overlay view. This calls {@link onCreateOverlayView} to get
+ * a view to attach to the overlay window.
+ *
+ * @param windowToken A window token of an application.
+ * @param frame A position of the overlay view.
+ */
+ void createOverlayView(IBinder windowToken, Rect frame) {
+ if (mOverlayView != null) {
+ mWindowManager.removeView(mOverlayView);
+ mOverlayView = null;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "create overlay view(" + frame + ")");
+ }
+ mWindowToken = windowToken;
+ mOverlayFrame = frame;
+ if (!mOverlayViewEnabled) {
+ return;
+ }
+ mOverlayView = onCreateOverlayView();
+ if (mOverlayView == null) {
+ return;
+ }
+ // TvView's window type is TYPE_APPLICATION_MEDIA and we want to create
+ // an overlay window above the media window but below the application window.
+ int type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+ // We make the overlay view non-focusable and non-touchable so that
+ // the application that owns the window token can decide whether to consume or
+ // dispatch the input events.
+ int flag = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ mWindowParams = new WindowManager.LayoutParams(
+ frame.right - frame.left, frame.bottom - frame.top,
+ frame.left, frame.top, type, flag, PixelFormat.TRANSPARENT);
+ mWindowParams.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ mWindowParams.gravity = Gravity.START | Gravity.TOP;
+ mWindowParams.token = windowToken;
+ mWindowManager.addView(mOverlayView, mWindowParams);
+ }
+
+ /**
+ * Relayouts the current overlay view.
+ *
+ * @param frame A new position of the overlay view.
+ */
+ void relayoutOverlayView(Rect frame) {
+ if (DEBUG) {
+ Log.d(TAG, "relayout overlay view(" + frame + ")");
+ }
+ mOverlayFrame = frame;
+ if (!mOverlayViewEnabled || mOverlayView == null) {
+ return;
+ }
+ mWindowParams.x = frame.left;
+ mWindowParams.y = frame.top;
+ mWindowParams.width = frame.right - frame.left;
+ mWindowParams.height = frame.bottom - frame.top;
+ mWindowManager.updateViewLayout(mOverlayView, mWindowParams);
+ }
+
+ /**
+ * Removes the current overlay view.
+ */
+ void removeOverlayView(boolean clearWindowToken) {
+ if (DEBUG) {
+ Log.d(TAG, "remove overlay view(" + mOverlayView + ")");
+ }
+ if (clearWindowToken) {
+ mWindowToken = null;
+ mOverlayFrame = null;
+ }
+ if (mOverlayView != null) {
+ mWindowManager.removeView(mOverlayView);
+ mOverlayView = null;
+ mWindowParams = null;
+ }
+ }
}
private final class ServiceHandler extends Handler {
diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java
new file mode 100644
index 0000000..325950d
--- /dev/null
+++ b/core/java/android/tv/TvView.java
@@ -0,0 +1,228 @@
+/*
+ * 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.tv;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.tv.TvInputManager;
+import android.tv.TvInputManager.Session;
+import android.tv.TvInputManager.SessionCreateCallback;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewTreeObserver;
+
+/**
+ * View playing TV
+ */
+public class TvView extends SurfaceView {
+ private static final String TAG = "TvView";
+
+ private final Handler mHandler = new Handler();
+ private TvInputManager.Session mSession;
+ private Surface mSurface;
+ private boolean mOverlayViewCreated;
+ private Rect mOverlayViewFrame;
+ private boolean mGlobalListenersAdded;
+ private TvInputManager mTvInputManager;
+ private SessionCreateCallback mSessionCreateCallback;
+
+ private SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.d(TAG, "surfaceChanged(holder=" + holder + ", format=" + format + ", width=" + width
+ + ", height=" + height + ")");
+ if (holder.getSurface() == mSurface) {
+ return;
+ }
+ mSurface = holder.getSurface();
+ setSessionSurface(mSurface);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ mSurface = holder.getSurface();
+ setSessionSurface(mSurface);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mSurface = null;
+ setSessionSurface(null);
+ }
+ };
+
+ public TvView(Context context) {
+ this(context, null, 0);
+ }
+
+ public TvView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TvView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ getHolder().addCallback(mSurfaceHolderCallback);
+ mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
+ }
+
+ /**
+ * Binds a TV input to this view. {@link SessionCreateCallback#onSessionCreated} will be
+ * called to send the result of this binding with {@link TvInputManager.Session}.
+ * If a TV input is already bound, the input will be unbound from this view and its session
+ * will be released.
+ *
+ * @param name TV input name will be bound to this view.
+ * @param callback called when TV input is bound. The callback sends
+ * {@link TvInputManager.Session}
+ * @throws IllegalArgumentException if any of the arguments is {@code null}.
+ */
+ public void bindTvInput(ComponentName name, SessionCreateCallback callback) {
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+ if (callback == null) {
+ throw new IllegalArgumentException("callback cannot be null");
+ }
+ if (mSession != null) {
+ release();
+ }
+ // When bindTvInput is called multiple times before the callback is called,
+ // only the callback of the last bindTvInput call will be actually called back.
+ // The previous callbacks will be ignored. For the logic, mSessionCreateCallback
+ // is newly assigned for every bindTvInput call and compared with
+ // MySessionCreateCallback.this.
+ mSessionCreateCallback = new MySessionCreateCallback(callback);
+ mTvInputManager.createSession(name, mSessionCreateCallback, mHandler);
+ }
+
+ /**
+ * Unbinds a TV input currently bound. Its corresponding {@link TvInputManager.Session}
+ * is released.
+ */
+ public void unbindTvInput() {
+ if (mSession != null) {
+ release();
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ createSessionOverlayView();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ removeSessionOverlayView();
+ super.onDetachedFromWindow();
+ }
+
+ /** @hide */
+ @Override
+ protected void updateWindow(boolean force, boolean redrawNeeded) {
+ super.updateWindow(force, redrawNeeded);
+ relayoutSessionOverlayView();
+ }
+
+ private void release() {
+ setSessionSurface(null);
+ removeSessionOverlayView();
+ mSession.release();
+ mSession = null;
+ }
+
+ private void setSessionSurface(Surface surface) {
+ if (mSession == null) {
+ return;
+ }
+ mSession.setSurface(surface);
+ }
+
+ private void createSessionOverlayView() {
+ if (mSession == null || !isAttachedToWindow()
+ || mOverlayViewCreated) {
+ return;
+ }
+ mOverlayViewFrame = getViewFrameOnScreen();
+ mSession.createOverlayView(this, mOverlayViewFrame);
+ mOverlayViewCreated = true;
+ }
+
+ private void removeSessionOverlayView() {
+ if (mSession == null || !mOverlayViewCreated) {
+ return;
+ }
+ mSession.removeOverlayView();
+ mOverlayViewCreated = false;
+ mOverlayViewFrame = null;
+ }
+
+ private void relayoutSessionOverlayView() {
+ if (mSession == null || !isAttachedToWindow()
+ || !mOverlayViewCreated) {
+ return;
+ }
+ Rect viewFrame = getViewFrameOnScreen();
+ if (viewFrame.equals(mOverlayViewFrame)) {
+ return;
+ }
+ mSession.relayoutOverlayView(viewFrame);
+ mOverlayViewFrame = viewFrame;
+ }
+
+ private Rect getViewFrameOnScreen() {
+ int[] location = new int[2];
+ getLocationOnScreen(location);
+ return new Rect(location[0], location[1],
+ location[0] + getWidth(), location[1] + getHeight());
+ }
+
+ private class MySessionCreateCallback implements SessionCreateCallback {
+ final SessionCreateCallback mExternalCallback;
+
+ MySessionCreateCallback(SessionCreateCallback externalCallback) {
+ mExternalCallback = externalCallback;
+ }
+
+ @Override
+ public void onSessionCreated(Session session) {
+ if (this != mSessionCreateCallback) {
+ // This callback is obsolete.
+ session.release();
+ return;
+ }
+ mSession = session;
+ if (session != null) {
+ // mSurface may not be ready yet as soon as starting an application.
+ // In the case, we don't send Session.setSurface(null) unnecessarily.
+ // setSessionSurface will be called in surfaceCreated.
+ if (mSurface != null) {
+ setSessionSurface(mSurface);
+ }
+ createSessionOverlayView();
+ }
+ if (mExternalCallback != null) {
+ mExternalCallback.onSessionCreated(session);
+ }
+ }
+ }
+}
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 29c0ba2..aefced8 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -56,16 +56,18 @@
public static final class Event {
private final ByteBuffer mBuffer;
- // Layout of event log entry received from kernel.
+ // Layout of event log entry received from Android logger.
+ // see system/core/include/log/logger.h
private static final int LENGTH_OFFSET = 0;
+ private static final int HEADER_SIZE_OFFSET = 2;
private static final int PROCESS_OFFSET = 4;
private static final int THREAD_OFFSET = 8;
private static final int SECONDS_OFFSET = 12;
private static final int NANOSECONDS_OFFSET = 16;
- private static final int PAYLOAD_START = 20;
- private static final int TAG_OFFSET = 20;
- private static final int DATA_START = 24;
+ // Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET
+ private static final int V1_PAYLOAD_START = 20;
+ private static final int DATA_OFFSET = 4;
// Value types
private static final byte INT_TYPE = 0;
@@ -97,14 +99,22 @@
/** @return the type tag code of the entry */
public int getTag() {
- return mBuffer.getInt(TAG_OFFSET);
+ int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
+ if (offset == 0) {
+ offset = V1_PAYLOAD_START;
+ }
+ return mBuffer.getInt(offset);
}
/** @return one of Integer, Long, String, null, or Object[] of same. */
public synchronized Object getData() {
try {
- mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
- mBuffer.position(DATA_START); // Just after the tag.
+ int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
+ if (offset == 0) {
+ offset = V1_PAYLOAD_START;
+ }
+ mBuffer.limit(offset + mBuffer.getShort(LENGTH_OFFSET));
+ mBuffer.position(offset + DATA_OFFSET); // Just after the tag.
return decodeObject();
} catch (IllegalArgumentException e) {
Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index abd173a..2b81072 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -352,6 +352,7 @@
/** @hide */ public static final int LOG_ID_RADIO = 1;
/** @hide */ public static final int LOG_ID_EVENTS = 2;
/** @hide */ public static final int LOG_ID_SYSTEM = 3;
+ /** @hide */ public static final int LOG_ID_CRASH = 4;
/** @hide */ public static native int println_native(int bufID,
int priority, String tag, String msg);
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 13cc88b..2cc91b9 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -130,7 +130,10 @@
private static final String IRI
= "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
- private static final String HOST_NAME = IRI + "(?:\\." + IRI + ")+";
+ private static final String GOOD_GTLD_CHAR =
+ "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
+ private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}";
+ private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD;
public static final Pattern DOMAIN_NAME
= Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index f0d8a61..34b85d9 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -1117,11 +1117,11 @@
}
@Override
- public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
+ public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ Paint paint) {
int modifiers = setupModifiers(paint, MODIFIER_SHADER);
try {
- nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
- rx, ry, paint.mNativePaint);
+ nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
} finally {
if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
}
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index a7ee12b..71296fa 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -161,6 +161,7 @@
} else if (tagName.equals(XML_MENU)) {
// A menu start tag denotes a submenu for an item
SubMenu subMenu = menuState.addSubMenuItem();
+ registerMenu(subMenu, attrs);
// Parse the submenu into returned SubMenu
parseMenu(parser, attrs, subMenu);
@@ -183,9 +184,9 @@
if (!menuState.hasAddedItem()) {
if (menuState.itemActionProvider != null &&
menuState.itemActionProvider.hasSubMenu()) {
- menuState.addSubMenuItem();
+ registerMenu(menuState.addSubMenuItem(), attrs);
} else {
- menuState.addItem();
+ registerMenu(menuState.addItem(), attrs);
}
}
} else if (tagName.equals(XML_MENU)) {
@@ -200,7 +201,30 @@
eventType = parser.next();
}
}
-
+
+ /**
+ * The method is a hook for layoutlib to do its magic.
+ * Nothing is needed outside of LayoutLib. However, it should not be deleted because it
+ * appears to do nothing.
+ */
+ private void registerMenu(@SuppressWarnings("unused") MenuItem item,
+ @SuppressWarnings("unused") AttributeSet set) {
+ }
+
+ /**
+ * The method is a hook for layoutlib to do its magic.
+ * Nothing is needed outside of LayoutLib. However, it should not be deleted because it
+ * appears to do nothing.
+ */
+ private void registerMenu(@SuppressWarnings("unused") SubMenu subMenu,
+ @SuppressWarnings("unused") AttributeSet set) {
+ }
+
+ // Needed by layoutlib.
+ /*package*/ Context getContext() {
+ return mContext;
+ }
+
private static class InflatedOnMenuItemClickListener
implements MenuItem.OnMenuItemClickListener {
private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
@@ -446,9 +470,11 @@
}
}
- public void addItem() {
+ public MenuItem addItem() {
itemAdded = true;
- setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle));
+ MenuItem item = menu.add(groupId, itemId, itemCategoryOrder, itemTitle);
+ setItem(item);
+ return item;
}
public SubMenu addSubMenuItem() {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 23123dd..4a2cc1a 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -422,7 +422,8 @@
mWindowType = type;
}
- private void updateWindow(boolean force, boolean redrawNeeded) {
+ /** @hide */
+ protected void updateWindow(boolean force, boolean redrawNeeded) {
if (!mHaveFrame) {
return;
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 60d7c78..924c331 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -178,11 +178,14 @@
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
- callbacks.onHardwarePostDraw(canvas);
- canvas.drawDisplayList(view.getDisplayList());
- callbacks.onHardwarePostDraw(canvas);
- mRootNode.end(canvas);
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ try {
+ callbacks.onHardwarePostDraw(canvas);
+ canvas.drawDisplayList(view.getDisplayList());
+ callbacks.onHardwarePostDraw(canvas);
+ } finally {
+ mRootNode.end(canvas);
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
view.mRecreateDisplayList = false;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f44cc87..fdf31fa 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27,7 +27,6 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Interpolator;
@@ -720,6 +719,11 @@
private static boolean sIgnoreMeasureCache = false;
/**
+ * Ignore the clipBounds of this view for the children.
+ */
+ static boolean sIgnoreClipBoundsForChildren = false;
+
+ /**
* This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
* calling setFlags.
*/
@@ -2371,24 +2375,26 @@
static final int PFLAG3_CALLED_SUPER = 0x10;
/**
- * Flag indicating that an view will be clipped to its outline.
- */
- static final int PFLAG3_CLIP_TO_OUTLINE = 0x20;
-
- /**
* Flag indicating that a view's outline has been specifically defined.
*/
- static final int PFLAG3_OUTLINE_DEFINED = 0x40;
+ static final int PFLAG3_OUTLINE_DEFINED = 0x20;
/**
* Flag indicating that we're in the process of applying window insets.
*/
- static final int PFLAG3_APPLYING_INSETS = 0x80;
+ static final int PFLAG3_APPLYING_INSETS = 0x40;
/**
* Flag indicating that we're in the process of fitting system windows using the old method.
*/
- static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x100;
+ static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x80;
+
+ /**
+ * Flag indicating that nested scrolling is enabled for this view.
+ * The view will optionally cooperate with views up its parent chain to allow for
+ * integrated nested scrolling along the same axis.
+ */
+ static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x200;
/* End of masks for mPrivateFlags3 */
@@ -2842,6 +2848,21 @@
public static final int SCREEN_STATE_ON = 0x1;
/**
+ * Indicates no axis of view scrolling.
+ */
+ public static final int SCROLL_AXIS_NONE = 0;
+
+ /**
+ * Indicates scrolling along the horizontal axis.
+ */
+ public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0;
+
+ /**
+ * Indicates scrolling along the vertical axis.
+ */
+ public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
+
+ /**
* Controls the over-scroll mode for this view.
* See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
* {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS},
@@ -2963,7 +2984,7 @@
/**
* Current clip bounds. to which all drawing of this view are constrained.
*/
- private Rect mClipBounds = null;
+ Rect mClipBounds = null;
private boolean mLastIsOpaque;
@@ -3232,9 +3253,7 @@
/**
* Stores the outline of the view, passed down to the DisplayList level for
- * defining shadow shape and clipping.
- *
- * TODO: once RenderNode is long-lived, remove this and rely on native copy.
+ * defining shadow shape.
*/
private Outline mOutline;
@@ -3468,6 +3487,14 @@
ViewOverlay mOverlay;
/**
+ * The currently active parent view for receiving delegated nested scrolling events.
+ * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared
+ * by {@link #stopNestedScroll()} at the same point where we clear
+ * requestDisallowInterceptTouchEvent.
+ */
+ private ViewParent mNestedScrollingParent;
+
+ /**
* Consistency verifier for debugging purposes.
* @hide
*/
@@ -3477,6 +3504,8 @@
private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
+ private int[] mTempNestedScrollConsumed;
+
/**
* Simple constructor to use when creating a view from code.
*
@@ -3511,6 +3540,9 @@
// of whether a layout was requested on that View.
sIgnoreMeasureCache = targetSdkVersion < KITKAT;
+ // Older apps may need this to ignore the clip bounds
+ sIgnoreClipBoundsForChildren = targetSdkVersion < L;
+
sCompatibilityDone = true;
}
}
@@ -3955,6 +3987,9 @@
case R.styleable.View_sharedElementName:
setSharedElementName(a.getString(attr));
break;
+ case R.styleable.View_nestedScrollingEnabled:
+ setNestedScrollingEnabled(a.getBoolean(attr, false));
+ break;
}
}
@@ -4729,13 +4764,13 @@
private void manageFocusHotspot(boolean focused, View v) {
if (mBackground != null && mBackground.supportsHotspots()) {
final Rect r = new Rect();
- if (v != null) {
+ if (!focused && v != null) {
v.getBoundsOnScreen(r);
final int[] location = new int[2];
getLocationOnScreen(location);
r.offset(-location[0], -location[1]);
} else {
- r.set(mLeft, mTop, mRight, mBottom);
+ r.set(0, 0, mRight - mLeft, mBottom - mTop);
}
final float x = r.exactCenterX();
@@ -4850,16 +4885,13 @@
if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
mPrivateFlags &= ~PFLAG_FOCUSED;
- if (hasFocus()) {
- manageFocusHotspot(false, focused);
- }
-
if (propagate && mParent != null) {
mParent.clearChildFocus(this);
}
onFocusChanged(false, 0, null);
+ manageFocusHotspot(false, focused);
refreshDrawableState();
if (propagate && (!refocus || !rootViewRequestFocus())) {
@@ -7971,27 +8003,46 @@
* @return True if the event was handled by the view, false otherwise.
*/
public boolean dispatchTouchEvent(MotionEvent event) {
+ boolean result = false;
+
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
+ final int actionMasked = event.getActionMasked();
+ if (actionMasked == MotionEvent.ACTION_DOWN) {
+ // Defensive cleanup for new gesture
+ stopNestedScroll();
+ }
+
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
- if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
+ if (li != null && li.mOnTouchListener != null
+ && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
- return true;
+ result = true;
}
- if (onTouchEvent(event)) {
- return true;
+ if (!result && onTouchEvent(event)) {
+ result = true;
}
}
- if (mInputEventConsistencyVerifier != null) {
+ if (!result && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
- return false;
+
+ // Clean up after nested scrolls if this is the end of a gesture;
+ // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
+ // of the gesture.
+ if (actionMasked == MotionEvent.ACTION_UP ||
+ actionMasked == MotionEvent.ACTION_CANCEL ||
+ (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
+ stopNestedScroll();
+ }
+
+ return result;
}
/**
@@ -10514,16 +10565,13 @@
/**
* Sets the outline of the view, which defines the shape of the shadow it
- * casts, and can used for clipping.
+ * casts.
* <p>
* If the outline is not set or is null, shadows will be cast from the
- * bounds of the View, and clipToOutline will be ignored.
+ * bounds of the View.
*
* @param outline The new outline of the view.
* Must be {@link android.graphics.Outline#isValid() valid.}
- *
- * @see #getClipToOutline()
- * @see #setClipToOutline(boolean)
*/
public void setOutline(@Nullable Outline outline) {
if (outline != null && !outline.isValid()) {
@@ -10537,46 +10585,33 @@
} else {
// always copy the path since caller may reuse
if (mOutline == null) {
- mOutline = new Outline();
+ mOutline = new Outline(outline);
}
- mOutline.set(outline);
}
mRenderNode.setOutline(mOutline);
}
- /**
- * Returns whether the outline of the View will be used for clipping.
- *
- * @see #setOutline(Outline)
- */
- public final boolean getClipToOutline() {
- return ((mPrivateFlags3 & PFLAG3_CLIP_TO_OUTLINE) != 0);
- }
+ // TODO: remove
+ public final boolean getClipToOutline() { return false; }
+ public void setClipToOutline(boolean clipToOutline) {}
- /**
- * Sets whether the outline of the View will be used for clipping.
- * <p>
- * The current implementation of outline clipping uses
- * {@link Canvas#clipPath(Path) path clipping},
- * and thus does not support anti-aliasing, and is expensive in terms of
- * graphics performance. Therefore, it is strongly recommended that this
- * property only be set temporarily, as in an animation. For the same
- * reasons, there is no parallel XML attribute for this property.
- * <p>
- * If the outline of the view is not set or is empty, no clipping will be
- * performed.
- *
- * @see #setOutline(Outline)
- */
- public void setClipToOutline(boolean clipToOutline) {
- // TODO : Add a fast invalidation here.
- if (getClipToOutline() != clipToOutline) {
- if (clipToOutline) {
- mPrivateFlags3 |= PFLAG3_CLIP_TO_OUTLINE;
+ private void queryOutlineFromBackgroundIfUndefined() {
+ if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
+ // Outline not currently defined, query from background
+ if (mOutline == null) {
+ mOutline = new Outline();
} else {
- mPrivateFlags3 &= ~PFLAG3_CLIP_TO_OUTLINE;
+ //invalidate outline, to ensure background calculates it
+ mOutline.set(null);
}
- mRenderNode.setClipToOutline(clipToOutline);
+ if (mBackground.getOutline(mOutline)) {
+ if (!mOutline.isValid()) {
+ throw new IllegalStateException("Background drawable failed to build outline");
+ }
+ mRenderNode.setOutline(mOutline);
+ } else {
+ mRenderNode.setOutline(null);
+ }
}
}
@@ -12726,10 +12761,15 @@
mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
+ if (mBackground != null) {
+ mBackground.clearHotspots();
+ }
+
removeUnsetPressCallback();
removeLongPressCallback();
removePerformClickCallback();
removeSendViewScrolledAccessibilityEventCallback();
+ stopNestedScroll();
destroyDrawingCache();
destroyLayer(false);
@@ -14834,11 +14874,7 @@
if (mBackgroundSizeChanged) {
background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
mBackgroundSizeChanged = false;
- if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
- // Outline not currently define, query from background
- mOutline = background.getOutline();
- mRenderNode.setOutline(mOutline);
- }
+ queryOutlineFromBackgroundIfUndefined();
}
// Attempt to use a display list if requested.
@@ -14892,8 +14928,11 @@
final int width = bounds.width();
final int height = bounds.height();
final HardwareCanvas canvas = displayList.start(width, height);
- drawable.draw(canvas);
- displayList.end(canvas);
+ try {
+ drawable.draw(canvas);
+ } finally {
+ displayList.end(canvas);
+ }
// Set up drawable properties that are view-independent.
displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
@@ -15237,7 +15276,7 @@
* @param drawable the drawable to invalidate
*/
@Override
- public void invalidateDrawable(Drawable drawable) {
+ public void invalidateDrawable(@NonNull Drawable drawable) {
if (verifyDrawable(drawable)) {
final Rect dirty = drawable.getDirtyBounds();
final int scrollX = mScrollX;
@@ -15245,6 +15284,10 @@
invalidate(dirty.left + scrollX, dirty.top + scrollY,
dirty.right + scrollX, dirty.bottom + scrollY);
+
+ if (drawable == mBackground) {
+ queryOutlineFromBackgroundIfUndefined();
+ }
}
}
@@ -17893,6 +17936,249 @@
}
/**
+ * Enable or disable nested scrolling for this view.
+ *
+ * <p>If this property is set to true the view will be permitted to initiate nested
+ * scrolling operations with a compatible parent view in the current hierarchy. If this
+ * view does not implement nested scrolling this will have no effect.</p>
+ *
+ * @param enabled true to enable nested scrolling, false to disable
+ *
+ * @see #isNestedScrollingEnabled()
+ */
+ public void setNestedScrollingEnabled(boolean enabled) {
+ if (enabled) {
+ mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED;
+ } else {
+ mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED;
+ }
+ }
+
+ /**
+ * Returns true if nested scrolling is enabled for this view.
+ *
+ * <p>If nested scrolling is enabled and this View class implementation supports it,
+ * this view will act as a nested scrolling child view when applicable, forwarding data
+ * about the scroll operation in progress to a compatible and cooperating nested scrolling
+ * parent.</p>
+ *
+ * @return true if nested scrolling is enabled
+ *
+ * @see #setNestedScrollingEnabled(boolean)
+ */
+ public boolean isNestedScrollingEnabled() {
+ return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) ==
+ PFLAG3_NESTED_SCROLLING_ENABLED;
+ }
+
+ /**
+ * Begin a nestable scroll operation along the given axes.
+ *
+ * <p>A view starting a nested scroll promises to abide by the following contract:</p>
+ *
+ * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case
+ * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}.
+ * In the case of touch scrolling the nested scroll will be terminated automatically in
+ * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}.
+ * In the event of programmatic scrolling the caller must explicitly call
+ * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p>
+ *
+ * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found.
+ * If it returns false the caller may ignore the rest of this contract until the next scroll.
+ * Calling startNestedScroll while a nested scroll is already in progress will return true.</p>
+ *
+ * <p>At each incremental step of the scroll the caller should invoke
+ * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll}
+ * once it has calculated the requested scrolling delta. If it returns true the nested scrolling
+ * parent at least partially consumed the scroll and the caller should adjust the amount it
+ * scrolls by.</p>
+ *
+ * <p>After applying the remainder of the scroll delta the caller should invoke
+ * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing
+ * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat
+ * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}.
+ * </p>
+ *
+ * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or
+ * {@link #SCROLL_AXIS_VERTICAL}.
+ * @return true if a cooperative parent was found and nested scrolling has been enabled for
+ * the current gesture.
+ *
+ * @see #stopNestedScroll()
+ * @see #dispatchNestedPreScroll(int, int, int[], int[])
+ * @see #dispatchNestedScroll(int, int, int, int, int[])
+ */
+ public boolean startNestedScroll(int axes) {
+ if (hasNestedScrollingParent()) {
+ // Already in progress
+ return true;
+ }
+ if (isNestedScrollingEnabled()) {
+ ViewParent p = getParent();
+ View child = this;
+ while (p != null) {
+ try {
+ if (p.onStartNestedScroll(child, this, axes)) {
+ mNestedScrollingParent = p;
+ p.onNestedScrollAccepted(child, this, axes);
+ return true;
+ }
+ } catch (AbstractMethodError e) {
+ Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " +
+ "method onStartNestedScroll", e);
+ // Allow the search upward to continue
+ }
+ if (p instanceof View) {
+ child = (View) p;
+ }
+ p = p.getParent();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Stop a nested scroll in progress.
+ *
+ * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p>
+ *
+ * @see #startNestedScroll(int)
+ */
+ public void stopNestedScroll() {
+ if (mNestedScrollingParent != null) {
+ mNestedScrollingParent.onStopNestedScroll(this);
+ mNestedScrollingParent = null;
+ }
+ }
+
+ /**
+ * Returns true if this view has a nested scrolling parent.
+ *
+ * <p>The presence of a nested scrolling parent indicates that this view has initiated
+ * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p>
+ *
+ * @return whether this view has a nested scrolling parent
+ */
+ public boolean hasNestedScrollingParent() {
+ return mNestedScrollingParent != null;
+ }
+
+ /**
+ * Dispatch one step of a nested scroll in progress.
+ *
+ * <p>Implementations of views that support nested scrolling should call this to report
+ * info about a scroll in progress to the current nested scrolling parent. If a nested scroll
+ * is not currently in progress or nested scrolling is not
+ * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p>
+ *
+ * <p>Compatible View implementations should also call
+ * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before
+ * consuming a component of the scroll event themselves.</p>
+ *
+ * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step
+ * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step
+ * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view
+ * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view
+ * @param offsetInWindow Optional. If not null, on return this will contain the offset
+ * in local view coordinates of this view from before this operation
+ * to after it completes. View implementations may use this to adjust
+ * expected input coordinate tracking.
+ * @return true if the event was dispatched, false if it could not be dispatched.
+ * @see #dispatchNestedPreScroll(int, int, int[], int[])
+ */
+ public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
+ if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
+ int startX = 0;
+ int startY = 0;
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ startX = offsetInWindow[0];
+ startY = offsetInWindow[1];
+ }
+
+ mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed,
+ dxUnconsumed, dyUnconsumed);
+
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ offsetInWindow[0] -= startX;
+ offsetInWindow[1] -= startY;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Dispatch one step of a nested scroll in progress before this view consumes any portion of it.
+ *
+ * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch.
+ * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested
+ * scrolling operation to consume some or all of the scroll operation before the child view
+ * consumes it.</p>
+ *
+ * @param dx Horizontal scroll distance in pixels
+ * @param dy Vertical scroll distance in pixels
+ * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx
+ * and consumed[1] the consumed dy.
+ * @param offsetInWindow Optional. If not null, on return this will contain the offset
+ * in local view coordinates of this view from before this operation
+ * to after it completes. View implementations may use this to adjust
+ * expected input coordinate tracking.
+ * @return true if the parent consumed some or all of the scroll delta
+ * @see #dispatchNestedScroll(int, int, int, int, int[])
+ */
+ public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
+ if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
+ int startX = 0;
+ int startY = 0;
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ startX = offsetInWindow[0];
+ startY = offsetInWindow[1];
+ }
+
+ if (consumed == null) {
+ if (mTempNestedScrollConsumed == null) {
+ mTempNestedScrollConsumed = new int[2];
+ }
+ consumed = mTempNestedScrollConsumed;
+ }
+ consumed[0] = 0;
+ consumed[1] = 0;
+ mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed);
+
+ if (offsetInWindow != null) {
+ getLocationInWindow(offsetInWindow);
+ offsetInWindow[0] -= startX;
+ offsetInWindow[1] -= startY;
+ }
+ return consumed[0] != 0 || consumed[1] != 0;
+ }
+ return false;
+ }
+
+ /**
+ * Dispatch a fling to a nested scrolling parent.
+ *
+ * <p>If a nested scrolling child view would normally fling but it is at the edge of its
+ * own content it should use this method to delegate the fling to its nested scrolling parent.
+ * The view implementation can use a {@link VelocityTracker} to obtain the velocity values
+ * to pass.</p>
+ *
+ * @param velocityX Horizontal fling velocity in pixels per second
+ * @param velocityY Vertical fling velocity in pixels per second
+ * @return true if the nested scrolling parent consumed the fling
+ */
+ public boolean dispatchNestedFling(float velocityX, float velocityY) {
+ if (isNestedScrollingEnabled() && mNestedScrollingParent != null) {
+ return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY);
+ }
+ return false;
+ }
+
+ /**
* Gets a scale factor that determines the distance the view should scroll
* vertically in response to {@link MotionEvent#ACTION_SCROLL}.
* @return The vertical scroll scale factor.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index a64bdc7..8865ab4 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -460,6 +460,13 @@
@ViewDebug.ExportedProperty(category = "layout")
private int mChildCountWithTransientState = 0;
+ /**
+ * Currently registered axes for nested scrolling. Flag set consisting of
+ * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
+ * for null.
+ */
+ private int mNestedScrollAxes;
+
public ViewGroup(Context context) {
this(context, null);
}
@@ -2011,6 +2018,7 @@
clearTouchTargets();
resetCancelNextUpFlag(this);
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
+ mNestedScrollAxes = SCROLL_AXIS_NONE;
}
/**
@@ -2334,6 +2342,7 @@
if (disallowIntercept) {
mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
+ stopNestedScroll();
} else {
mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
}
@@ -2962,14 +2971,24 @@
}
}
- int saveCount = 0;
+ int clipSaveCount = 0;
final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
+ boolean hasClipBounds = mClipBounds != null && !sIgnoreClipBoundsForChildren;
+ boolean clippingNeeded = clipToPadding || hasClipBounds;
+
+ if (clippingNeeded) {
+ clipSaveCount = canvas.save();
+ }
+
if (clipToPadding) {
- saveCount = canvas.save();
canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
mScrollX + mRight - mLeft - mPaddingRight,
mScrollY + mBottom - mTop - mPaddingBottom);
+ }
+ if (hasClipBounds) {
+ canvas.clipRect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
+ mClipBounds.bottom);
}
// We will draw our child's animation, let's reset the flag
@@ -3010,8 +3029,8 @@
onDebugDraw(canvas);
}
- if (clipToPadding) {
- canvas.restoreToCount(saveCount);
+ if (clippingNeeded) {
+ canvas.restoreToCount(clipSaveCount);
}
// mGroupFlags might have been updated by drawChild()
@@ -5846,6 +5865,74 @@
return true;
}
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int axes) {
+ mNestedScrollAxes = axes;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * <p>The default implementation of onStopNestedScroll calls
+ * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
+ */
+ @Override
+ public void onStopNestedScroll(View child) {
+ // Stop any recursive nested scrolling.
+ stopNestedScroll();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed) {
+ // Do nothing
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+ // Do nothing
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY) {
+ return false;
+ }
+
+ /**
+ * Return the current axes of nested scrolling for this ViewGroup.
+ *
+ * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
+ * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
+ *
+ * @return Flags indicating the current axes of nested scrolling
+ * @see #SCROLL_AXIS_HORIZONTAL
+ * @see #SCROLL_AXIS_VERTICAL
+ * @see #SCROLL_AXIS_NONE
+ */
+ public int getNestedScrollAxes() {
+ return mNestedScrollAxes;
+ }
+
/** @hide */
protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 01376934..3cd6449 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -407,4 +407,119 @@
* {@link View#TEXT_ALIGNMENT_VIEW_END}
*/
public int getTextAlignment();
+
+ /**
+ * React to a descendant view initiating a nestable scroll operation, claiming the
+ * nested scroll operation if appropriate.
+ *
+ * <p>This method will be called in response to a descendant view invoking
+ * {@link View#startNestedScroll(int)}. Each parent up the view hierarchy will be
+ * given an opportunity to respond and claim the nested scrolling operation by returning
+ * <code>true</code>.</p>
+ *
+ * <p>This method may be overridden by ViewParent implementations to indicate when the view
+ * is willing to support a nested scrolling operation that is about to begin. If it returns
+ * true, this ViewParent will become the target view's nested scrolling parent for the duration
+ * of the scroll operation in progress. When the nested scroll is finished this ViewParent
+ * will receive a call to {@link #onStopNestedScroll(View)}.
+ * </p>
+ *
+ * @param child Direct child of this ViewParent containing target
+ * @param target View that initiated the nested scroll
+ * @param nestedScrollAxes Flags consisting of {@link View#SCROLL_AXIS_HORIZONTAL},
+ * {@link View#SCROLL_AXIS_VERTICAL} or both
+ * @return true if this ViewParent accepts the nested scroll operation
+ */
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);
+
+ /**
+ * React to the successful claiming of a nested scroll operation.
+ *
+ * <p>This method will be called after
+ * {@link #onStartNestedScroll(View, View, int) onStartNestedScroll} returns true. It offers
+ * an opportunity for the view and its superclasses to perform initial configuration
+ * for the nested scroll. Implementations of this method should always call their superclass's
+ * implementation of this method if one is present.</p>
+ *
+ * @param child Direct child of this ViewParent containing target
+ * @param target View that initiated the nested scroll
+ * @param nestedScrollAxes Flags consisting of {@link View#SCROLL_AXIS_HORIZONTAL},
+ * {@link View#SCROLL_AXIS_VERTICAL} or both
+ * @see #onStartNestedScroll(View, View, int)
+ * @see #onStopNestedScroll(View)
+ */
+ public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);
+
+ /**
+ * React to a nested scroll operation ending.
+ *
+ * <p>Perform cleanup after a nested scrolling operation.
+ * This method will be called when a nested scroll stops, for example when a nested touch
+ * scroll ends with a {@link MotionEvent#ACTION_UP} or {@link MotionEvent#ACTION_CANCEL} event.
+ * Implementations of this method should always call their superclass's implementation of this
+ * method if one is present.</p>
+ *
+ * @param target View that initiated the nested scroll
+ */
+ public void onStopNestedScroll(View target);
+
+ /**
+ * React to a nested scroll in progress.
+ *
+ * <p>This method will be called when the ViewParent's current nested scrolling child view
+ * dispatches a nested scroll event. To receive calls to this method the ViewParent must have
+ * previously returned <code>true</code> for a call to
+ * {@link #onStartNestedScroll(View, View, int)}.</p>
+ *
+ * <p>Both the consumed and unconsumed portions of the scroll distance are reported to the
+ * ViewParent. An implementation may choose to use the consumed portion to match or chase scroll
+ * position of multiple child elements, for example. The unconsumed portion may be used to
+ * allow continuous dragging of multiple scrolling or draggable elements, such as scrolling
+ * a list within a vertical drawer where the drawer begins dragging once the edge of inner
+ * scrolling content is reached.</p>
+ *
+ * @param target The descendent view controlling the nested scroll
+ * @param dxConsumed Horizontal scroll distance in pixels already consumed by target
+ * @param dyConsumed Vertical scroll distance in pixels already consumed by target
+ * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by target
+ * @param dyUnconsumed Vertical scroll distance in pixels not consumed by target
+ */
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed);
+
+ /**
+ * React to a nested scroll in progress before the target view consumes a portion of the scroll.
+ *
+ * <p>When working with nested scrolling often the parent view may want an opportunity
+ * to consume the scroll before the nested scrolling child does. An example of this is a
+ * drawer that contains a scrollable list. The user will want to be able to scroll the list
+ * fully into view before the list itself begins scrolling.</p>
+ *
+ * <p><code>onNestedPreScroll</code> is called when a nested scrolling child invokes
+ * {@link View#dispatchNestedPreScroll(int, int, int[], int[])}. The implementation should
+ * report how any pixels of the scroll reported by dx, dy were consumed in the
+ * <code>consumed</code> array. Index 0 corresponds to dx and index 1 corresponds to dy.
+ * This parameter will never be null. Initial values for consumed[0] and consumed[1]
+ * will always be 0.</p>
+ *
+ * @param target View that initiated the nested scroll
+ * @param dx Horizontal scroll distance in pixels
+ * @param dy Vertical scroll distance in pixels
+ * @param consumed Output. The horizontal and vertical scroll distance consumed by this parent
+ */
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);
+
+ /**
+ * Request a fling from a nested scroll.
+ *
+ * <p>If a nested scrolling child view would normally fling but it is at the edge of
+ * its own content, it can delegate the fling to its nested scrolling parent instead.
+ * This method allows the parent to optionally consume the fling.</p>
+ *
+ * @param target View that initiated the nested scroll
+ * @param velocityX Horizontal velocity in pixels per second.
+ * @param velocityY Vertical velocity in pixels per second
+ * @return true if this parent consumed the fling
+ */
+ public boolean onNestedFling(View target, float velocityX, float velocityY);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index eec4354..246905d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1173,7 +1173,15 @@
void dispatchApplyInsets(View host) {
mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
- host.dispatchApplyWindowInsets(new WindowInsets(mFitSystemWindowsInsets));
+ boolean isRound = false;
+ if ((mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0
+ && mDisplay.getDisplayId() == 0) {
+ // we're fullscreen and not hosted in an ActivityView
+ isRound = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_windowIsRound);
+ }
+ host.dispatchApplyWindowInsets(new WindowInsets(
+ mFitSystemWindowsInsets, isRound));
}
private void performTraversals() {
@@ -1506,43 +1514,46 @@
mResizeBuffer.prepare(mWidth, mHeight, false);
RenderNode layerRenderNode = mResizeBuffer.startRecording();
HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
- final int restoreCount = layerCanvas.save();
+ try {
+ final int restoreCount = layerCanvas.save();
- int yoff;
- final boolean scrolling = mScroller != null
- && mScroller.computeScrollOffset();
- if (scrolling) {
- yoff = mScroller.getCurrY();
- mScroller.abortAnimation();
- } else {
- yoff = mScrollY;
+ int yoff;
+ final boolean scrolling = mScroller != null
+ && mScroller.computeScrollOffset();
+ if (scrolling) {
+ yoff = mScroller.getCurrY();
+ mScroller.abortAnimation();
+ } else {
+ yoff = mScrollY;
+ }
+
+ layerCanvas.translate(0, -yoff);
+ if (mTranslator != null) {
+ mTranslator.translateCanvas(layerCanvas);
+ }
+
+ RenderNode renderNode = mView.mRenderNode;
+ if (renderNode != null && renderNode.isValid()) {
+ layerCanvas.drawDisplayList(renderNode, null,
+ RenderNode.FLAG_CLIP_CHILDREN);
+ } else {
+ mView.draw(layerCanvas);
+ }
+
+ drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
+
+ mResizeBufferStartTime = SystemClock.uptimeMillis();
+ mResizeBufferDuration = mView.getResources().getInteger(
+ com.android.internal.R.integer.config_mediumAnimTime);
+
+ layerCanvas.restoreToCount(restoreCount);
+ layerRenderNode.end(layerCanvas);
+ layerRenderNode.setCaching(true);
+ layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
+ mTempRect.set(0, 0, mWidth, mHeight);
+ } finally {
+ mResizeBuffer.endRecording(mTempRect);
}
-
- layerCanvas.translate(0, -yoff);
- if (mTranslator != null) {
- mTranslator.translateCanvas(layerCanvas);
- }
-
- RenderNode renderNode = mView.mRenderNode;
- if (renderNode != null && renderNode.isValid()) {
- layerCanvas.drawDisplayList(renderNode, null,
- RenderNode.FLAG_CLIP_CHILDREN);
- } else {
- mView.draw(layerCanvas);
- }
-
- drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
-
- mResizeBufferStartTime = SystemClock.uptimeMillis();
- mResizeBufferDuration = mView.getResources().getInteger(
- com.android.internal.R.integer.config_mediumAnimTime);
-
- layerCanvas.restoreToCount(restoreCount);
- layerRenderNode.end(layerCanvas);
- layerRenderNode.setCaching(true);
- layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
- mTempRect.set(0, 0, mWidth, mHeight);
- mResizeBuffer.endRecording(mTempRect);
mAttachInfo.mHardwareRenderer.flushLayerUpdates();
}
mAttachInfo.mContentInsets.set(mPendingContentInsets);
@@ -2941,7 +2952,7 @@
}
}
}
-
+
/**
* Return true if child is an ancestor of parent, (or equal to the parent).
*/
@@ -3714,7 +3725,8 @@
if (result == InputMethodManager.DISPATCH_HANDLED) {
return FINISH_HANDLED;
} else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
- return FINISH_NOT_HANDLED;
+ // The IME could not handle it, so skip along to the next InputStage
+ return FORWARD;
} else {
return DEFER; // callback will be invoked later
}
@@ -5812,6 +5824,13 @@
}
}
+ public void dispatchUnhandledInputEvent(InputEvent event) {
+ if (event instanceof KeyEvent) {
+ dispatchUnhandledKey((KeyEvent) event);
+ return;
+ }
+ }
+
public void dispatchAppVisibility(boolean visible) {
Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
msg.arg1 = visible ? 1 : 0;
@@ -6071,6 +6090,33 @@
// Do nothing.
}
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return false;
+ }
+
+ @Override
+ public void onStopNestedScroll(View target) {
+ }
+
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
+ }
+
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed) {
+ }
+
+ @Override
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+ }
+
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY) {
+ return false;
+ }
+
void changeCanvasOpacity(boolean opaque) {
// TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index f8cc793..2160efe 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -51,6 +51,11 @@
}
/** @hide */
+ public WindowInsets(Rect systemWindowInsets, boolean isRound) {
+ this(systemWindowInsets, EMPTY_RECT, isRound);
+ }
+
+ /** @hide */
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
mSystemWindowInsets = systemWindowInsets;
mWindowDecorInsets = windowDecorInsets;
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
new file mode 100644
index 0000000..8951786
--- /dev/null
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.webkit;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * ClientCertRequest: The user receives an instance of this class as
+ * a parameter of {@link WebViewClient#onReceivedClientCertRequest}.
+ * The request includes the parameters to choose the client certificate,
+ * such as the host name and the port number requesting the cert, the acceptable
+ * key types and the principals.
+ *
+ * The user should call one of the interface methods to indicate how to deal
+ * with the client certificate request. All methods should be called on
+ * UI thread.
+ *
+ * WebView caches the {@link #proceed} and {@link #cancel} responses in memory
+ * and uses them to handle future client certificate requests for the same
+ * host/port pair. The user can clear the cached data using
+ * {@link WebView#clearClientCertPreferences}.
+ *
+ * TODO(sgurun) unhide
+ * @hide
+ */
+public interface ClientCertRequest {
+ /**
+ * Returns the acceptable types of asymmetric keys (can be null).
+ */
+ public String[] getKeyTypes();
+
+ /**
+ * Returns the acceptable certificate issuers for the certificate
+ * matching the private key (can be null).
+ */
+ public Principal[] getPrincipals();
+
+ /**
+ * Returns the host name of the server requesting the certificate.
+ */
+ public String getHost();
+
+ /**
+ * Returns the port number of the server requesting the certificate.
+ */
+ public int getPort();
+
+ /**
+ * Proceed with the specified private key and client certificate chain.
+ * Remember the user's positive choice and use it for future requests.
+ */
+ public void proceed(PrivateKey privateKey, X509Certificate[] chain);
+
+ /**
+ * Ignore the request for now. Do not remember user's choice.
+ */
+ public void ignore();
+
+ /**
+ * Cancel this request. Remember the user's choice and use it for
+ * future requests.
+ */
+ public void cancel();
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 62fbbc4..c914e52 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -485,7 +485,7 @@
* @param privateBrowsing whether this WebView will be initialized in
* private mode
*
- * @deprecated Private browsing is no longer supported directly via
+ * @deprecated Private browsing is no longer supported directly via
* WebView and will be removed in a future release. Prefer using
* {@link WebSettings}, {@link WebViewDatabase}, {@link CookieManager}
* and {@link WebStorage} for fine-grained control of privacy data.
@@ -1136,9 +1136,18 @@
}
/**
+ * @deprecated Use {@link #createPrintDocumentAdapter(String)} which requires user
+ * to provide a print document name.
+ */
+ @Deprecated
+ public PrintDocumentAdapter createPrintDocumentAdapter() {
+ checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "createPrintDocumentAdapter");
+ return mProvider.createPrintDocumentAdapter("default");
+ }
+
+ /**
* Creates a PrintDocumentAdapter that provides the content of this Webview for printing.
- * Only supported for API levels
- * {@link android.os.Build.VERSION_CODES#KITKAT} and above.
*
* The adapter works by converting the Webview contents to a PDF stream. The Webview cannot
* be drawn during the conversion process - any such draws are undefined. It is recommended
@@ -1146,11 +1155,14 @@
* temporarily hide a visible WebView by using a custom PrintDocumentAdapter instance
* wrapped around the object returned and observing the onStart and onFinish methods. See
* {@link android.print.PrintDocumentAdapter} for more information.
+ *
+ * @param documentName The user-facing name of the printed document. See
+ * {@link android.print.PrintDocumentInfo}
*/
- public PrintDocumentAdapter createPrintDocumentAdapter() {
+ public PrintDocumentAdapter createPrintDocumentAdapter(String documentName) {
checkThread();
if (DebugFlags.TRACE_API) Log.d(LOGTAG, "createPrintDocumentAdapter");
- return mProvider.createPrintDocumentAdapter();
+ return mProvider.createPrintDocumentAdapter(documentName);
}
/**
@@ -1464,6 +1476,24 @@
}
/**
+ * Clears the client certificate preferences table stored in response
+ * to proceeding/cancelling client cert requests. Note that webview
+ * automatically clears these preferences when it receives a
+ * {@link KeyChain.ACTION_STORAGE_CHANGED}
+ *
+ * @param resultCallback A callback to be invoked when client certs are cleared.
+ * The embedder can pass null if not interested in the callback.
+ *
+ * TODO(sgurun) unhide
+ * @hide
+ */
+ public void clearClientCertPreferences(ValueCallback<Void> resultCallback) {
+ checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearClientCertPreferences");
+ mProvider.clearClientCertPreferences(resultCallback);
+ }
+
+ /**
* Gets the WebBackForwardList for this WebView. This contains the
* back/forward list for use in querying each item in the history stack.
* This is a copy of the private WebBackForwardList so it contains only a
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index e8974c6..688c251 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -22,6 +22,8 @@
import android.view.KeyEvent;
import android.view.ViewRootImpl;
+import java.security.Principal;
+
public class WebViewClient {
/**
@@ -205,6 +207,30 @@
}
/**
+ * Notify the host application to handle a SSL client certificate
+ * request. The host application is responsible for showing the UI
+ * if desired and providing the keys. There are three ways to
+ * respond: proceed(), cancel() or ignore(). Webview remembers the
+ * response if proceed() or cancel() is called and does not
+ * call onReceivedClientCertRequest() again for the same host and port
+ * pair. Webview does not remember the response if ignore() is called.
+ *
+ * This method is called on the UI thread. During the callback, the
+ * connection is suspended.
+ *
+ * The default behavior is to cancel, returning no client certificate.
+ *
+ * @param view The WebView that is initiating the callback
+ * @param request An instance of a {@link ClientCertRequest}
+ *
+ * TODO(sgurun) unhide
+ * @hide
+ */
+ public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
+ request.cancel();
+ }
+
+ /**
* Notifies the host application that the WebView received an HTTP
* authentication request. The host application can use the supplied
* {@link HttpAuthHandler} to set the WebView's response to the request.
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 9488cdd..efa5497 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -148,7 +148,7 @@
public Picture capturePicture();
- public PrintDocumentAdapter createPrintDocumentAdapter();
+ public PrintDocumentAdapter createPrintDocumentAdapter(String documentName);
public float getScale();
@@ -198,6 +198,8 @@
public void clearSslPreferences();
+ public void clearClientCertPreferences(ValueCallback<Void> resultCallback);
+
public WebBackForwardList copyBackForwardList();
public void setFindListener(WebView.FindListener listener);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 301317e..becda67 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -543,7 +543,7 @@
/**
* The last CheckForTap runnable we posted, if any
*/
- private Runnable mPendingCheckForTap;
+ private CheckForTap mPendingCheckForTap;
/**
* The last CheckForKeyLongPress runnable we posted, if any
@@ -2126,7 +2126,9 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
+
mInLayout = true;
+
final int childCount = getChildCount();
if (changed) {
for (int i = 0; i < childCount; i++) {
@@ -3185,7 +3187,10 @@
return INVALID_ROW_ID;
}
- final class CheckForTap implements Runnable {
+ private final class CheckForTap implements Runnable {
+ float x;
+ float y;
+
@Override
public void run() {
if (mTouchMode == TOUCH_MODE_DOWN) {
@@ -3205,7 +3210,7 @@
final boolean longClickable = isLongClickable();
if (mSelector != null) {
- Drawable d = mSelector.getCurrent();
+ final Drawable d = mSelector.getCurrent();
if (d != null && d instanceof TransitionDrawable) {
if (longClickable) {
((TransitionDrawable) d).startTransition(longPressTimeout);
@@ -3213,6 +3218,9 @@
((TransitionDrawable) d).resetTransition();
}
}
+ if (d.supportsHotspots()) {
+ d.setHotspot(R.attr.state_pressed, x, y);
+ }
}
if (longClickable) {
@@ -3596,6 +3604,8 @@
mPendingCheckForTap = new CheckForTap();
}
+ mPendingCheckForTap.x = ev.getX();
+ mPendingCheckForTap.y = ev.getY();
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
}
}
@@ -3705,6 +3715,9 @@
if (d != null && d instanceof TransitionDrawable) {
((TransitionDrawable) d).resetTransition();
}
+ if (mSelector.supportsHotspots()) {
+ mSelector.setHotspot(R.attr.state_pressed, x, ev.getY());
+ }
}
if (mTouchModeReset != null) {
removeCallbacks(mTouchModeReset);
@@ -3716,6 +3729,9 @@
mTouchMode = TOUCH_MODE_REST;
child.setPressed(false);
setPressed(false);
+ if (mSelector != null && mSelector.supportsHotspots()) {
+ mSelector.removeHotspot(R.attr.state_pressed);
+ }
if (!mDataChanged && !mIsDetaching && isAttachedToWindow()) {
performClick.run();
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 438a9da..225cd6d 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -29,6 +29,8 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
public abstract class AbsSeekBar extends ProgressBar {
private Drawable mThumb;
private int mThumbOffset;
@@ -289,28 +291,39 @@
*/
private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
int available = w - mPaddingLeft - mPaddingRight;
- int thumbWidth = thumb.getIntrinsicWidth();
- int thumbHeight = thumb.getIntrinsicHeight();
+ final int thumbWidth = thumb.getIntrinsicWidth();
+ final int thumbHeight = thumb.getIntrinsicHeight();
available -= thumbWidth;
// The extra space for the thumb to move on the track
available += mThumbOffset * 2;
- int thumbPos = (int) (scale * available + 0.5f);
+ final int thumbPos = (int) (scale * available + 0.5f);
- int topBound, bottomBound;
+ final int top, bottom;
if (gap == Integer.MIN_VALUE) {
- Rect oldBounds = thumb.getBounds();
- topBound = oldBounds.top;
- bottomBound = oldBounds.bottom;
+ final Rect oldBounds = thumb.getBounds();
+ top = oldBounds.top;
+ bottom = oldBounds.bottom;
} else {
- topBound = gap;
- bottomBound = gap + thumbHeight;
+ top = gap;
+ bottom = gap + thumbHeight;
}
-
- // Canvas will be translated, so 0,0 is where we start drawing
+
final int left = (isLayoutRtl() && mMirrorForRtl) ? available - thumbPos : thumbPos;
- thumb.setBounds(left, topBound, left + thumbWidth, bottomBound);
+ final int right = left + thumbWidth;
+
+ final Drawable background = getBackground();
+ if (background != null && background.supportsHotspots()) {
+ final Rect bounds = mThumb.getBounds();
+ final int offsetX = mPaddingLeft - mThumbOffset;
+ final int offsetY = mPaddingTop;
+ background.setHotspotBounds(left + offsetX, bounds.top + offsetY,
+ right + offsetX, bounds.bottom + offsetY);
+ }
+
+ // Canvas will be translated, so 0,0 is where we start drawing
+ thumb.setBounds(left, top, right, bottom);
}
/**
@@ -328,6 +341,7 @@
@Override
protected synchronized void onDraw(Canvas canvas) {
super.onDraw(canvas);
+
if (mThumb != null) {
canvas.save();
// Translate the padding. For the x, we need to allow the thumb to
@@ -424,10 +438,24 @@
return true;
}
+ private void setHotspot(int id, float x, float y) {
+ final Drawable bg = getBackground();
+ if (bg != null && bg.supportsHotspots()) {
+ bg.setHotspot(id, x, y);
+ }
+ }
+
+ private void clearHotspot(int id) {
+ final Drawable bg = getBackground();
+ if (bg != null && bg.supportsHotspots()) {
+ bg.removeHotspot(id);
+ }
+ }
+
private void trackTouchEvent(MotionEvent event) {
final int width = getWidth();
final int available = width - mPaddingLeft - mPaddingRight;
- int x = (int)event.getX();
+ final int x = (int) event.getX();
float scale;
float progress = 0;
if (isLayoutRtl() && mMirrorForRtl) {
@@ -451,7 +479,8 @@
}
final int max = getMax();
progress += scale * max;
-
+
+ setHotspot(R.attr.state_pressed, x, (int) event.getY());
setProgress((int) progress, true);
}
@@ -477,6 +506,7 @@
* canceled.
*/
void onStopTrackingTouch() {
+ clearHotspot(R.attr.state_pressed);
mIsDragging = false;
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 4298545..9e17cca 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -261,15 +261,13 @@
@Override
protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int drawableHeight = buttonDrawable.getIntrinsicHeight();
final int drawableWidth = buttonDrawable.getIntrinsicWidth();
- int top = 0;
+ final int top;
switch (verticalGravity) {
case Gravity.BOTTOM:
top = getHeight() - drawableHeight;
@@ -277,12 +275,24 @@
case Gravity.CENTER_VERTICAL:
top = (getHeight() - drawableHeight) / 2;
break;
+ default:
+ top = 0;
}
- int bottom = top + drawableHeight;
- int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
- int right = isLayoutRtl() ? getWidth() : drawableWidth;
+ final int bottom = top + drawableHeight;
+ final int left = isLayoutRtl() ? getWidth() - drawableWidth : 0;
+ final int right = isLayoutRtl() ? getWidth() : drawableWidth;
buttonDrawable.setBounds(left, top, right, bottom);
+
+ final Drawable background = getBackground();
+ if (background != null && background.supportsHotspots()) {
+ background.setHotspotBounds(left, top, right, bottom);
+ }
+ }
+
+ super.onDraw(canvas);
+
+ if (buttonDrawable != null) {
buttonDrawable.draw(canvas);
}
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 082d728..7e8f6b4 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -138,6 +138,12 @@
private int mActivePointerId = INVALID_POINTER;
/**
+ * Used during scrolling to retrieve the new offset within the window.
+ */
+ private final int[] mScrollOffset = new int[2];
+ private final int[] mScrollConsumed = new int[2];
+
+ /**
* The StrictMode "critical time span" objects to catch animation
* stutters. Non-null when a time-sensitive animation is
* in-flight. Must call finish() on them when done animating.
@@ -505,7 +511,7 @@
final int y = (int) ev.getY(pointerIndex);
final int yDiff = Math.abs(y - mLastMotionY);
- if (yDiff > mTouchSlop) {
+ if (yDiff > mTouchSlop && (getNestedScrollAxes() & SCROLL_AXIS_VERTICAL) == 0) {
mIsBeingDragged = true;
mLastMotionY = y;
initVelocityTrackerIfNotExists();
@@ -547,6 +553,7 @@
if (mIsBeingDragged && mScrollStrictSpan == null) {
mScrollStrictSpan = StrictMode.enterCriticalSpan("ScrollView-scroll");
}
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
break;
}
@@ -559,6 +566,7 @@
if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
postInvalidateOnAnimation();
}
+ stopNestedScroll();
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
@@ -606,6 +614,7 @@
// Remember where the motion event started
mLastMotionY = (int) ev.getY();
mActivePointerId = ev.getPointerId(0);
+ startNestedScroll(SCROLL_AXIS_VERTICAL);
break;
}
case MotionEvent.ACTION_MOVE:
@@ -617,6 +626,9 @@
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
+ if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
+ deltaY -= mScrollConsumed[1] + mScrollOffset[1];
+ }
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
final ViewParent parent = getParent();
if (parent != null) {
@@ -633,22 +645,25 @@
// Scroll to follow the motion event
mLastMotionY = y;
- final int oldX = mScrollX;
final int oldY = mScrollY;
final int range = getScrollRange();
final int overscrollMode = getOverScrollMode();
- final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
+ boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
// Calling overScrollBy will call onOverScrolled, which
// calls onScrollChanged if applicable.
- if (overScrollBy(0, deltaY, 0, mScrollY,
- 0, range, 0, mOverscrollDistance, true)) {
+ if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true)
+ && !hasNestedScrollingParent()) {
// Break our velocity if we hit a scroll barrier.
mVelocityTracker.clear();
}
- if (canOverscroll) {
+ final int scrolledDeltaY = mScrollY - oldY;
+ final int unconsumedY = deltaY - scrolledDeltaY;
+ if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset)) {
+ mLastMotionY -= mScrollOffset[1];
+ } else if (canOverscroll) {
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
mEdgeGlowTop.onPull((float) deltaY / getHeight());
@@ -674,15 +689,11 @@
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
- if (getChildCount() > 0) {
- if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
- fling(-initialVelocity);
- } else {
- if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0,
- getScrollRange())) {
- postInvalidateOnAnimation();
- }
- }
+ if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
+ flingWithNestedDispatch(-initialVelocity);
+ } else if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0,
+ getScrollRange())) {
+ postInvalidateOnAnimation();
}
mActivePointerId = INVALID_POINTER;
@@ -1553,6 +1564,15 @@
}
}
+ private void flingWithNestedDispatch(int velocityY) {
+ if (mScrollY == 0 && velocityY < 0 ||
+ mScrollY == getScrollRange() && velocityY > 0) {
+ dispatchNestedFling(0, velocityY);
+ } else {
+ fling(velocityY);
+ }
+ }
+
private void endDrag() {
mIsBeingDragged = false;
@@ -1603,6 +1623,34 @@
}
@Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public void onStopNestedScroll(View target) {
+ super.onStopNestedScroll(target);
+ }
+
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+ int dxUnconsumed, int dyUnconsumed) {
+ scrollBy(0, dyUnconsumed);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean onNestedFling(View target, float velocityX, float velocityY) {
+ flingWithNestedDispatch((int) velocityY);
+ return true;
+ }
+
+ @Override
public void draw(Canvas canvas) {
super.draw(canvas);
if (mEdgeGlowTop != null) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 3d23e4d..08af4de 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -773,8 +773,6 @@
@Override
protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
final Rect tempRect = mTempRect;
final Drawable trackDrawable = mTrackDrawable;
final Drawable thumbDrawable = mThumbDrawable;
@@ -785,16 +783,12 @@
final int switchRight = mSwitchRight;
final int switchBottom = mSwitchBottom;
trackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
- trackDrawable.draw(canvas);
-
- final int saveCount = canvas.save();
-
trackDrawable.getPadding(tempRect);
+
final int switchInnerLeft = switchLeft + tempRect.left;
final int switchInnerTop = switchTop + tempRect.top;
final int switchInnerRight = switchRight - tempRect.right;
final int switchInnerBottom = switchBottom - tempRect.bottom;
- canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
// Relies on mTempRect, MUST be called first!
final int thumbPos = getThumbOffset();
@@ -803,6 +797,18 @@
int thumbLeft = switchInnerLeft - tempRect.left + thumbPos;
int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + tempRect.right;
thumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
+
+ final Drawable background = getBackground();
+ if (background != null && background.supportsHotspots()) {
+ background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
+ }
+
+ super.onDraw(canvas);
+
+ trackDrawable.draw(canvas);
+
+ final int saveCount = canvas.save();
+ canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
thumbDrawable.draw(canvas);
final int drawableState[] = getDrawableState();
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 32f700d..fc89b31 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -19,6 +19,7 @@
import com.android.internal.os.BatteryStatsImpl;
import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.SignalStrength;
interface IBatteryStats {
@@ -55,7 +56,7 @@
void noteScreenOff();
void noteInputEvent();
void noteUserActivity(int uid, int event);
- void noteDataConnectionActive(int type, boolean active, long timestampNs);
+ void noteMobileRadioPowerState(int powerState, long timestampNs);
void notePhoneOn();
void notePhoneOff();
void notePhoneSignalStrength(in SignalStrength signalStrength);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
new file mode 100644
index 0000000..e3c0728
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.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 com.android.internal.app;
+
+import android.content.Intent;
+
+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);
+}
diff --git a/core/java/com/android/internal/app/IVoiceInteractor.aidl b/core/java/com/android/internal/app/IVoiceInteractor.aidl
new file mode 100644
index 0000000..737906a
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractor.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.internal.app;
+
+import android.os.Bundle;
+
+import com.android.internal.app.IVoiceInteractorCallback;
+import com.android.internal.app.IVoiceInteractorRequest;
+
+/**
+ * IPC interface for an application to perform calls through a VoiceInteractor.
+ */
+interface IVoiceInteractor {
+ IVoiceInteractorRequest startConfirmation(String callingPackage,
+ IVoiceInteractorCallback callback, String prompt, in Bundle extras);
+ IVoiceInteractorRequest startCommand(String callingPackage,
+ IVoiceInteractorCallback callback, String command, in Bundle extras);
+ boolean[] supportsCommands(String callingPackage, in String[] commands);
+}
diff --git a/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl
new file mode 100644
index 0000000..f5392e9
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.os.Bundle;
+
+import com.android.internal.app.IVoiceInteractorRequest;
+
+/**
+ * IPC interface for an application to receive callbacks from the voice system.
+ */
+oneway interface IVoiceInteractorCallback {
+ void deliverConfirmationResult(IVoiceInteractorRequest request, boolean confirmed,
+ in Bundle result);
+ void deliverCommandResult(IVoiceInteractorRequest request, in Bundle result);
+ void deliverCancel(IVoiceInteractorRequest request);
+}
diff --git a/core/java/com/android/internal/app/IVoiceInteractorRequest.aidl b/core/java/com/android/internal/app/IVoiceInteractorRequest.aidl
new file mode 100644
index 0000000..ce2902d
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractorRequest.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.internal.app;
+
+/**
+ * IPC interface identifying a request from an application calling through an IVoiceInteractor.
+ */
+interface IVoiceInteractorRequest {
+ void cancel();
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 1dd1f5e..7ff949e 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -22,6 +22,8 @@
import static android.os.BatteryStats.NETWORK_WIFI_TX_DATA;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.net.ConnectivityManager;
@@ -60,11 +62,14 @@
private static final String TAG = BatteryStatsHelper.class.getSimpleName();
private static BatteryStats sStatsXfer;
+ private static Intent sBatteryBroadcastXfer;
final private Context mContext;
+ final private boolean mCollectBatteryBroadcast;
private IBatteryStats mBatteryInfo;
private BatteryStats mStats;
+ private Intent mBatteryBroadcast;
private PowerProfile mPowerProfile;
private final List<BatterySipper> mUsageList = new ArrayList<BatterySipper>();
@@ -85,6 +90,8 @@
long mBatteryUptime;
long mTypeBatteryRealtime;
long mTypeBatteryUptime;
+ long mBatteryTimeRemaining;
+ long mChargeTimeRemaining;
private long mStatsPeriod = 0;
private double mMaxPower = 1;
@@ -102,7 +109,12 @@
private long mAppWifiRunning;
public BatteryStatsHelper(Context context) {
+ this(context, true);
+ }
+
+ public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) {
mContext = context;
+ mCollectBatteryBroadcast = collectBatteryBroadcast;
}
/** Clears the current stats and forces recreating for future use. */
@@ -117,6 +129,13 @@
return mStats;
}
+ public Intent getBatteryBroadcast() {
+ if (mBatteryBroadcast == null && mCollectBatteryBroadcast) {
+ load();
+ }
+ return mBatteryBroadcast;
+ }
+
public PowerProfile getPowerProfile() {
return mPowerProfile;
}
@@ -129,6 +148,7 @@
public void create(Bundle icicle) {
if (icicle != null) {
mStats = sStatsXfer;
+ mBatteryBroadcast = sBatteryBroadcastXfer;
}
mBatteryInfo = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
@@ -137,6 +157,7 @@
public void storeState() {
sStatsXfer = mStats;
+ sBatteryBroadcastXfer = mBatteryBroadcast;
}
public static String makemAh(double power) {
@@ -190,6 +211,8 @@
mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeUs);
mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
+ mBatteryTimeRemaining = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
+ mChargeTimeRemaining = mStats.computeChargeTimeRemaining(rawRealtimeUs);
if (DEBUG) {
Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs/1000) + " uptime="
@@ -787,6 +810,10 @@
return mMaxDrainedPower;
}
+ public long getBatteryTimeRemaining() { return mBatteryTimeRemaining; }
+
+ public long getChargeTimeRemaining() { return mChargeTimeRemaining; }
+
private void load() {
if (mBatteryInfo == null) {
return;
@@ -803,5 +830,9 @@
} catch (RemoteException e) {
Log.e(TAG, "RemoteException:", e);
}
+ if (mCollectBatteryBroadcast) {
+ mBatteryBroadcast = mContext.registerReceiver(null,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ }
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4c11fa9..343c507 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -38,6 +38,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -87,7 +88,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 101 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 103 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -284,7 +285,7 @@
int mBluetoothState = -1;
final StopwatchTimer[] mBluetoothStateTimer = new StopwatchTimer[NUM_BLUETOOTH_STATES];
- boolean mMobileRadioActive;
+ int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
StopwatchTimer mMobileRadioActiveTimer;
StopwatchTimer mMobileRadioActivePerAppTimer;
LongSamplingCounter mMobileRadioActiveAdjustedTime;
@@ -306,7 +307,9 @@
*/
int mDischargeStartLevel;
int mDischargeUnplugLevel;
+ int mDischargePlugLevel;
int mDischargeCurrentLevel;
+ int mCurrentBatteryLevel;
int mLowDischargeAmountSinceCharge;
int mHighDischargeAmountSinceCharge;
int mDischargeScreenOnUnplugLevel;
@@ -2736,40 +2739,41 @@
}
}
- public void noteDataConnectionActive(int type, boolean active, long timestampNs) {
- if (ConnectivityManager.isNetworkTypeMobile(type)) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
- if (mMobileRadioActive != active) {
- long realElapsedRealtimeMs;
- if (active) {
+ public void noteMobileRadioPowerState(int powerState, long timestampNs) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ if (mMobileRadioPowerState != powerState) {
+ long realElapsedRealtimeMs;
+ final boolean active =
+ powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
+ || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+ if (active) {
+ realElapsedRealtimeMs = elapsedRealtime;
+ mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+ } else {
+ realElapsedRealtimeMs = timestampNs / (1000*1000);
+ long lastUpdateTimeMs = mMobileRadioActiveTimer.getLastUpdateTimeMs();
+ if (realElapsedRealtimeMs < lastUpdateTimeMs) {
+ Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
+ + " is before start time " + lastUpdateTimeMs);
realElapsedRealtimeMs = elapsedRealtime;
- mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
- } else {
- realElapsedRealtimeMs = timestampNs / (1000*1000);
- long lastUpdateTimeMs = mMobileRadioActiveTimer.getLastUpdateTimeMs();
- if (realElapsedRealtimeMs < lastUpdateTimeMs) {
- Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
- + " is before start time " + lastUpdateTimeMs);
- realElapsedRealtimeMs = elapsedRealtime;
- } else if (realElapsedRealtimeMs < elapsedRealtime) {
- mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtime
- - realElapsedRealtimeMs);
- }
- mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+ } else if (realElapsedRealtimeMs < elapsedRealtime) {
+ mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtime
+ - realElapsedRealtimeMs);
}
- if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
- + Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(elapsedRealtime, uptime);
- mMobileRadioActive = active;
- if (active) {
- mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
- mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
- } else {
- mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
- updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
- mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
- }
+ mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+ }
+ if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mMobileRadioPowerState = powerState;
+ if (active) {
+ mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
+ mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
+ } else {
+ mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
+ updateNetworkActivityLocked(NET_UPDATE_MOBILE, realElapsedRealtimeMs);
+ mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
}
}
}
@@ -5520,7 +5524,9 @@
initTimes(uptime, realtime);
mDischargeStartLevel = 0;
mDischargeUnplugLevel = 0;
+ mDischargePlugLevel = -1;
mDischargeCurrentLevel = 0;
+ mCurrentBatteryLevel = 0;
initDischarge();
clearHistoryLocked();
}
@@ -5580,13 +5586,13 @@
if (end) {
Slog.w(TAG, "New history ends before old history!");
} else if (!out.same(mHistoryReadTmp)) {
- long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
PrintWriter pw = new FastPrintWriter(new LogWriter(android.util.Log.WARN, TAG));
pw.println("Histories differ!");
pw.println("Old history:");
- (new HistoryPrinter()).printNextItem(pw, out, now, false, true);
+ (new HistoryPrinter()).printNextItem(pw, out, 0, false, true);
pw.println("New history:");
- (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now, false, true);
+ (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, 0, false,
+ true);
pw.flush();
}
}
@@ -5664,7 +5670,12 @@
return false;
}
+ final long lastRealtime = out.time;
+ final long lastWalltime = out.currentTime;
readHistoryDelta(mHistoryBuffer, out);
+ if (out.cmd != HistoryItem.CMD_CURRENT_TIME && lastWalltime != 0) {
+ out.currentTime = lastWalltime + (out.time - lastRealtime);
+ }
return true;
}
@@ -5721,7 +5732,8 @@
mDischargeStartLevel = mHistoryCur.batteryLevel;
pullPendingStateUpdatesLocked();
addHistoryRecordLocked(mSecRealtime, mSecUptime);
- mDischargeCurrentLevel = mDischargeUnplugLevel = mHistoryCur.batteryLevel;
+ mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel
+ = mCurrentBatteryLevel = mHistoryCur.batteryLevel;
mOnBatteryTimeBase.reset(uptime, realtime);
mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
@@ -5902,7 +5914,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(mSecRealtime, mSecUptime);
- mDischargeCurrentLevel = level;
+ mDischargeCurrentLevel = mDischargePlugLevel = level;
if (level < mDischargeUnplugLevel) {
mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
@@ -5966,6 +5978,10 @@
startRecordingHistory(elapsedRealtime, uptime, true);
}
}
+ mCurrentBatteryLevel = level;
+ if (mDischargePlugLevel < 0) {
+ mDischargePlugLevel = level;
+ }
if (onBattery != mOnBattery) {
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.batteryStatus = (byte)status;
@@ -6219,6 +6235,42 @@
return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which);
}
+ @Override
+ public long computeBatteryTimeRemaining(long curTime) {
+ if (!mOnBattery) {
+ return -1;
+ }
+ int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2;
+ if (discharge < 2) {
+ return -1;
+ }
+ long duration = computeBatteryRealtime(curTime, STATS_SINCE_CHARGED);
+ if (duration < 1000*1000) {
+ return -1;
+ }
+ long usPerLevel = duration/discharge;
+ return usPerLevel * mCurrentBatteryLevel;
+ }
+
+ @Override
+ public long computeChargeTimeRemaining(long curTime) {
+ if (true || mOnBattery) {
+ // Not yet working.
+ return -1;
+ }
+ int curLevel = mCurrentBatteryLevel;
+ int plugLevel = mDischargePlugLevel;
+ if (plugLevel < 0 || curLevel < (plugLevel+1)) {
+ return -1;
+ }
+ long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
+ if (duration < 1000*1000) {
+ return -1;
+ }
+ long usPerLevel = duration/(curLevel-plugLevel);
+ return usPerLevel * (100-curLevel);
+ }
+
long getBatteryUptimeLocked() {
return mOnBatteryTimeBase.getUptime(SystemClock.uptimeMillis() * 1000);
}
@@ -6717,7 +6769,9 @@
mOnBatteryTimeBase.readSummaryFromParcel(in);
mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
mDischargeUnplugLevel = in.readInt();
+ mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
+ mCurrentBatteryLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
@@ -6744,7 +6798,7 @@
mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
- mMobileRadioActive = false;
+ mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
@@ -6969,7 +7023,9 @@
mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
out.writeInt(mDischargeUnplugLevel);
+ out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
+ out.writeInt(mCurrentBatteryLevel);
out.writeInt(getLowDischargeAmountSinceCharge());
out.writeInt(getHighDischargeAmountSinceCharge());
out.writeInt(getDischargeAmountScreenOnSinceCharge());
@@ -7257,7 +7313,7 @@
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
- mMobileRadioActive = false;
+ mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mOnBatteryTimeBase, in);
mMobileRadioActivePerAppTimer = new StopwatchTimer(null, -401, null, mOnBatteryTimeBase,
in);
@@ -7279,7 +7335,9 @@
null, mOnBatteryTimeBase, in);
}
mDischargeUnplugLevel = in.readInt();
+ mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
+ mCurrentBatteryLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOn = in.readInt();
@@ -7397,7 +7455,9 @@
mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
}
out.writeInt(mDischargeUnplugLevel);
+ out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
+ out.writeInt(mCurrentBatteryLevel);
out.writeInt(mLowDischargeAmountSinceCharge);
out.writeInt(mHighDischargeAmountSinceCharge);
out.writeInt(mDischargeAmountScreenOn);
@@ -7494,6 +7554,7 @@
pr.println("*** Data connection type #" + i + ":");
mPhoneDataConnectionsTimer[i].logState(pr, " ");
}
+ pr.println("*** mMobileRadioPowerState=" + mMobileRadioPowerState);
pr.println("*** Mobile network active timer:");
mMobileRadioActiveTimer.logState(pr, " ");
pr.println("*** Mobile network active adjusted timer:");
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index d9e3ef6..40834ba 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -85,7 +85,27 @@
public void sendMessage(Message msg) {
mH.sendMessage(msg);
}
-
+
+ public SomeArgs sendMessageAndWait(Message msg) {
+ if (Looper.myLooper() == mH.getLooper()) {
+ throw new IllegalStateException("Can't wait on same thread as looper");
+ }
+ SomeArgs args = (SomeArgs)msg.obj;
+ args.mWaitState = SomeArgs.WAIT_WAITING;
+ mH.sendMessage(msg);
+ synchronized (args) {
+ while (args.mWaitState == SomeArgs.WAIT_WAITING) {
+ try {
+ args.wait();
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
+ }
+ args.mWaitState = SomeArgs.WAIT_NONE;
+ return args;
+ }
+
public Message obtainMessage(int what) {
return mH.obtainMessage(what);
}
@@ -136,6 +156,14 @@
return mH.obtainMessage(what, arg1, 0, args);
}
+ public Message obtainMessageIOOO(int what, int arg1, Object arg2, Object arg3, Object arg4) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = arg2;
+ args.arg2 = arg3;
+ args.arg3 = arg4;
+ return mH.obtainMessage(what, arg1, 0, args);
+ }
+
public Message obtainMessageOO(int what, Object arg1, Object arg2) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = arg1;
@@ -161,6 +189,17 @@
return mH.obtainMessage(what, 0, 0, args);
}
+ public Message obtainMessageOOOOO(int what, Object arg1, Object arg2,
+ Object arg3, Object arg4, Object arg5) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = arg1;
+ args.arg2 = arg2;
+ args.arg3 = arg3;
+ args.arg4 = arg4;
+ args.arg5 = arg5;
+ return mH.obtainMessage(what, 0, 0, args);
+ }
+
public Message obtainMessageIIII(int what, int arg1, int arg2,
int arg3, int arg4) {
SomeArgs args = SomeArgs.obtain();
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 5538dca..4a26b4b 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -55,6 +55,11 @@
private static final native void nativeFinishInit();
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
+ private static int Clog_e(String tag, String msg, Throwable tr) {
+ return Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
/**
* Use this to log a message when a thread exits due to an uncaught
* exception. The framework catches these for the main threads, so
@@ -68,7 +73,7 @@
mCrashing = true;
if (mApplicationObject == null) {
- Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
+ Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
} else {
StringBuilder message = new StringBuilder();
message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
@@ -77,7 +82,7 @@
message.append("Process: ").append(processName).append(", ");
}
message.append("PID: ").append(Process.myPid());
- Slog.e(TAG, message.toString(), e);
+ Clog_e(TAG, message.toString(), e);
}
// Bring up crash dialog, wait for it to be dismissed
@@ -85,9 +90,9 @@
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
} catch (Throwable t2) {
try {
- Slog.e(TAG, "Error reporting crash", t2);
+ Clog_e(TAG, "Error reporting crash", t2);
} catch (Throwable t3) {
- // Even Slog.e() fails! Oh well.
+ // Even Clog_e() fails! Oh well.
}
} finally {
// Try everything to make sure this process goes away.
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index 6fb72f1..7edf4cc 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -35,6 +35,11 @@
private boolean mInPool;
+ static final int WAIT_NONE = 0;
+ static final int WAIT_WAITING = 1;
+ static final int WAIT_FINISHED = 2;
+ int mWaitState = WAIT_NONE;
+
public Object arg1;
public Object arg2;
public Object arg3;
@@ -70,6 +75,9 @@
if (mInPool) {
throw new IllegalStateException("Already recycled.");
}
+ if (mWaitState != WAIT_NONE) {
+ return;
+ }
synchronized (sPoolLock) {
clear();
if (sPoolSize < MAX_POOL_SIZE) {
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index b776226..5d7d322 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -392,8 +392,8 @@
private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
final int ordering = getOrdering(categoryOrder);
- final MenuItemImpl item = new MenuItemImpl(this, group, id, categoryOrder,
- ordering, title, mDefaultShowAsAction);
+ final MenuItemImpl item = createNewMenuItem(group, id, categoryOrder, ordering, title,
+ mDefaultShowAsAction);
if (mCurrentMenuInfo != null) {
// Pass along the current menu info
@@ -405,7 +405,14 @@
return item;
}
-
+
+ // Layoutlib overrides this method to return its custom implementation of MenuItemImpl
+ private MenuItemImpl createNewMenuItem(int group, int id, int categoryOrder, int ordering,
+ CharSequence title, int defaultShowAsAction) {
+ return new MenuItemImpl(this, group, id, categoryOrder, ordering, title,
+ defaultShowAsAction);
+ }
+
public MenuItem add(CharSequence title) {
return addInternal(0, 0, 0, title);
}
diff --git a/core/java/com/android/server/SystemService.java b/core/java/com/android/server/SystemService.java
index e374563..bf36bb1 100644
--- a/core/java/com/android/server/SystemService.java
+++ b/core/java/com/android/server/SystemService.java
@@ -123,6 +123,38 @@
public void onBootPhase(int phase) {}
/**
+ * Called when a new user is starting, for system services to initialize any per-user
+ * state they maintain for running users.
+ * @param userHandle The identifier of the user.
+ */
+ public void onStartUser(int userHandle) {}
+
+ /**
+ * Called when switching to a different foreground user, for system services that have
+ * special behavior for whichever user is currently in the foreground. This is called
+ * before any application processes are aware of the new user.
+ * @param userHandle The identifier of the user.
+ */
+ public void onSwitchUser(int userHandle) {}
+
+ /**
+ * Called when an existing user is stopping, for system services to finalize any per-user
+ * state they maintain for running users. This is called prior to sending the SHUTDOWN
+ * broadcast to the user; it is a good place to stop making use of any resources of that
+ * user (such as binding to a service running in the user).
+ * @param userHandle The identifier of the user.
+ */
+ public void onStopUser(int userHandle) {}
+
+ /**
+ * Called when an existing user is stopping, for system services to finalize any per-user
+ * state they maintain for running users. This is called after all application process
+ * teardown of the user is complete.
+ * @param userHandle The identifier of the user.
+ */
+ public void onCleanupUser(int userHandle) {}
+
+ /**
* Publish the service so it is accessible to other services and apps.
*/
protected final void publishBinderService(String name, IBinder service) {
diff --git a/core/java/com/android/server/SystemServiceManager.java b/core/java/com/android/server/SystemServiceManager.java
index eb8df0e..87a50a9 100644
--- a/core/java/com/android/server/SystemServiceManager.java
+++ b/core/java/com/android/server/SystemServiceManager.java
@@ -131,6 +131,58 @@
}
}
+ public void startUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onStartUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting start of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void switchUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onSwitchUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting switch of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void stopUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onStopUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting stop of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void cleanupUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onCleanupUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
/** Sets the safe mode flag for services to query. */
public void setSafeMode(boolean safeMode) {
mSafeMode = safeMode;
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 5148266..2adbf3a 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -509,12 +509,11 @@
}
static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle,
- jobject jrect, jfloat rx, jfloat ry,
- jlong paintHandle) {
+ jfloat left, jfloat top, jfloat right, jfloat bottom, jfloat rx, jfloat ry,
+ jlong paintHandle) {
SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
- SkRect rect;
- GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
canvas->drawRoundRect(rect, rx, ry, *paint);
}
@@ -1176,7 +1175,7 @@
{"native_drawCircle","(JFFFJ)V", (void*) SkCanvasGlue::drawCircle},
{"native_drawArc","(JLandroid/graphics/RectF;FFZJ)V",
(void*) SkCanvasGlue::drawArc},
- {"native_drawRoundRect","(JLandroid/graphics/RectF;FFJ)V",
+ {"native_drawRoundRect","(JFFFFFFJ)V",
(void*) SkCanvasGlue::drawRoundRect},
{"native_drawPath","(JJJ)V", (void*) SkCanvasGlue::drawPath},
{"native_drawBitmap","(JJFFJIII)V",
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 1ad1a8a..420a17f 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -163,42 +163,35 @@
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
obj->close();
}
-
- static void addRect__RectFI(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect, jint dirHandle) {
- SkRect rect;
- SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
- GraphicsJNI::jrectf_to_rect(env, jrect, &rect);
- obj->addRect(rect, dir);
- }
-
- static void addRect__FFFFI(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
+
+ static void addRect(JNIEnv* env, jobject clazz, jlong objHandle,
+ jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
obj->addRect(left, top, right, bottom, dir);
}
-
- static void addOval(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jint dirHandle) {
+
+ static void addOval(JNIEnv* env, jobject clazz, jlong objHandle,
+ jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
- SkRect oval_;
- GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
- obj->addOval(oval_, dir);
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
+ obj->addOval(oval, dir);
}
-
+
static void addCircle(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y, jfloat radius, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
obj->addCircle(x, y, radius, dir);
}
-
+
static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle) {
SkRect oval_;
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
GraphicsJNI::jrectf_to_rect(env, oval, &oval_);
obj->addArc(oval_, startAngle, sweepAngle);
}
-
+
static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect,
jfloat rx, jfloat ry, jint dirHandle) {
SkRect rect;
@@ -496,9 +489,8 @@
{"native_rCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo},
{"native_arcTo","(JLandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo},
{"native_close","(J)V", (void*) SkPathGlue::close},
- {"native_addRect","(JLandroid/graphics/RectF;I)V", (void*) SkPathGlue::addRect__RectFI},
- {"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect__FFFFI},
- {"native_addOval","(JLandroid/graphics/RectF;I)V", (void*) SkPathGlue::addOval},
+ {"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect},
+ {"native_addOval","(JFFFFI)V", (void*) SkPathGlue::addOval},
{"native_addCircle","(JFFFI)V", (void*) SkPathGlue::addCircle},
{"native_addArc","(JLandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc},
{"native_addRoundRect","(JLandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY},
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 7a4728d..fcf8f83e 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -160,7 +160,6 @@
ASensorEvent buffer[16];
while ((n = q->read(buffer, 16)) > 0) {
for (int i=0 ; i<n ; i++) {
-
if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) {
// step-counter returns a uint64, but the java API only deals with floats
float value = float(buffer[i].u64.step_counter);
@@ -183,17 +182,17 @@
buffer[i].vector.status,
buffer[i].timestamp);
}
-
if (env->ExceptionCheck()) {
+ mSensorQueue->sendAck(buffer, n);
ALOGE("Exception dispatching input event.");
return 1;
}
}
+ mSensorQueue->sendAck(buffer, n);
}
if (n<0 && n != -EAGAIN) {
// FIXME: error receiving events, what to do in this case?
}
-
return 1;
}
};
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 475e926..662af89 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -23,6 +23,7 @@
#include "JNIHelp.h"
#include <fcntl.h>
+#include <inttypes.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -334,7 +335,7 @@
if (b == NULL) {
b = new JavaBBinder(env, obj);
mBinder = b;
- ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n",
+ ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
}
@@ -697,9 +698,9 @@
"Not allowed to write file descriptors here");
break;
default:
- ALOGE("Unknown binder error code. 0x%x", err);
+ ALOGE("Unknown binder error code. 0x%" PRIx32, err);
String8 msg;
- msg.appendFormat("Unknown binder error code. 0x%x", err);
+ msg.appendFormat("Unknown binder error code. 0x%" PRIx32, err);
// RemoteException is a checked exception, only throw from certain methods.
jniThrowException(env, canThrowRemoteException
? "android/os/RemoteException" : "java/lang/RuntimeException", msg.string());
@@ -733,7 +734,7 @@
if (uid > 0 && uid < 999) {
// In Android currently there are no uids in this range.
char buf[128];
- sprintf(buf, "Restoring bad calling ident: 0x%Lx", token);
+ sprintf(buf, "Restoring bad calling ident: 0x%" PRIx64, token);
jniThrowException(env, "java/lang/IllegalStateException", buf);
return;
}
@@ -965,8 +966,8 @@
jint len = strlen(str);
int space_needed = 1 + sizeof(len) + len;
if (end - *pos < space_needed) {
- ALOGW("not enough space for string. remain=%d; needed=%d",
- (end - *pos), space_needed);
+ ALOGW("not enough space for string. remain=%" PRIdPTR "; needed=%d",
+ end - *pos, space_needed);
return false;
}
**pos = EVENT_TYPE_STRING;
@@ -981,8 +982,8 @@
static bool push_eventlog_int(char** pos, const char* end, jint val) {
int space_needed = 1 + sizeof(val);
if (end - *pos < space_needed) {
- ALOGW("not enough space for int. remain=%d; needed=%d",
- (end - *pos), space_needed);
+ ALOGW("not enough space for int. remain=%" PRIdPTR "; needed=%d",
+ end - *pos, space_needed);
return false;
}
**pos = EVENT_TYPE_INT;
@@ -1068,7 +1069,7 @@
return JNI_FALSE;
}
- ALOGV("Java code calling transact on %p in Java object %p with code %d\n",
+ ALOGV("Java code calling transact on %p in Java object %p with code %" PRId32 "\n",
target, obj, code);
#if ENABLE_BINDER_SAMPLE
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index a4efed7..01f4d3a 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -30,15 +30,16 @@
#include "android_util_Binder.h"
#include "JNIHelp.h"
-#include <sys/errno.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <grp.h>
+#include <inttypes.h>
#include <pwd.h>
#include <signal.h>
+#include <sys/errno.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#define POLICY_DEBUG 0
@@ -159,7 +160,7 @@
void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int tid, jint grp)
{
- ALOGV("%s tid=%d grp=%d", __func__, tid, grp);
+ ALOGV("%s tid=%d grp=%" PRId32, __func__, tid, grp);
SchedPolicy sp = (SchedPolicy) grp;
int res = set_sched_policy(tid, sp);
if (res != NO_ERROR) {
@@ -169,7 +170,7 @@
void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
{
- ALOGV("%s pid=%d grp=%d", __func__, pid, grp);
+ ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
DIR *d;
FILE *fp;
char proc_path[255];
@@ -322,7 +323,7 @@
}
}
- //ALOGI("Setting priority of %d: %d, getpriority returns %d\n",
+ //ALOGI("Setting priority of %" PRId32 ": %" PRId32 ", getpriority returns %d\n",
// pid, pri, getpriority(PRIO_PROCESS, pid));
}
@@ -340,7 +341,7 @@
if (errno != 0) {
signalExceptionForPriorityError(env, errno);
}
- //ALOGI("Returning priority of %d: %d\n", pid, pri);
+ //ALOGI("Returning priority of %" PRId32 ": %" PRId32 "\n", pid, pri);
return pri;
}
@@ -362,7 +363,7 @@
int fd = open(text, O_WRONLY);
if (fd >= 0) {
- sprintf(text, "%d", pid);
+ sprintf(text, "%" PRId32, pid);
write(fd, text, strlen(text));
close(fd);
}
@@ -403,7 +404,7 @@
static int pid_compare(const void* v1, const void* v2)
{
- //ALOGI("Compare %d vs %d\n", *((const jint*)v1), *((const jint*)v2));
+ //ALOGI("Compare %" PRId32 " vs %" PRId32 "\n", *((const jint*)v1), *((const jint*)v2));
return *((const jint*)v1) - *((const jint*)v2);
}
@@ -517,7 +518,7 @@
return;
}
- //ALOGI("Clearing %d sizes", count);
+ //ALOGI("Clearing %" PRId32 " sizes", count);
for (i=0; i<count; i++) {
sizesArray[i] = 0;
}
@@ -556,7 +557,7 @@
}
char* end;
sizesArray[i] = strtoll(num, &end, 10);
- //ALOGI("Field %s = %d", field.string(), sizesArray[i]);
+ //ALOGI("Field %s = %" PRId64, field.string(), sizesArray[i]);
foundCount++;
break;
}
@@ -758,7 +759,7 @@
}
}
- //ALOGI("Field %d: %d-%d dest=%d mode=0x%x\n", i, start, end, di, mode);
+ //ALOGI("Field %" PRId32 ": %" PRId32 "-%" PRId32 " dest=%" PRId32 " mode=0x%" PRIx32 "\n", i, start, end, di, mode);
if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) {
char c = buffer[end];
@@ -857,7 +858,7 @@
void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig)
{
if (pid > 0) {
- ALOGI("Sending signal. PID: %d SIG: %d", pid, sig);
+ ALOGI("Sending signal. PID: %" PRId32 " SIG: %" PRId32, pid, sig);
kill(pid, sig);
}
}
@@ -887,7 +888,7 @@
{
char filename[64];
- snprintf(filename, sizeof(filename), "/proc/%d/smaps", pid);
+ snprintf(filename, sizeof(filename), "/proc/%" PRId32 "/smaps", pid);
FILE * file = fopen(filename, "r");
if (!file) {
@@ -899,7 +900,7 @@
jlong pss = 0;
while (fgets(line, sizeof(line), file)) {
jlong v;
- if (sscanf(line, "Pss: %lld kB", &v) == 1) {
+ if (sscanf(line, "Pss: %" SCNd64 " kB", &v) == 1) {
pss += v;
}
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 8549004..ef5ebd0 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -287,7 +287,7 @@
jlong rendererPtr, jlong paintPtr, jint saveFlags) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
- const android::uirenderer::Rect& bounds(renderer->getClipBounds());
+ const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
return renderer->saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
paint, saveFlags);
}
@@ -302,7 +302,7 @@
static jint android_view_GLES20Canvas_saveLayerAlphaClip(JNIEnv* env, jobject clazz,
jlong rendererPtr, jint alpha, jint saveFlags) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- const android::uirenderer::Rect& bounds(renderer->getClipBounds());
+ const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
return renderer->saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom,
alpha, saveFlags);
}
@@ -356,7 +356,7 @@
static jboolean android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject clazz,
jlong rendererPtr, jobject rect) {
OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
- const android::uirenderer::Rect& bounds(renderer->getClipBounds());
+ const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds());
env->CallVoidMethod(rect, gRectClassInfo.set,
int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
@@ -870,8 +870,7 @@
return reinterpret_cast<jlong>(renderer->finishRecording());
}
-static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
- jobject clazz) {
+static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) {
return reinterpret_cast<jlong>(new DisplayListRenderer);
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8141a00..c293c7a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -508,7 +508,7 @@
nsecs_t presentedTimesNanoSrc[frameCount];
for (size_t i = 0; i < frameCount; i++) {
- nsecs_t presentedTimeNano = stats.desiredPresentTimesNano[i];
+ nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
if (presentedTimeNano == INT64_MAX) {
presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b8fe0ff..4f093a8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2056,6 +2056,13 @@
android:description="@string/permdesc_bindWallpaper"
android:protectionLevel="signature|system" />
+ <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
+ to ensure that only the system can bind to it. -->
+ <permission android:name="android.permission.BIND_VOICE_INTERACTION"
+ android:label="@string/permlab_bindVoiceInteraction"
+ android:description="@string/permdesc_bindVoiceInteraction"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
to ensure that only the system can bind to it.
@hide -->
@@ -2071,6 +2078,14 @@
android:description="@string/permdesc_bindTvInput"
android:protectionLevel="signature|system" />
+ <!-- Must be required by a {@link android.media.routeprovider.RouteProviderService}
+ to ensure that only the system can interact with it.
+ -->
+ <permission android:name="android.permission.BIND_ROUTE_PROVIDER"
+ android:label="@string/permlab_bindRouteProvider"
+ android:description="@string/permdesc_bindRouteProvider"
+ android:protectionLevel="signature" />
+
<!-- Must be required by device administration receiver, to ensure that only the
system can interact with it. -->
<permission android:name="android.permission.BIND_DEVICE_ADMIN"
@@ -2612,6 +2627,15 @@
android:description="@string/permdesc_bindNotificationListenerService"
android:protectionLevel="signature" />
+ <!-- Must be required by an {@link
+ android.service.notification.ConditionProviderService},
+ to ensure that only the system can bind to it.
+ @hide -->
+ <permission android:name="android.permission.BIND_CONDITION_PROVIDER_SERVICE"
+ android:label="@string/permlab_bindConditionProviderService"
+ android:description="@string/permdesc_bindConditionProviderService"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to call into a carrier setup flow. It is up to the
carrier setup application to enforce that this permission is required
@hide This is not a third-party API (intended for OEMs and system apps). -->
diff --git a/core/res/res/color/primary_text_quantum_dark.xml b/core/res/res/color/primary_text_quantum_dark.xml
new file mode 100644
index 0000000..1fcd0e3
--- /dev/null
+++ b/core/res/res/color/primary_text_quantum_dark.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_quantum_dark"/>
+ <item android:color="@color/primary_text_default_quantum_dark"/>
+</selector>
diff --git a/core/res/res/color/primary_text_quantum_light.xml b/core/res/res/color/primary_text_quantum_light.xml
new file mode 100644
index 0000000..1ec1634
--- /dev/null
+++ b/core/res/res/color/primary_text_quantum_light.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_quantum_light"/>
+ <item android:color="@color/primary_text_default_quantum_light"/>
+</selector>
diff --git a/core/res/res/drawable-hdpi/ic_settings.png b/core/res/res/drawable-hdpi/ic_settings.png
new file mode 100644
index 0000000..cfa539f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_settings.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_settings.png b/core/res/res/drawable-mdpi/ic_settings.png
new file mode 100644
index 0000000..e6237eb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_settings.png b/core/res/res/drawable-xhdpi/ic_settings.png
new file mode 100644
index 0000000..208089d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_settings.png b/core/res/res/drawable-xxhdpi/ic_settings.png
new file mode 100644
index 0000000..452942e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_settings.png
Binary files differ
diff --git a/core/res/res/drawable/btn_borderless_quantum.xml b/core/res/res/drawable/btn_borderless_quantum.xml
index 69a891a..2e3c515 100644
--- a/core/res/res/drawable/btn_borderless_quantum.xml
+++ b/core/res/res/drawable/btn_borderless_quantum.xml
@@ -16,7 +16,6 @@
<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="?attr/colorButtonPressed">
- <item android:drawable="@color/transparent" />
<item android:id="@id/mask"
android:drawable="@drawable/btn_qntm_alpha" />
</touch-feedback>
diff --git a/core/res/res/drawable/btn_color_quantum.xml b/core/res/res/drawable/btn_color_quantum.xml
index e923003..2da9226 100644
--- a/core/res/res/drawable/btn_color_quantum.xml
+++ b/core/res/res/drawable/btn_color_quantum.xml
@@ -19,7 +19,8 @@
<selector>
<item android:state_enabled="false">
<nine-patch android:src="@drawable/btn_qntm_alpha"
- android:tint="?attr/colorButtonNormal" />
+ android:tint="?attr/colorButtonNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item>
<nine-patch android:src="@drawable/btn_qntm_alpha"
diff --git a/core/res/res/drawable/btn_default_quantum.xml b/core/res/res/drawable/btn_default_quantum.xml
index 2919621..c6a3a33 100644
--- a/core/res/res/drawable/btn_default_quantum.xml
+++ b/core/res/res/drawable/btn_default_quantum.xml
@@ -17,7 +17,18 @@
<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="?attr/colorButtonPressed">
<item>
- <nine-patch android:src="@drawable/btn_qntm_alpha"
- android:tint="?attr/colorButtonNormal" />
+ <selector>
+ <item android:state_enabled="false">
+ <nine-patch
+ android:src="@drawable/btn_qntm_alpha"
+ android:tint="?attr/colorButtonNormal"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item>
+ <nine-patch
+ android:src="@drawable/btn_qntm_alpha"
+ android:tint="?attr/colorButtonNormal" />
+ </item>
+ </selector>
</item>
</touch-feedback>
diff --git a/core/res/res/drawable/btn_radio_quantum.xml b/core/res/res/drawable/btn_radio_quantum.xml
index 152e3d3..0f9ebce 100644
--- a/core/res/res/drawable/btn_radio_quantum.xml
+++ b/core/res/res/drawable/btn_radio_quantum.xml
@@ -15,18 +15,20 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true" android:state_enabled="true" android:state_pressed="true">
- <bitmap android:src="@drawable/btn_radio_on_pressed_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
+ <item android:state_enabled="false" android:state_checked="true">
+ <bitmap android:src="@drawable/btn_radio_on_qntm_alpha"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_enabled="false">
+ <bitmap android:src="@drawable/btn_radio_off_qntm_alpha"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true">
<bitmap android:src="@drawable/btn_radio_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
- <item android:state_enabled="true" android:state_pressed="true">
- <bitmap android:src="@drawable/btn_radio_off_pressed_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
<item>
<bitmap android:src="@drawable/btn_radio_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/drawable/dialog_background_quantum.xml b/core/res/res/drawable/dialog_background_quantum.xml
new file mode 100644
index 0000000..7e5b003
--- /dev/null
+++ b/core/res/res/drawable/dialog_background_quantum.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+
+ <corners
+ android:radius="2dp" />
+ <solid
+ android:color="?attr/colorBackground" />
+
+</shape>
diff --git a/core/res/res/drawable/edit_text_quantum.xml b/core/res/res/drawable/edit_text_quantum.xml
index d1f9831..c42c7b7 100644
--- a/core/res/res/drawable/edit_text_quantum.xml
+++ b/core/res/res/drawable/edit_text_quantum.xml
@@ -14,29 +14,26 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_window_focused="false" android:state_enabled="true">
- <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:state_window_focused="false" android:state_enabled="false">
- <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
- <item android:state_enabled="true" android:state_focused="true">
- <nine-patch android:src="@drawable/textfield_activated_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:state_enabled="true" android:state_activated="true">
- <nine-patch android:src="@drawable/textfield_activated_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:state_enabled="true">
- <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
+<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
+ android:tint="?attr/colorControlActivated">
<item>
- <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
- android:tint="?attr/colorControlNormal" />
+ <selector>
+ <item android:state_window_focused="false">
+ <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:state_enabled="false">
+ <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item android:state_focused="false" android:state_activated="false">
+ <nine-patch android:src="@drawable/textfield_default_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ <item>
+ <nine-patch android:src="@drawable/textfield_activated_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ </selector>
</item>
-</selector>
+</touch-feedback>
diff --git a/core/res/res/drawable/list_selector_quantum.xml b/core/res/res/drawable/list_selector_quantum.xml
new file mode 100644
index 0000000..c007117
--- /dev/null
+++ b/core/res/res/drawable/list_selector_quantum.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
+ android:tint="?attr/colorButtonPressed">
+ <item android:id="@id/mask">
+ <color android:color="@color/white" />
+ </item>
+</touch-feedback>
diff --git a/core/res/res/drawable/scrubber_control_selector_quantum.xml b/core/res/res/drawable/scrubber_control_selector_quantum.xml
index e34f64a..ef3af0c 100644
--- a/core/res/res/drawable/scrubber_control_selector_quantum.xml
+++ b/core/res/res/drawable/scrubber_control_selector_quantum.xml
@@ -19,10 +19,6 @@
<bitmap android:src="@drawable/scrubber_control_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />
</item>
- <item android:state_pressed="true">
- <bitmap android:src="@drawable/scrubber_control_on_pressed_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
<item>
<bitmap android:src="@drawable/scrubber_control_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
diff --git a/core/res/res/drawable/switch_inner_quantum.xml b/core/res/res/drawable/switch_inner_quantum.xml
index 915377e..856895e 100644
--- a/core/res/res/drawable/switch_inner_quantum.xml
+++ b/core/res/res/drawable/switch_inner_quantum.xml
@@ -15,18 +15,20 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true" android:state_pressed="true">
+ <item android:state_enabled="false" android:state_checked="true">
<nine-patch android:src="@drawable/switch_on_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
+ </item>
+ <item android:state_enabled="false">
+ <nine-patch android:src="@drawable/switch_off_qntm_alpha"
+ android:tint="?attr/colorControlNormal"
+ android:alpha="?attr/disabledAlpha" />
</item>
<item android:state_checked="true">
<nine-patch android:src="@drawable/switch_on_qntm_alpha"
android:tint="?attr/colorControlActivated" />
</item>
- <item android:state_pressed="true">
- <nine-patch android:src="@drawable/switch_off_qntm_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
<item>
<nine-patch android:src="@drawable/switch_off_qntm_alpha"
android:tint="?attr/colorControlNormal" />
diff --git a/core/res/res/layout/alert_dialog_quantum.xml b/core/res/res/layout/alert_dialog_quantum.xml
index 537162a..80e34cb 100644
--- a/core/res/res/layout/alert_dialog_quantum.xml
+++ b/core/res/res/layout/alert_dialog_quantum.xml
@@ -20,7 +20,10 @@
android:id="@+id/parentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:background="@drawable/dialog_background_quantum"
+ android:translationZ="@dimen/floating_window_z"
+ android:layout_margin="@dimen/floating_window_margin">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/simple_list_item_2_single_choice.xml b/core/res/res/layout/simple_list_item_2_single_choice.xml
index 65c5856..940c6b8 100644
--- a/core/res/res/layout/simple_list_item_2_single_choice.xml
+++ b/core/res/res/layout/simple_list_item_2_single_choice.xml
@@ -21,7 +21,8 @@
android:gravity="center_vertical"
android:paddingStart="16dip"
android:paddingEnd="12dip"
- android:minHeight="?android:attr/listPreferredItemHeightSmall">
+ android:minHeight="?attr/listPreferredItemHeightSmall"
+ android:background="@color/transparent">
<LinearLayout
android:layout_width="wrap_content"
@@ -33,8 +34,8 @@
<TextView android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceListItem"
- android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:textAppearance="?attr/textAppearanceListItem"
+ android:textColor="?attr/textColorAlertDialogListItem"
android:gravity="center_vertical|start"
android:singleLine="true"
android:ellipsize="marquee" />
@@ -42,8 +43,8 @@
<TextView android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceListItemSecondary"
- android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:textAppearance="?attr/textAppearanceListItemSecondary"
+ android:textColor="?attr/textColorAlertDialogListItem"
android:gravity="center_vertical|start"
android:singleLine="true"
android:ellipsize="marquee" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index bf8037a..db4092e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkroniseer"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel <xliff:g id="CONTENT_TYPE">%s</xliff:g> uitgevee."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Horlosieberging is vol! Vee \'n paar lêers uit om plek te maak."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Foon se berging is vol. Vee \'n aantal lêers uit om spasie vry te maak."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan dalk gemonitor word"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Deur \'n onbekende derde party"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Luitoestel aan"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Sit tans af…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Jou tablet gaan nou afskakel."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Jou horlosie gaan nou afskakel."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Jou foon gaan nou afsit."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Wil jy afskakel?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Herlaai na veilige modus"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegtuigmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegtuigmodus is AAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegtuigmodus is AF"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Instellings"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Laat die program toe om \'n kennisgewing uit te saai dat \'n SMS-boodskap ontvang is. Kwaadwillige programme kan dit dalk gebruik om inkomende SMS-boodskappe na te maak."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"stuur WAP-PUSH-ontvange uitsending"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Laat die program toe om \'n kennisgewing uit te saai dat \'n WAP PUSH-boodskap ontvang is. Kwaadwillige programme kan dit dalk gebruik om MMS-boodskap-ontvangsbewyse na te maak of die inhoud van enige webbladsy stilweg te vervang met kwaadwillige variante."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"stuur uitsending vir netwerktelling"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Laat die program toe om \'n kennisgewing uit te saai dat netwerke tellings moet kry. Nooit vir normale programme nodig nie."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"beperk hoeveelheid lopende prosesse"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Laat die program toe om die maksimum getal prosesse te beheer wat sal loop. Nooit nodig vir normale programme nie."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"dwing agtergrondprogramme om te sluit"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Dit laat die houer toe om aan die top-koppelvlak van \'n afstandskerm te koppel. Behoort nooit vir gewone programme nodig te wees nie."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind aan \'n legstukdiens"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind aan \'n roeteverskafferdiens"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Laat die houer toe om aan enige geregistreerde roeteverskaffers te bind. Behoort nooit vir normale programme nodig te wees nie."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Laat die houer toe om bedoelings na \'n toesteladministrateur te stuur. Dit moet nooit vir normale programme nodig wees nie."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bind aan \'n TV-invoer"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Verander WiMAX-status"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Laat die program toe om die tablet aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Laat die program toe om die foon aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"gee telling vir netwerke"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Laat die program toe om netwerke te gradeer en beïnvloed watter netwerke die tablet moet verkies."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Laat die program toe om netwerke te gradeer en beïnvloed watter netwerke die foon moet verkies."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"bind saam met Bluetooth-toestelle"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Laat die program toe om die opstelling van Bluetooth op die tablet te sien, en om verbindings met saamgebinde toestelle te maak en te aanvaar."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Laat die program toe om die opstelling van die Bluetooth op die foon te sien, en om verbindings met saamgebinde toestelle te maak en te aanvaar."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 585857b..de89ec6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ሥምሪያ"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"በጣም ብዙ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ስርዞች።"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"የጡባዊ ተኮ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"የእጅ ሰዓት ማከማቻ ሙሉ ነው። ቦታ ለማስለቀቅ አንዳንድ ፋይሎችን ይሰርዙ።"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"የስልክ ማከማቻ ሙሉ ነው! ቦታ ነፃ ለማድረግ አንዳንድ ፋይሎች ሰርዝ።"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"አውታረ መረብ በክትትል ውስጥ ሊሆን ይችላል"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ባልታወቀ ሶስተኛ ወገን"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"መጥሪያ በርቷል"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"በመዝጋት ላይ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"ጡባዊዎ ይዘጋል።"</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"የእርስዎ የእጅ ሰዓት ይዘጋል።"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"ስልክዎ ይዘጋል።"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"ዘግተህ መውጣት ትፈልጋለህ?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"በአስተማማኝ ኹነታ ውስጥ ዳግም አስጀምር"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"የአውሮፕላን ሁነታ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"የአውሮፕላንሁነታ በርቷል"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"የአውሮፕላንሁነታ ጠፍቷል"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ኤስ ኤም ኤስ መልዕክት መቀበሉን ማሳወቂያ እንዲያሰራጭ ለመተግበሪያው ይፈቅዳሉ፡፡ መጪ ኤስ ኤም ኤስ መልዕክቶችን አመሳስሎ በማቅረብ ተንኮል አዘል መተግበሪያዎች ይሄንን ሊጠቀሙበት ይችላሉ፡፡"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"የWAP-PUSH ደርስዋል ስርጭት ላክ"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"የWAP PUSH መልዕክት እንደተቀበለ ማሳወቂያ ለማሰራጨት ለመተግበሪያው ይፈቅዳሉ፡፡ ኤም ኤም ኤስ መልዕክት መቀበልን ለማስመሰል ወይም በተንኮል አዘል መሰሎች ለማንኛውም የድር ገፅ ይዘት በዝምታ ለመተካት ተንኮል አዘል መተግበሪያዎች ሊጠቀሙበት ይችላሉ፡፡"</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ለአውታረ መረቦች የነጥብ ስጥ ስርጭት ይልካል"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"መተግበሪያው አውታረ መረቦች ነጥብ እንዲያዝለት የሚፈልጉት አንድ ማሳወቂያ እንዲያሰራጭ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"የአሂድ ሂደቶችን ቁጥር ወስን"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"የሚሄዱ ሂደቶችን የመጨረሻ ቁጥር ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ፡፡ ለመደበኛ መተግበሪያዎች መቼም አያስፈልግም፡፡"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"የጀርባ መተግበሪያዎች እንዲዘጉ አስገድዳቸው"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ያዢው ከአንድ የርቀት ማሳያ ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ወደ ፍርግም አገልግሎት አያይዝ"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ከመንገድ አቅራቢዎች አገልግሎት ጋር ያስተሳስሩ"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"አቃፊው ከማናቸውም የተመዘገቡ የመንገድ አቅራቢዎች ጋር እንዲተሳሰር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ያዡ በይነመረብን ለመሣሪያ አስተዳዳሪ ለመላክ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ከአንድ የቴሌቪዥን ግብዓት ጋር እሰር"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"የWiMAX ሁኔታ ለውጥ"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"መተግበሪያው ጡባዊ ተኮውን ከWiMAX አውታረ መረብ ጋር እንዲያገናኝና እንዲያለያይ ይፈቅድለታል።"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"መተግበሪያው ስልኩን ከWiMAX አውታረ መረብ ጋር እንዲያገናኝና እንዲያለያይ ይፈቅድለታል።"</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ለአውታረ መረቦች ነጥብ ይሰጣል"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ጡባዊው የትኛዎቹን አውታረ መረቦች እንደሚመርጥ ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"መተግበሪያው ለአውታረ መረቦች ደረጃ እንዲሰጥ እና ስልኩ የትኛዎቹን አውታረ መረቦች እንደሚመርጥ እና ላይ ተጽዕኖ እንዲያሳርፍ ያስችለዋል።"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ከብሉቱዝ መሣሪያዎች ጋር ተጣመር"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"መተግበሪያው በጡባዊ ተኮው ላይ ያለውን የብሉቱዝ ውቅር እንዲያይ እና ከተጣመሩ መሳሪያዎች ጋር ግንኙነቶችን እንዲያደርግና እንዲቀበል ይፈቅድለታል።"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"መተግበሪያው በስልኩ ላይ ያለውን የብሉቱዝ ውቅር እንዲያይ እና ከተጣመሩ መሳሪያዎች ጋር ግንኙነቶችን እንዲያደርግና እንዲቀበል ይፈቅድለታል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 468c14b..2ee49bd 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"وضع الطائرة"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"وضع الطائرة قيد التشغيل"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"وضع الطائرة متوقف"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"الإعدادات"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"نظام Android"</string>
@@ -337,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"للسماح للتطبيق ببث إشعار باستلام رسالة قصيرة SMS. قد تستخدم التطبيقات الضارة هذا لتزييف الرسائل القصيرة SMS الواردة."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"إرسال بث WAP-PUSH المستلم"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"للسماح للتطبيق ببث إشعار باستلام رسالة WAP PUSH. يمكن أن تستخدم التطبيقات الضارة هذا لتزيف استلام رسالة وسائط متعددة أو لاستبدال محتوى أي صفحة ويب بمتغيرات ضارة بشكل غير ملحوظ."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"إرسال بث الشبكات التي تم تقييمها"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"السماح للتطبيق لكي يبث إشعارًا يفيد بأنه يلزم تقييم الشبكات. لا يلزم ذلك مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"تحديد عدد العمليات قيد التشغيل"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"للسماح للتطبيق بالتحكم في الحد الأقصى لعدد العمليات التي سيتم تشغيلها. غير مطلوب على الإطلاق للتطبيقات العادية."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"فرض إغلاق تطبيقات الخلفية"</string>
@@ -392,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للعرض عن بُعد. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"الالتزام بخدمة أداة"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"الربط مع خدمة مزود طريق"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"للسماح لحامل البطاقة الربط مع أي مزود طريق مسجل. لا يجب استخدامه على الإطلاق مع التطبيقات العادية."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"للسماح للمالك بإرسال الأهداف إلى أحد مشرفي الجهاز. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"الالتزام بإدخال التلفزيون"</string>
@@ -642,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"تغيير حالة WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"للسماح للتطبيق بتوصيل الجهاز اللوحي بشبكات WiMAX وقطع اتصاله بها."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"للسماح للتطبيق بتوصيل الهاتف بشبكات WiMAX وقطع اتصاله بها."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"تقييم الشبكات"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"للسماح للتطبيق بترتيب الشبكات وتحديد تلك الشبكات التي من المفضل أن يستخدمها الجهاز اللوحي."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"للسماح للتطبيق بترتيب الشبكات وتحديد تلك الشبكات التي من المفضل أن يستخدمها الهاتف."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"الاتصال بأجهزة بلوتوث"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"للسماح للتطبيق بعرض تهيئة البلوتوث على الجهاز اللوحي وإجراء اتصالات وقبولها مع الأجهزة المقترنة."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"للسماح للتطبيق بعرض تهيئة البلوتوث على الهاتف وإجراء اتصالات وقبولها مع الأجهزة المقترنة."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index bb2bf43..3f00f1f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизиране"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Изтриванията за <xliff:g id="CONTENT_TYPE">%s</xliff:g> са твърде много."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Хранилището на таблета е пълно. Изтрийте файлове, за да освободите място."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Хранилището на часовника е пълно. Изтрийте файлове, за да освободите място."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Хранилището на телефона е пълно. Изтрийте файлове, за да освободите място."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежата може да се наблюдава"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"От неизвестна трета страна"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Звъненето е включено"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Изключва се..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таблетът ви ще се изключи."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Часовникът ви ще се изключи."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефонът ви ще се изключи."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Искате ли да изключите?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Рестартиране в безопасен режим"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Самолетен режим"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Самолетният режим е ВКЛЮЧЕН"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Самолетният режим е ИЗКЛЮЧЕН"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Разрешава на приложението да излъчва известие, че е получен SMS. Злонамерените приложения могат да използват това, за да фалшифицират входящите SMS съобщения."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"изпращане на излъчване при получено WAP PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Разрешава на приложението да излъчва известие, че е получено WAP PUSH съобщение. Злонамерените приложения могат да използват това, за да фалшифицират получаването на MMS или скрито да заменят съдържанието на произволна уеб страница със злонамерен вариант."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"изпращане на излъчване за оценяване на мрежите"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Разрешава на приложението да излъчи известие, че мрежите трябва да бъдат оценени. Не е необходимо за нормалните приложения."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ограничаване на броя изпълнявани процеси"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Разрешава на приложението да контролира максималния брой изпълнявани процеси. Нормалните приложения никога не се нуждаят от това."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"принудително затваряне на приложенията на заден план"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Разрешава на притежателя да се свърже с интерфейса от първо ниво на отдалечен екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обвързване с услуга за приспособления"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"свързване с услуга за предоставяне на маршрути"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Разрешава на собственика да се свързва с всички регистрирани доставчици на маршрути. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Разрешава на притежателя да изпраща намерения до администратор на устройството. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"свързване към вход на телевизор"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Промяна на състоянието на WiMAX мрежата"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Разрешава на приложението да свързва таблета към WiMAX мрежа и да прекратява връзката му с нея."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Разрешава на приложението да свързва телефона към WiMAX мрежа и да прекратява връзката му с нея."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"оценяване на мрежите"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Разрешава на приложението да класира мрежите и да повлияе върху това, кои да са предпочитаните за таблета."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Разрешава на приложението да класира мрежите и да повлияе върху това, кои да са предпочитаните за телефона."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"сдвояване с устройства с Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Разрешава на приложението да вижда конфигурацията на Bluetooth на таблета и да изгражда и приема връзки със сдвоени устройства."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Разрешава на приложението да вижда конфигурацията на Bluetooth на телефона и да изгражда и приема връзки със сдвоени устройства."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 11601bb..afb0852 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronització"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Massa supressions de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"L\'emmagatzematge de la tauleta és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"L\'emmagatzematge del rellotge està ple. Suprimeix uns quants fitxers per alliberar espai."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"L\'emmagatzematge del telèfon és ple. Suprimeix uns quants fitxers per alliberar espai."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"És possible que la xarxa estigui supervisada"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Per un tercer desconegut"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activat"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"S\'està apagant..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"La tauleta s\'apagarà."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"El rellotge s\'apagarà."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"El telèfon s\'apagarà."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vols apagar-lo?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reinicia en mode segur"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode d\'avió"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode d\'avió activat"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode d\'avió desactivat"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Configuració"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet que l\'aplicació difongui una notificació en què s\'indiqui que s\'ha rebut un missatge SMS. Les aplicacions malicioses poden fer servir aquesta funció per falsificar els missatges SMS entrants."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar una difusió de tipus WAP-PUSH-received"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet que l\'aplicació difongui una notificació que indica que s\'ha rebut un missatge d\'inserció WAP. Les aplicacions malicioses poden utilitzar-ho per falsificar la recepció dels missatges MMS o per substituir silenciosament el contingut d\'una pàgina web per variants malicioses."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar l\'emissió de la puntuació de les xarxes"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permet que l\'aplicació emeti una notificació necessària perquè les xarxes rebin una puntuació. No es necessita mai per a les aplicacions normals."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar el nombre de processos en execució"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet que l\'aplicació controli el nombre màxim de processos que s\'executaran. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"com fer que es tanquin les aplicacions en segon pla"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet que el titular es vinculi a la interfície de nivell superior d\'una pantalla remota. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincula a un servei de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"establir vincles amb un servei d\'aprovisionament de rutes"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permet que el titular estableixi vincles amb els proveïdors de rutes registrats. No hauria de ser mai necessari per a les aplicacions normals."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet que el titular enviï intents a un administrador del sistema. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"Vinculació a una entrada de televisor"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Canvia l\'estat de WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet que l\'aplicació connecti i desconnecti la tauleta de les xarxes WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet que l\'aplicació connecti i desconnecti el telèfon de les xarxes WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar les xarxes"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permet que l\'aplicació classifiqui les xarxes i indiqui quines han de ser les xarxes preferides de la tauleta."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permet que l\'aplicació classifiqui les xarxes i indiqui quines han de ser les xarxes preferides del telèfon."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"emparella amb dispositius Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet que l\'aplicació visualitzi la configuració de Bluetooth de la tauleta i que estableixi i accepti connexions amb dispositius sincronitzats."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet que una aplicació visualitzi la configuració de Bluetooth del telèfon i que estableixi i accepti connexions amb els dispositius sincronitzats."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ef6c7e9..39c6c08 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V letadle"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V letadle je ZAPNUTÝ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V letadle je VYPNUTÝ"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
@@ -337,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy SMS. Škodlivé aplikace mohou toto oprávnění použít k vytváření falešných příchozích zpráv SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"odeslání vysílání typu WAP-PUSH-received"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Umožňuje aplikaci vysílat oznámení o přijetí zprávy WAP PUSH. Škodlivé aplikace mohou toto oprávnění použít k vytváření falešných přijatých zpráv MMS nebo utajenému nahrazení obsahu libovolné webové stránky jejich škodlivými variantami."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"odeslání skóre vysílaných sítěmi"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Umožňuje aplikaci vysílat oznámení, že je třeba zadat skóre sítí. Běžné aplikace toto oprávnění nepotřebují."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"omezení počtu spuštěných procesů"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Umožňuje aplikaci řídit maximální počet spuštěných procesů. Běžné aplikace toto oprávnění nikdy nepotřebují."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vynucení zavření aplikací na pozadí"</string>
@@ -392,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteli připojit se k vysokoúrovňovému rozhraní vzdáleného displeje. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"navázat se na službu widgetu"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"navázání na službu poskytovatele tras"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umožňuje držiteli navázat se na libovolného poskytovatele registrovaných tras. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteli oprávnění odesílat informace správci zařízení. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"navázání na televizní vstup"</string>
@@ -642,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Změnit stav připojení WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Umožňuje aplikaci připojovat tablet k sítím WiMAX a odpojovat jej od nich."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Umožňuje aplikaci připojovat telefon k sítím WiMAX a odpojovat jej od nich."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"zadání skóre sítí"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Umožňuje aplikaci hodnotit sítě a ovlivňovat, které sítě by měl tablet preferovat."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Umožňuje aplikaci hodnotit sítě a ovlivňovat, které sítě by měl telefon preferovat."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"párování se zařízeními Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Umožňuje aplikaci zobrazit konfiguraci tabletu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Umožňuje aplikaci zobrazit konfiguraci telefonu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index be6e28e..c06ecbb 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkroniser"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange <xliff:g id="CONTENT_TYPE">%s</xliff:g> sletninger"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Din tablets lager er fuldt. Slet nogle filer for at frigøre plads."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Urets lager er fuldt. Slet nogle filer for at frigøre plads."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonens lager er fuldt. Slet nogle filer for at frigøre plads."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netværket kan være overvåget"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Af en ukendt tredjepart"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringeren er aktiveret"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din tablet slukkes nu."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Dit ur lukkes ned."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon slukkes nu."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slukke?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Genstart i sikker tilstand"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flytilstand"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flytilstand er TIL"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flytilstand er slået FRA"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Indstillinger"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Tillader, at appen kan udsende en underretning om, at der er modtaget en sms-besked. Ondsindede apps kan bruge dette til at simulere indgående sms-beskeder."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-modtaget udsendelse"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Tillader, at appen kan udsende en underretning om, at der er modtaget en WAP PUSH-besked. Ondsindede apps kan bruge dette til at simulere modtagelse af mms-beskeder eller i det skjulte erstatte indholdet på en webside med ondsindede varianter."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"sende underretninger om bedømmelse af netværk"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Tillader, at appen kan udsende en underretning om, at netværket skal bedømmes. Dette er aldrig nødvendigt for almindelige apps."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"begræns antallet af kørende processer"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Tillader, at appen kan kontrollere det maksimale antal kørende processer. Dette er aldrig nødvendigt til normale apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinge baggrundsapps til at lukke"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Tillader, at brugeren kan foretage en binding til grænsefladens øverste niveau på en ekstern skærm. Bør aldrig være nødvendigt til almindelige apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"forpligt til en widgettjeneste"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"oprette tilknytning til en ruteudbydertjeneste"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Tillader, at indehaveren opretter tilknytninger til registrerede ruteudbydere. Dette bør aldrig være nødvendigt for normale apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillader, at brugeren kan sende hensigter til en enhedsadministrator. Dette bør aldrig være nødvendigt for almindelige apps."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"knyt til en tv-indgang"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Skift WiMAX-tilstand"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Tillader, at appen kan oprette forbindelse fra tabletten og afbryde forbindelsen til tabletten på WiMAX-netværk."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Tillader, at appen kan oprette forbindelse fra telefonen og afbryde forbindelsen til telefonen på WiMAX-netværk."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"bedømme netværk"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Tillader, at appen rangerer netværk og påvirker, hvilke netværk tabletten bør foretrække."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Tillader, at appen rangerer netværk og påvirker, hvilke netværk telefonen bør foretrække."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"parre med Bluetooth-enheder"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Tillader, at appen kan læse konfigurationen af Bluetooth på tabletten samt kan oprette og acceptere forbindelser med parrede enheder."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Tillader, at appen kan læse konfigurationen af Bluetooth på telefonen samt kan oprette og acceptere forbindelser med parrede enheder."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3ba4c6f..e1ee025 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisierung"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zu viele <xliff:g id="CONTENT_TYPE">%s</xliff:g> gelöscht."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Der Tablet-Speicher ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Der Speicher Ihrer Uhr ist voll. Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Der Handyspeicher ist voll! Löschen Sie Dateien, um Speicherplatz freizugeben."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Das Netzwerk wird möglicherweise überwacht."</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Von einem unbekannten Dritten"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Klingelton ein"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Wird heruntergefahren..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ihr Tablet wird heruntergefahren."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ihre Uhr wird heruntergefahren."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon wird heruntergefahren."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Möchten Sie das Gerät herunterfahren?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Im abgesicherten Modus starten"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flugmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Einstellungen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
@@ -318,13 +317,13 @@
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"Bildschirminhalt abrufen"</string>
<string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Ermöglicht der App, den Inhalt des aktiven Fensters abzurufen. Schädliche Apps können so den gesamten Fensterinhalt abrufen und mit Ausnahme von Passwörtern den gesamten Text auswerten."</string>
<string name="permlab_temporary_enable_accessibility" msgid="2312612135127310254">"Bedienungshilfen vorübergehend aktivieren"</string>
- <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ermöglicht einer App, die Bedienungshilfen auf dem Gerät vorübergehend zu aktivieren. Schädliche Apps können Bedienungshilfen ohne die Zustimmung des Nutzers aktivieren."</string>
+ <string name="permdesc_temporary_enable_accessibility" msgid="8079456293182975464">"Ermöglicht der App, die Bedienungshilfen auf dem Gerät vorübergehend zu aktivieren. Schädliche Apps können Bedienungshilfen ohne die Zustimmung des Nutzers aktivieren."</string>
<string name="permlab_retrieveWindowToken" msgid="7154762602367758602">"Fenstertoken abrufen"</string>
<string name="permdesc_retrieveWindowToken" msgid="668173747687795074">"Berechtigt eine App zum Abruf des Fenstertokens. Bösartige Apps können sich als System ausgeben und unautorisiert mit dem App-Fenster interagieren."</string>
<string name="permlab_frameStats" msgid="7056374987314361639">"Framestatistiken abrufen"</string>
<string name="permdesc_frameStats" msgid="4758001089491284919">"Berechtigt eine App zur Erfassung von Framestatistiken. Bösartige Apps können möglicherweise die Framestatistiken für Fenster von anderen Apps beobachten."</string>
<string name="permlab_filter_events" msgid="8675535648807427389">"Ereignisse filtern"</string>
- <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht einer App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
+ <string name="permdesc_filter_events" msgid="8006236315888347680">"Ermöglicht der App, einen Eingabefilter zu registrieren, der den Stream aller Nutzerereignisse vor ihrem Versand filtert. Eine schädliche App kann die System-UI ohne Eingriff des Nutzers kontrollieren."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"Partielles Herunterfahren"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Versetzt den Aktivitätsmanager in einen heruntergefahrenen Zustand. Führt kein vollständiges Herunterfahren aus."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"App-Wechsel verhindern"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine SMS empfangen wurde. Schädliche Apps können so eingehende SMS fälschen."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Von WAP-PUSH empfangenen Broadcast senden"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ermöglicht der App, eine Benachrichtigung zu senden, dass eine WAP PUSH-Nachricht empfangen wurde. Schädliche Apps können so den Empfang von MMS vortäuschen oder unbemerkt den Inhalt einer beliebigen Webseite durch schädliche Inhalte ersetzen."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"Netzwerkbewertungen senden"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ermöglicht der App, Benachrichtigungen zu senden, dass Netzwerke bewertet werden müssen. Für normale Apps ist dies nie erforderlich."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"Anzahl der laufenden Prozesse beschränken"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ermöglicht der App, die maximale Anzahl an aktiven Prozessen zu steuern. Wird nie für normale Apps benötigt."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"Apps im Hintergrund schließen"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ermöglicht dem Halter, sich an die Oberfläche eines Remote-Displays auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"An einen Widget-Dienst binden"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"An Routenanbieterdienst binden"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ermöglicht dem Inhaber die Bindung an registrierte Routenanbieter. Sollte für normale Apps nicht erforderlich sein"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ermöglicht dem Halter, Intents an einen Geräteadministrator zu senden. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"An eine TV-Eingabe binden"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-Status ändern"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ermöglicht der App, eine Verbindung zwischen dem Tablet und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ermöglicht der App, eine Verbindung zwischen dem Telefon und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"Netzwerke bewerten"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ermöglicht der App, Netzwerke zu bewerten und die Auswahl des jeweiligen Netzwerks für das Tablet zu beeinflussen"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ermöglicht der App, Netzwerke zu bewerten und die Auswahl des jeweiligen Netzwerks für das Telefon zu beeinflussen"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Pairing mit Bluetooth-Geräten durchführen"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ermöglicht der App, die Bluetooth-Konfiguration eines Tablets einzusehen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ermöglicht der App, die Bluetooth-Konfiguration des Telefons einzusehen und Verbindungen mit gekoppelten Geräten herzustellen und zu akzeptieren."</string>
@@ -1338,7 +1334,7 @@
<string name="permlab_copyProtectedData" msgid="4341036311211406692">"Inhalte kopieren"</string>
<string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Ermöglicht der App das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalten. Nicht für normale Apps vorgesehen."</string>
<string name="permlab_route_media_output" msgid="1642024455750414694">"Medienausgabe umleiten"</string>
- <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht einer App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"Ermöglicht der App, die Medienausgabe auf andere externe Geräte umzuleiten."</string>
<string name="permlab_access_keyguard_secure_storage" msgid="7565552237977815047">"Zugriff auf mit Keyguard geschützten Speicher"</string>
<string name="permdesc_access_keyguard_secure_storage" msgid="5866245484303285762">"Ermöglicht einer App den Zugriff auf mit Keyguard geschützten Speicher"</string>
<string name="permlab_control_keyguard" msgid="172195184207828387">"Anzeige und Ausblenden des Keyguard steuern"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index b951897..5af0277 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Συγχρονισμός"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Πάρα πολλές <xliff:g id="CONTENT_TYPE">%s</xliff:g> διαγραφές."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ο αποθηκευτικός χώρος του tablet είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Ο αποθηκευτικός χώρος παρακολούθησης είναι πλήρης! Διαγράψτε μερικά αρχεία για να απελευθερώσετε χώρο."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Ο αποθηκευτικός χώρος του τηλεφώνου είναι πλήρης. Διαγράψτε μερικά αρχεία για να δημιουργήσετε ελεύθερο χώρο."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Το δίκτυο ενδέχεται να παρακολουθείται"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Από ένα άγνωστο τρίτο μέρος"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ειδοποίηση ήχου ενεργή"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Απενεργοποίηση..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Το tablet σας θα απενεργοποιηθεί."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Η παρακολούθησή σας θα τερματιστεί."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Το τηλέφωνό σας θα απενεργοποιηθεί."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Θέλετε να γίνει τερματισμός λειτουργίας;"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Επανεκκίνηση στην ασφαλή λειτουργία"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Λειτουργία πτήσης"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Η λειτουργία πτήσης είναι ενεργοποιημένη."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Λειτ. πτήσης είναι ανενεργή"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Ρυθμίσεις"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
<string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Επιτρέπει στην εφαρμογή την εκπομπή ειδοποίησης σχετικά με τη λήψη μηνύματος SMS. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τη δημιουργία πλαστών εισερχόμενων μηνυμάτων SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"αποστολή εκπομπής που έχει ληφθεί με WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Επιτρέπει στην εφαρμογή τη μετάδοση μιας ειδοποίησης ότι έχει ληφθεί κάποιο μήνυμα WAP PUSH. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τη λήψη πλαστών μηνυμάτων MMS ή την εν αγνοία του χρήστη αντικατάσταση του περιεχομένου οποιασδήποτε ιστοσελίδας με κακόβουλες παραλλαγές."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"αποστολή μετάδοσης κατάταξης δικτύων"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Επιτρέπει στην εφαρμογή να μεταδίδει μια ειδοποίηση ότι απαιτείται κατάταξη των δικτύων. Δεν απαιτείται ποτέ για τις συνήθεις εφαρμογές."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"περιορισμός αριθμού εκτελούμενων διαδικασιών"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Επιτρέπει στην εφαρμογή τον έλεγχο του μέγιστου αριθμού διαδικασιών που θα εκτελούνται. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"αναγκαστικός τερματισμός εφαρμογών στο παρασκήνιο"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας απομακρυσμένης οθόνης. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"δέσμευση σε υπηρεσία γραφικών στοιχείων"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"σύνδεση σε μια υπηρεσία παρόχου δρομολογητή"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Δίνει στον κάτοχο τη δυνατότητα σύνδεσης με οποιονδήποτε εγγεγραμμένο πάροχο δρομολογητή. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Επιτρέπει στον κάτοχο την αποστολή στόχων σε έναν διαχειριστή συσκευής. Δεν είναι απαραίτητο για συνήθεις εφαρμογές."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"σύνδεση σε μία είσοδο τηλεόρασης"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Αλλαγή κατάστασης WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Επιτρέπει στην εφαρμογή τη σύνδεση στο tablet και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Επιτρέπει στην εφαρμογή τη σύνδεση στο τηλέφωνο και την αποσύνδεση από αυτό, από δίκτυα WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"κατάταξη δικτύων"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Επιτρέπει στην εφαρμογή να κατατάσσει τα δίκτυα και να επιλέγει τα προτιμώμενα δίκτυα του tablet."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Επιτρέπει στην εφαρμογή να κατατάσσει τα δίκτυα και να επιλέγει τα προτιμώμενα δίκτυα του τηλεφώνου."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"σύζευξη με συσκευές Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο tablet, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Επιτρέπει στην εφαρμογή να προβάλλει τη διαμόρφωση του Bluetooth στο τηλέφωνο, καθώς και να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
@@ -1382,7 +1378,7 @@
<string name="vpn_lockdown_error" msgid="6009249814034708175">"Σφάλμα πάντα ενεργοποιημένου VPN"</string>
<string name="vpn_lockdown_config" msgid="6415899150671537970">"Αγγίξτε για διαμόρφωση"</string>
<string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
- <string name="no_file_chosen" msgid="6363648562170759465">"Δεν έχει επιλεγεί αρχείο"</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"Δεν επιλέχθηκε κανένα αρχείο."</string>
<string name="reset" msgid="2448168080964209908">"Επαναφορά"</string>
<string name="submit" msgid="1602335572089911941">"Υποβολή"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Η λειτουργία αυτοκινήτου είναι ενεργοποιημένη"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c13bb1e..ad45887 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sync"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Watch storage is full. Delete some files to free up space."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringer on"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Shutting down…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Your tablet will shut down."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Your watch will shut down."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Your phone will shut down."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Do you want to shut down?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot to safe mode"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Allows the app to broadcast a notification that an SMS message has been received. Malicious apps may use this to forge incoming SMS messages."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-received broadcast"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Allows the app to broadcast a notification that a WAP PUSH message has been received. Malicious apps may use this to forge MMS message receipt or to silently replace the content of any web page with malicious variants."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"send score networks broadcast"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Allows the app to broadcast a notification that networks need to be scored. Never needed for normal apps."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limit number of running processes"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Allows the app to control the maximum number of processes that will run. Never needed for normal apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"force background apps to close"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind to a route provider service"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Allows the holder to bind to any registered route providers. Should never be needed for normal apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bind to a TV input"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"change WiMAX state"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Allows the app to connect the tablet to and disconnect the tablet from WiMAX networks."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Allows the app to connect the phone to and disconnect the phone from WiMAX networks."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score networks"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Allows the app to rank networks and influence which networks the tablet should prefer."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Allows the app to rank networks and influence which networks the phone should prefer."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"pair with Bluetooth devices"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Allows the app to view the configuration of Bluetooth on the tablet and to make and accept connections with paired devices."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Allows the app to view the configuration of the Bluetooth on the phone and to make and accept connections with paired devices."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index c13bb1e..ad45887 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sync"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Too many <xliff:g id="CONTENT_TYPE">%s</xliff:g> deletions."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tablet storage is full. Delete some files to free space."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Watch storage is full. Delete some files to free up space."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Phone storage is full. Delete some files to free space."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Network may be monitored"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"By an unknown third party"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringer on"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Shutting down…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Your tablet will shut down."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Your watch will shut down."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Your phone will shut down."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Do you want to shut down?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot to safe mode"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Allows the app to broadcast a notification that an SMS message has been received. Malicious apps may use this to forge incoming SMS messages."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"send WAP-PUSH-received broadcast"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Allows the app to broadcast a notification that a WAP PUSH message has been received. Malicious apps may use this to forge MMS message receipt or to silently replace the content of any web page with malicious variants."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"send score networks broadcast"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Allows the app to broadcast a notification that networks need to be scored. Never needed for normal apps."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limit number of running processes"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Allows the app to control the maximum number of processes that will run. Never needed for normal apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"force background apps to close"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind to a route provider service"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Allows the holder to bind to any registered route providers. Should never be needed for normal apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Allows the holder to send intents to a device administrator. Should never be needed for normal apps."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bind to a TV input"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"change WiMAX state"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Allows the app to connect the tablet to and disconnect the tablet from WiMAX networks."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Allows the app to connect the phone to and disconnect the phone from WiMAX networks."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score networks"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Allows the app to rank networks and influence which networks the tablet should prefer."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Allows the app to rank networks and influence which networks the phone should prefer."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"pair with Bluetooth devices"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Allows the app to view the configuration of Bluetooth on the tablet and to make and accept connections with paired devices."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Allows the app to view the configuration of the Bluetooth on the phone and to make and accept connections with paired devices."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index b999506..6d032ca 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Configuración"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -337,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que la aplicación transmita una notificación acerca de la recepción de un mensaje SMS. Las aplicaciones maliciosas pueden utilizar este permiso para falsificar mensajes SMS entrantes."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisiones WAP-PUSH-recibido"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que la aplicación transmita una notificación acerca de la recepción de un mensaje WAP PUSH. Las aplicaciones maliciosas pueden utilizar este permiso para falsificar la recepción de mensajes MMS o para reemplazar sin aviso el contenido de cualquier página web con variantes maliciosas."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmisión de puntuación de redes"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que la aplicación transmita una notificación que las redes necesitan para recibir una puntuación. Las aplicaciones normales no necesitan nunca este permiso."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar la cantidad de procesos en ejecución"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que la aplicación controle la cantidad máxima de procesos que se ejecutarán. Las aplicaciones normales no deben utilizar este permiso."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forzar el cierre de aplicaciones de fondo"</string>
@@ -392,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite al propietario vincularse a la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servicio de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"vincular con un servicio de proveedor de rutas"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite al propietario vincular con proveedores de rutas registrados. No debe ser necesario para las aplicaciones normales."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite enviar intentos a un administrador de dispositivos. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"vincular a una entrada de TV"</string>
@@ -642,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar el estado de WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que la aplicación conecte la tablet a una red WiMAX y que la desconecte de ella."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que la aplicación conecte el dispositivo a una red WiMAX y que lo desconecte de ella."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar redes"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que la aplicación clasifique redes e influya en las redes que la tablet debería preferir."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que la aplicación clasifique redes e influya en las redes que el teléfono debería preferir."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"vincular con dispositivos Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que la aplicación vea la configuración de Bluetooth de la tablet y que cree y acepte conexiones con los dispositivos sincronizados."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que la aplicación vea la configuración de Bluetooth del dispositivo y que cree y acepte conexiones con los dispositivos sincronizados."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 24a919f..63bed24 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento del tablet. Elimina algunos archivos para liberar espacio."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"El almacenamiento del reloj está lleno. Elimina algunos archivos para liberar espacio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Es posible que la red esté supervisada"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por un tercero desconocido"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activado"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Apagando..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"El tablet se apagará."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"El reloj se apagará."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"El teléfono se apagará."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"¿Seguro que quieres apagar el teléfono?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar en modo seguro"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avión activado. Desactivar"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avión desactivado. Activar"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Ajustes"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"> 999"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que la aplicación emita una notificación cuando se haya recibido un mensaje SMS. Las aplicaciones malintencionadas pueden usar este permiso para falsificar mensajes SMS entrantes."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar emisión recibida mediante mensaje WAP PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que la aplicación envíe una notificación cuando se haya recibido un mensaje WAP PUSH. Las aplicaciones malintencionadas pueden usar este permiso para falsificar la recepción de un mensaje MMS o para reemplazar sin aviso el contenido de cualquier página web con variantes malintencionadas."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar notificaciones sobre la puntuación de las redes"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que la aplicación emita una notificación que la red necesita para recibir una puntuación. Las aplicaciones normales no necesitan nunca este permiso."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar el número de procesos en ejecución"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que la aplicación controle el número máximo de procesos que se ejecutarán. No es necesario nunca para las aplicaciones normales."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forzar el cierre de aplicaciones en segundo plano"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite enlazar con la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"enlazar con un servicio de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"enlazar con un servicio de proveedor de rutas"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite enlazar con proveedores de rutas registrados. No debe ser necesario para las aplicaciones normales."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que se envíen intentos a un administrador de dispositivos. Las aplicaciones normales nunca deberían necesitar este permiso."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"enlazar a una entrada de TV"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar estado de WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que la aplicación conecte el tablet a redes WiMAX y lo desconecte de ellas."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que la aplicación conecte el teléfono a redes WiMAX y lo desconecte de ellas."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"puntuar redes"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que la aplicación clasifique redes e influya en las redes que el tablet debe preferir."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que la aplicación clasifique una red e influya en las redes que el teléfono debe preferir."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"vincular con dispositivos Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que la aplicación acceda a la configuración de Bluetooth del tablet y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que la aplicación acceda a la configuración de Bluetooth del teléfono y que establezca y acepte conexiones con los dispositivos sincronizados."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 92b7acb..00e4a20 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sünkroonimine"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liiga palju üksuse <xliff:g id="CONTENT_TYPE">%s</xliff:g> kustutusi."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tahvelarvuti mäluruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Kella talletusruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Võrku võidakse jälgida"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Tundmatu kolmas osapool:"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Helin on sees"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Väljalülitamine ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Teie tahvelarvuti lülitub välja."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Teie kell lülitub välja."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Teie telefon lülitub välja."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Kas soovite välja lülitada?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Ohutus režiimis taaskäivitamine"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lennurežiim"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lennurežiim on SEES"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lennurežiim on VÄLJAS"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Võimaldab rakendusel edastada teatise SMS-sõnumi vastuvõtmise kohta. Pahatahtlikud rakendused võivad seda kasutada sissetulevate SMS-sõnumite võltsimiseks."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"saada WAP-PUSH-vastuvõetud saateid"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Võimaldab rakendusel edastada teatise WAP PUSH-sõnumi vastuvõtmise kohta. Pahatahtlikud rakendused võivad seda kasutada MMS-sõnumite vastuvõtmise võltsimiseks või mis tahes veebilehe sisu salaja asendamiseks pahatahtlikuga."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"võrkude levi hinnangu saatmine"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Lubab rakendusel levitada märguannet, et võrke tuleb hinnata. Seda ei ole kunagi vaja tavapäraste rakenduste puhul."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"piira töötavate protsesside arvu"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Võimaldab rakendusel juhtida töötavate protsesside maksimaalset arvu. Tavarakenduste puhul pole seda vaja."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"sundige taustarakendused sulguma"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lubab omanikul siduda rakenduse kaugekraani ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"sidumine marsruudi pakkumisteenusega"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Lubab õiguste omajal luua seosed kõikide registreeritud marsruutide pakkujatega. Pole kunagi vajalik tavaliste rakenduste korral."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Võimaldab omanikul saata kavatsusi seadme administraatorile. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"sidumine TV-sisendiga"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-i oleku muutmine"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Võimaldab rakendusel luua ja katkestada tahvelarvuti ühenduse WiMAX-i võrkudega."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Võimaldab rakendusel luua ja katkestada telefoni ühenduse WiMAX-i võrkudega."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"võrkude hindamine"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Lubab rakendusel võrke hinnata ja mõjutada seda, milliseid võrke peaks tahvelarvuti eelistama."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Lubab rakendusel võrke hinnata ja mõjutada seda, milliseid võrke peaks telefon eelistama."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"siduge Bluetoothi seadmetega"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Võimaldab rakendusel vaadata tahvelarvuti Bluetooth-konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Võimaldab rakendusel vaadata telefoni Bluetooth-konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index cf2f957..42d654e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"همگامسازی"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"تعداد موارد حذف شده <xliff:g id="CONTENT_TYPE">%s</xliff:g> بسیار زیاد است."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"حافظه رایانهٔ لوحی پر است! برخی از فایلها را حذف کنید تا فضا آزاد شود."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"حافظه ساعت پر است. برای آزادسازی فضا، چند فایل را حذف کنید."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"حافظه تلفن پر است. بعضی از فایلها را حذف کنید تا فضا آزاد شود."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ممکن است شبکه نظارت شده باشد"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"توسط یک شخص ثالث ناشناس"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"زنگ روشن"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"در حال خاموش شدن…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"رایانهٔ لوحی شما خاموش میشود."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ساعت شما خاموش میشود."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"گوشی شما خاموش میشود."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"آیا میخواهید تلفن خاموش شود؟"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"راهاندازی مجدد در حالت امن"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"حالت هواپیما"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"حالت هواپیما روشن است"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"حالت هواپیما خاموش است"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
<string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"سیستم Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"به برنامه اجازه میدهد تا اعلان دریافت پیام کوتاه را پخش کند. برنامههای مخرب میتوانند از این برای جعل پیامهای کوتاه ورودی استفاده کنند."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ارسال پخش دریافت شده توسط WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"به برنامه اجازه میدهد تا اعلانی را پخش کند که پیام WAP PUSH دریافت کرده است. برنامههای مخرب میتوانند از آن استفاده کنند تا دریافت پیام MMS را جعل کنند یا محتوای هر صفحهٔ وب را با انواع مخرب جایگزین کنند."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ارسال اعلان پخش برای امتیازبندی شبکهها"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"به برنامه اجازه میدهد تا اعلانی پخش کند که شبکهها باید امتیازبندی شوند. هرگز برای برنامههای عادی مورد نیاز نیست."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"محدود کردن تعداد فرآیندهای در حال اجرا"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"به برنامه اجازه میدهد تا حداکثر تعداد پردازشهایی را که اجرا خواهد شد کنترل کند. هرگز برای برنامههای عادی لازم نیست."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"بستن اجباری برنامههای پسزمینه"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"به دارنده امکان میدهد تا به رابط سطح بالای نمایشگر راه دور وصل شود. نباید هرگز برای برنامههای عادی لازم باشد."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"اتصال به یک سرویس ابزارک"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"اتصال به یک سرویس ارائهدهنده مسیر"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"به دارنده امکان میدهد به هر ارائهدهنده مسیر ثبت شدهای متصل شود. هرگز برای برنامههای عادی مورد نیاز نیست."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"به دارنده اجازه میدهد اهداف خود را به سرپرست دستگاه ارسال کند. برنامههای معمولی هیچگاه به این ویژگی نیازی ندارند."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"اتصال به ورودی تلویزیون"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"تغییر وضعیت WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"به برنامه امکان میدهد رایانهٔ لوحی را به شبکههای وایمکس متصل کرده یا اتصال آن را از این شبکهها قطع کند."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"به برنامه امکان میدهد تا تلفن را به شبکههای وایمکس متصل کرده یا اتصال آنرا از این شبکهها قطع کند."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"امتیازبندی شبکهها"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"به برنامه اجازه میدهد که شبکهها را درجهبندی کند و روی اینکه رایانه لوحی باید کدام شبکه را در اولویت قرار دهد تأثیر میگذارد."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"به برنامه اجازه میدهد که شبکهها را درجهبندی کند و روی اینکه تلفن باید کدام شبکه را در اولویت قرار دهد تأثیر میگذارد."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"جفت کردن با دستگاههای بلوتوث"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"به برنامه اجازه میدهد تا پیکربندی بلوتوث در رایانهٔ لوحی را مشاهده کند و اتصال با دستگاههای مرتبط را برقرار کرده و بپذیرد."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"به برنامه اجازه میدهد تا پیکربندی بلوتوث در تلفن را مشاهده کند، و اتصالات دستگاههای مرتبط را برقرار کرده و بپذیرد."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 4d11ad4..7698dda 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lentokonetila"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lentokonetila on KÄYTÖSSÄ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lentokonetila on POIS KÄYTÖSTÄ"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
@@ -337,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Sallii sovelluksen lähettää ilmoituksen tekstiviestin vastaanotosta. Haitalliset sovellukset voivat käyttää tätä saapuvien tekstiviestien väärentämiseen."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"lähetä WAP-PUSH-vastaanotettu lähetys"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Antaa sovelluksen lähettää ilmoituksen WAP PUSH -viestin vastaanotosta. Haitalliset sovellukset voivat käyttää tätä MMS-viestien vastaanoton väärentämiseen tai sivujen sisällön korvaamiseen huomaamattomasti haitallisella sisällöllä."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"lähetä verkkojen pisteet"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Sallii sovelluksen lähettää ilmoituksen verkon pisteytystarpeesta. Ei tarvita tavallisissa sovelluksissa."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"rajoita käynnissä olevien prosessien määrää"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Antaa sovelluksen hallita suoritettavien sovellusten enimmäismäärää. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"pakota taustasovelluksia sulkeutumaan"</string>
@@ -392,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Antaa sovelluksen sitoutua etänäytön ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sitoudu widget-palveluun"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"reitin tarjoajan palveluun sitominen"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Antaa sovelluksen luoda sidoksen mihin tahansa rekisteröityyn reitin tarjoajaan. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Antaa sovelluksen lähettää aikomuksia laitteen järjestelmänvalvojalle. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"sido TV-tuloon"</string>
@@ -642,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Vaihda WiMAX-verkon tilaa"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Antaa sovelluksen muodostaa tablet-laitteella yhteyden WiMAX-verkkoon ja katkaista yhteyden."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Antaa sovelluksen muodostaa puhelimella yhteyden WiMAX-verkkoon ja katkaista yhteyden."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"pisteytä verkot"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Sallii sovelluksen asettaa verkkoja paremmuusjärjestykseen ja vaikuttaa siihen, mikä verkko tablet-laitteen kannattaa valita."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Sallii sovelluksen asettaa verkkoja paremmuusjärjestykseen ja vaikuttaa siihen, mikä verkko puhelimen kannattaa valita."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"muodosta laitepari Bluetooth-laitteiden kanssa"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Antaa sovelluksen tarkastella tablet-laitteen Bluetooth-asetuksia sekä muodostaa ja hyväksyä laitepariyhteyksiä."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Antaa sovelluksen tarkastella puhelimen Bluetooth-asetuksia sekä muodostaa ja hyväksyä laitepariyhteyksiä muihin laitteisiin."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index d2f4c9b..cc3bcd2 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchroniser"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"La mémoire de la montre est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Le réseau peut être surveillé"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Par un tiers inconnu"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Votre tablette va s\'éteindre."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Votre montre va s\'éteindre."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Voulez-vous éteindre l\'appareil?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Redémarrer en mode sans échec"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message texte. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux messages entrants."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"envoyer une diffusion de réception de WAP par poussée"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message WAP par poussée. Des applications malveillantes peuvent utiliser cette fonctionnalité pour créer de faux messages multimédias entrants ou pour remplacer le contenu d\'une page Web par du contenu malveillant."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"diffuser le classement des réseaux"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Autorise l\'application à diffuser une notification signalant que les réseaux doivent être évalués. Cela n\'est jamais nécessaire pour les applications normales."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"restreindre le nombre de processus en cours d\'exécution"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet à l\'application de définir le nombre maximal de processus devant s\'exécuter. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forcer la fermeture des applications en arrière-plan"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un écran distant. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"s\'associer à un service de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"associer à un fournisseur d\'itinéraires enregistré"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permet à l\'application autorisée de s\'associer à des fournisseurs d\'itinéraires enregistrés. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur d\'un périphérique"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"s\'associer à une entrée de téléviseur"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifier l\'état du WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet à l\'application de connecter la tablette aux réseaux WiMAX et de l\'en déconnecter."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet à l\'application de connecter le téléphone aux réseaux WiMAX et de l\'en déconnecter."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"classer les réseaux"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Autorise l\'application à classer les réseaux et à influencer la sélection du réseau par la tablette."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Autorise l\'application à classer les réseaux et à influencer la sélection du réseau par le téléphone."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"s\'associer à des appareils Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur la tablette, et d\'établir et accepter des connexions avec les appareils associés."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur le téléphone, et d\'établir et accepter des connexions avec les appareils associés."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 7a42a6d..30c7767 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisation"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"La mémoire de la tablette est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"La mémoire de la montre est saturée. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"La mémoire du téléphone est pleine. Veuillez supprimer des fichiers pour libérer de l\'espace."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Il est possible que le réseau soit surveillé."</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Par un tiers inconnu"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Arrêt en cours..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Votre tablette va s\'éteindre."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"La montre va s\'éteindre."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Votre téléphone va s\'éteindre."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Voulez-vous éteindre l\'appareil ?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Redémarrer en mode sans échec"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un SMS. Des applications malveillantes peuvent exploiter cette fonctionnalité pour créer de faux SMS entrants."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Envoi de diffusion de réception de WAP PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permet à l\'application d\'envoyer une notification indiquant la réception d\'un message WAP PUSH. Des applications malveillantes peuvent exploiter cette fonctionnalité pour créer de faux MMS entrants ou pour remplacer le contenu d\'une page Web par du contenu malveillant."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"diffuser des notifications pour l\'évaluation des réseaux"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Autoriser l\'application à diffuser une notification signalant que les réseaux doivent être évalués. Cette autorisation n\'est pas nécessaire pour les applications standards."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"Nombre maximal de processus en cours d\'exécution"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permet à l\'application de contrôler le nombre maximal de processus devant s\'exécuter. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forcer la fermeture des applications en arrière-plan"</string>
@@ -361,7 +359,7 @@
<string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Permet à l\'application de lancer l\'interface utilisateur de confirmation de sauvegarde complète. Seules certaines applications peuvent bénéficier de cette permission."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Affichage de fenêtres non autorisées"</string>
<string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Permet à l\'application de créer des fenêtres destinées à être utilisées par l\'interface utilisateur du système interne. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
- <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"S\'afficher en surimpression dans les autres applis"</string>
+ <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"Se superposer aux autres applis"</string>
<string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permet à l\'application d\'ignorer d\'autres applications ou certaines parties de l\'interface utilisateur. Cela peut altérer votre utilisation de l\'interface de n\'importe quelle application, ou modifier ce que vous pensez voir dans d\'autres applications."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"Réglage de la vitesse des animations"</string>
<string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Permet à l\'application de modifier à tout moment la vitesse générale des animations pour les ralentir ou les accélérer."</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permettre à l\'application autorisée de s\'associer à l\'interface de niveau supérieur d\'un écran à distance. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associer à un service widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"s\'associer à un fournisseur d\'itinéraires"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permettre à l\'application autorisée de s\'associer à n\'importe quel fournisseur d\'itinéraires. Ne devrait pas être nécessaire pour les applications standards."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permet à l\'application autorisée d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"s\'associer à une entrée TV"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifier l\'état du WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permet à l\'application de connecter la tablette aux réseaux WiMAX et de l\'en déconnecter."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permet à l\'application de connecter le téléphone aux réseaux WiMAX et de l\'en déconnecter."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"évaluer les réseaux"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Autoriser l\'application à classer les réseaux et à influencer la sélection du réseau sur la tablette"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Autoriser l\'application à classer les réseaux et à influencer la sélection du réseau sur le téléphone"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"associer à des appareils Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur la tablette, et d\'établir et accepter des connexions avec les appareils associés."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permet à l\'application d\'accéder à la configuration du Bluetooth sur le téléphone, et d\'établir et accepter des connexions avec les appareils associés."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index dc298de..852215f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"समन्वयन"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"बहुत से <xliff:g id="CONTENT_TYPE">%s</xliff:g> हटाए जाते हैं."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"टेबलेट संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"घड़ी संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"फ़ोन संग्रहण भर गया है. स्थान रिक्त करने के लिए कुछ फ़ाइलें हटाएं."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"नेटवर्क को मॉनिटर किया जा सकता है"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"किसी अज्ञात तृतीय पक्ष के द्वारा"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"रिंगर चालू"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"शट डाउन हो रहा है..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"आपकी टेबलेट शट डाउन हो जाएगी."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"आपकी घड़ी बंद हो जाएगी."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"आपका फ़ोन शट डाउन हो जाएगा."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"क्या आप शट डाउन करना चाहते हैं?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"सुरक्षित मोड में रीबूट करें"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"हवाई जहाज मोड"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"हवाई जहाज मोड चालू है"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"हवाई जहाज मोड बंद है"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"सेटिंग"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ऐप्स को वह सूचना प्रसारित करने देता है जो SMS संदेश ने प्राप्त की है. दुर्भावनापूर्ण ऐप्स इसका उपयोग नकली इनकमिंग संदेश गढ़ने के लिए कर सकते हैं."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-प्राप्त प्रसारण भेजें"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ऐप्स को वह सूचना प्रसारित करने देता है जो WAP PUSH संदेश को प्राप्त हुआ है. दुर्भावनापूर्ण ऐप्स इसका उपयोग नकली MMS संदेश प्राप्त करने या किसी वेबपृष्ठ की सामग्री को दुर्भावनापूर्ण दूसरे रूप से चुपचाप प्रतिस्थापित करने के लिए कर सकते हैं."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"स्कोर नेटवर्क प्रसारण भेजें"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ऐप्स को यह सूचना प्रसारित करने देती है कि नेटवर्क को स्कोर किए जाने की आवश्यकता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"चल रही प्रक्रियाओं की संख्या सीमित करें"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ऐप्स को चलाई जाने वाली अधिकतम प्रक्रियाओं को नियंत्रित करने देता है. सामान्य ऐप्स के लिए कभी आवश्यक नहीं होती."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"पृष्ठभूमि ऐप्स को बलपूर्वक बंद करें"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"धारक को किसी रिमोट डिस्प्ले के शीर्ष-स्तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"किसी रूट प्रदाता सेवा से आबद्ध हों"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"धारक को किसी भी पंजीकृत रूट प्रदाता से आबद्ध रहने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्यवस्थापक के साथ सहभागिता करें"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"धारक को किसी उपकरण व्यवस्थापक को उद्देश्य भेजने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"टीवी इनपुट से आबद्ध करें"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX स्थिति बदलें"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"ऐप्स को WiMAX नेटवर्क से टेबलेट को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"ऐप्स को WiMAX नेटवर्क से फ़ोन को कनेक्ट और डिस्कनेक्ट करने देता है."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"स्कोर नेटवर्क"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ऐप्स को नेटवर्क को रैंक करने देती है और इस बात पर ज़ोर देती है कि टेबलेट को किस नेटवर्क को प्राथमिकता देनी चाहिए."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ऐप्स को नेटवर्क को रैंक करने देती है और इस बात पर ज़ोर देती है कि फ़ोन को किस नेटवर्क को प्राथमिकता देनी चाहिए."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth उपकरणों के साथ युग्मित करें"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"ऐप्स को टेबलेट पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ऐप्स को फ़ोन पर Bluetooth का कॉन्फ़िगरेशन देखने, और युग्मित उपकरणों के साथ कनेक्शन बनाने और स्वीकार करने देता है."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 96872e8..4ab25af 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkronizacija"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše brisanja stavki <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Prostor za pohranu tabletnog računala pun je. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Memorija sata je puna. Izbrišite neke datoteke da biste oslobodili prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Prostor za pohranu na telefonu je pun. Izbrišite nekoliko datoteka kako biste oslobodili prostor."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadzire"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Zvono uključeno"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Isključivanje..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Vaš tabletni uređaj će se isključiti."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Sat će se isključiti."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Vaš će se telefon isključiti."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Želite li isključiti uređaj?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Ponovno pokretanje u sigurnom načinu rada"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način rada u zrakoplovu"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uključen je način rada u zrakoplovu"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Isključen je način rada u zrakoplovu"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Omogućuje aplikaciji emitiranje obavijesti da je primljena SMS poruka. Zlonamjerne aplikacije mogu to upotrijebiti za krivotvorenje dolaznih SMS poruka."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"slanje WAP-PUSH-primljenih prijenosa"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Omogućuje aplikaciji emitiranje obavijesti da je primljena WAP PUSH poruka. Zlonamjerne aplikacije mogu to upotrijebiti da bi krivotvorile prijem MMS poruka ili da bi potajno zamijenile sadržaj bilo koje web-stranice zlonamjernim varijantama."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"slanje obavijesti za ocjenjivanje mreža"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Aplikaciji omogućuje emitiranje obavijesti da se mreža treba ocijeniti. Nije potrebno za normalne aplikacije."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ograničavanje broja pokrenutih postupaka"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Omogućuje aplikaciji upravljanje maksimalnim brojem postupaka koji će biti pokrenuti. Nikada nije potrebno za uobičajene aplikacije."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"prisilno zatvaranje pozadinskih aplikacija"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Nositelju omogućuje vezanje uza sučelje najviše razine udaljenog zaslona. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vezanje na uslugu widgeta"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"povezivanje s davateljem usluge usmjeravanja poziva"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Nositelju omogućuje povezivanje s registriranim davateljem usluga usmjeravanja poziva. Nije potrebno za normalne aplikacije."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Nositelju omogućuje slanje namjera administratoru uređaja. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"povezivanje s TV ulazom"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Promjena stanja WiMAX mreže"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Aplikaciji omogućuje povezivanje tabletnog računala s WiMAX mrežama i prekidanje veze tabletnog računala s njima."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Aplikaciji omogućuje povezivanje telefona s WiMAX mrežama i prekidanje veze telefona s njima."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocjenjivanje mreža"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Aplikaciji omogućuje rangiranje mreža i utjecanje na odabir preferiranih mreža na tabletu."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Aplikaciji omogućuje rangiranje mreža i utjecanje na odabir preferiranih mreža na telefonu."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"uparivanje s Bluetooth uređajima"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Aplikaciji omogućuje pregled konfiguracije Bluetootha na tabletnom računalu te uspostavljanje i prihvaćanje veza s uparenim uređajima."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Aplikaciji omogućuje pregled konfiguracije Bluetootha na telefonu te uspostavljanje i prihvaćanje veza s uparenim uređajima."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index aded23b..cc47d26 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Szinkronizálás"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Túl sok <xliff:g id="CONTENT_TYPE">%s</xliff:g> törlés."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"A táblagép tárhelye tele van. Szabadítson fel helyet néhány fájl törlésével."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Az óra tárhelye megtelt. Szabadítson fel helyet néhány fájl törlésével."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"A telefon tárhelye megtelt. Hely felszabadításához töröljön néhány fájlt."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Lehet, hogy a hálózat felügyelt"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ismeretlen harmadik fél által"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Csengő bekapcsolva"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Leállítás..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"A táblagép ki fog kapcsolni."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Az óra ki fog kapcsolni."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"A telefon le fog állni."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Kikapcsolja?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Újraindítás csökkentett módban"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Repülőgép üzemmód"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Repülőgép üzemmód bekapcsolva"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Repülőgép üzemmód kikapcsolva"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Beállítások"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Lehetővé teszi az alkalmazás számára értesítés küldését SMS érkezéséről. A rosszindulatú alkalmazások beérkező SMS-ek hamisítására használhatják fel ezt."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH alapú üzenetek küldése"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Lehetővé teszi az alkalmazás számára értesítés küldését WAP PUSH üzenet érkezése esetén. A rosszindulatú alkalmazások arra használhatják ezt, hogy MMS-kézbesítési jelentést hamisítsanak, vagy hogy a háttérben rosszindulatú variánssal cseréljék le bármelyik weboldal tartalmát."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"hálózatpontozási értesítés küldése"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Lehetővé teszi, hogy az alkalmazás szétküldjön egy értesítést, amely szerint a hálózatokat pontozni kell. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"futó folyamatok számának korlátozása"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Lehetővé teszi az alkalmazás számára a futtatható folyamatok maximális számának vezérlését. Soha nem lehet rá szüksége a normál alkalmazásoknak."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"háttéralkalmazások leállításának kényszerítése"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lehetővé teszi a használó számára, hogy csatlakozzon egy távoli kijelző legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"csatlakozás modulszolgáltatáshoz"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"csatlakozás egy útvonal-szolgáltatóhoz"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Az eszköz kezelője csatlakozhat bármely regisztrált útvonal-szolgáltatóhoz. A normál alkalmazások esetében erre nincs szükség."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lehetővé teszi a tulajdonos számára, hogy célokat küldjön egy eszközkezelőnek. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"csatlakozás tévébemenethez"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-állapot módosítása"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Lehetővé teszi az alkalmazás számára, hogy a táblagépet csatlakoztassa WiMAX-hálózathoz vagy leválassza azt róla."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Lehetővé teszi az alkalmazás számára, hogy a telefont csatlakoztassa WiMAX-hálózathoz vagy leválassza azt róla."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"hálózatok pontozása"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Lehetővé teszi, hogy az alkalmazás rangsorolja a hálózatokat, illetve befolyásolja, hogy a táblagép mely hálózatokat részesítse előnyben."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Lehetővé teszi, hogy az alkalmazás rangsorolja a hálózatokat, illetve befolyásolja, hogy a telefon mely hálózatokat részesítse előnyben."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth-eszközök párosítása"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Lehetővé teszi az alkalmazás számára a táblagépen lévő Bluetooth beállításainak megtekintését, valamint kapcsolatok kezdeményezését és fogadását a párosított eszközökkel."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Lehetővé teszi az alkalmazás számára a telefonon lévő Bluetooth beállításainak megtekintését, valamint kapcsolatok kezdeményezését és fogadását a párosított eszközökkel."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 9edccf8..34bebb2 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռային ռեժիմ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռային ռեժիմը միացված է"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռային ռեժիմը անջատված է"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
@@ -337,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Թույլ է տալիս հավելվածին հաղորդել ծանուցում, որ ստացվել է SMS հաղորդագրություն: Վնասարար հավելվածները կարող են օգտագործել սա` կեղծելու մուտքային SMS հաղորդագրությունները:"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ուղարկել ստացված WAP-PUSH-ի հաղորդում"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Թույլ է տալիս հավելվածին հաղորդել ծանուցում, որ ստացվել է WAP PUSH հաղորդագրություն: Վնասարար հավելվածները կարող են օգտագործել սա` կեղծելու MMS հաղորդագրության ստացումը կամ աննկատ փոխարինելու ցանկացած կայքի բովանդակությունը վնասարար տարբերակներով:"</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ուղարկել ցանցերի գնահատականի հեռարձակում"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ծրագրին թույլ է տալիս հեռարձակել ծանուցում, որ ցանցերը պետք է հաշվարկվեն: Նորմալ ծրագրերում երբեք պետք չի գալիս:"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"սահմանափակել աշխատող գործընթացների թիվը"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Թույլ է տալիս հավելվածին վերահսկել գործընթացների առավելագույն թիվը, որ աշխատելու են: Երբևէ անհրաժեշտ չէ սովորական հավելվածների համար:"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"ստիպել, որ առաջին պլանի հավելվածները փակվեն"</string>
@@ -392,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Թույլ է տալիս սեփականատիրոջը միանալ վիջեթ ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"կապվել երթուղու մատակարարի ծառայությանը"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Թույլ է տալիս տիրոջը կապվել երթուղու մատակարարներից ցանկացածին: Սովորական ծրագրերի համար երբեք անհրաժեշտ չէ:"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"փոխգործակցել սարքի կառավարչի հետ"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Թույլ է տալիս սեփականատիրոջը ուղարկել մտադրություններ սարքի կառավարչին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"միանալ հեռուստացույցի մուտքին"</string>
@@ -642,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Փոխել WiMAX-ի կարգավիճակը"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Թույլ է տալիս հավելվածին գրասալիկը միացնել WiMAX ցանցին և անջատվել այդ ցանցից:"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Թույլ է տալիս հավելվածին հեռախոսը միացնել WiMAX ցանցին և անջատել այդ ցանցից:"</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ցանցերի գնահատական"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ծրագրին թույլ է տալիս դասակարգել ցանցերը և ազդել գրասալիկի նախընտրելի ցանցի ընտրության գործընթացի վրա:"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ծրագրին թույլ է տալիս դասակարգել ցանցերը և ազդել հեռախոսի նախընտրելի ցանցի ընտրության գործընթացի վրա:"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"զուգակցվել Bluetooth սարքերի հետ"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Թույլ է տալիս հավելվածին տեսնել Bluetooth-ի կարգավորումը գրասալիկի վրա և կապվել ու կապեր ընդունել զուգակցված սարքերի հետ:"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Թույլ է տալիս հավելվածին տեսնել Bluetooth-ի կարգավորումը հեռախոսի վրա և կապվել ու կապեր ընդունել զուգակցված սարքերի հետ:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index be0730a..1100bd0 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinkron"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak <xliff:g id="CONTENT_TYPE">%s</xliff:g> penghapusan."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Penyimpanan tablet penuh. Hapus beberapa file untuk mengosongkan ruang."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Penyimpanan arloji penuh. Hapus beberapa file untuk mengosongkan ruang."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Penyimpanan di ponsel penuh. Hapus sebagian file untuk mengosongkan ruang."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Jaringan mungkin dipantau"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Oleh pihak ketiga yang tidak dikenal"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Pendering nyala"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Sedang mematikan..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet Anda akan dimatikan."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Arloji Anda akan dimatikan."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ponsel Anda akan dimatikan."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Anda ingin mematikannya?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reboot ke mode aman"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode pesawat"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mode pesawat AKTIF"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mode pesawat MATI"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Setelan"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Mengizinkan apl menyiarkan pemberitahuan bahwa pesan SMS telah diterima. Apl berbahaya dapat menggunakan ini untuk memalsukan pesan SMS masuk."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"kirim siaran WAP-PUSH-diterima"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Mengizinkan apl menyiarkan pemberitahuan bahwa pesan WAP PUSH telah diterima. Apl berbahaya dapat menggunakan ini untuk memalsukan penerimaan pesan MMS atau diam-diam mengganti konten laman web apa pun dengan varian berbahaya."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"mengirim siaran beri skor jaringan"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Memungkinkan aplikasi menyiarkan pemberitahuan bahwa jaringan perlu diberi skor. Tidak pernah diperlukan untuk aplikasi normal."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"batasi jumlah dari proses yang berjalan"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Mengizinkan apl mengontrol jumlah maksimum proses yang akan berjalan. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"paksa aplikasi latar belakang agar menutup"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Mengizinkan pemegang mengikat ke antarmuka tingkat atas dari layar jarak jauh. Tidak pernah diperlukan untuk aplikasi normal."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"mengikat ke layanan widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"mengikat ke layanan penyedia rute"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Memungkinkan pemegang mengikat ke penyedia rute terdaftar mana pun. Tidak pernah dibutuhkan untuk aplikasi normal."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Mengizinkan pemegang mengirimkan tujuan kepada administrator perangkat. Tidak pernah diperlukan oleh apl normal."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"mengikat ke masukan TV"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Ubah status WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Memungkinkan aplikasi menyambungkan tablet ke dan memutus tablet dari jaringan WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Memungkinkan aplikasi menyambungkan ponsel ke dan memutus ponsel dari jaringan WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"memberi skor jaringan"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Memungkinkan aplikasi menilai jaringan dan memengaruhi jaringan mana yang sebaiknya dipilih tablet."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Memungkinkan aplikasi menilai jaringan dan memengaruhi jaringan mana yang sebaiknya dipilih ponsel."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"sandingkan dengan perangkat Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di tablet, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di ponsel, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 1ef77de..243dd15 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizzazione"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Troppe eliminazioni di <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Spazio di archiviazione del tablet esaurito. Elimina alcuni file per liberare spazio."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"La memoria dell\'orologio è piena. Elimina alcuni file per liberare spazio."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Spazio di archiviazione del telefono esaurito. Elimina alcuni file per liberare spazio."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"La rete potrebbe essere monitorata"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Da una terza parte sconosciuta"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Suoneria attiva"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Spegnimento..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Il tablet verrà spento."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"L\'orologio verrà spento."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Il telefono verrà spento."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Spegnere?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Riavvia in modalità provvisoria"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modalità aereo"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modalità aereo attiva"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modalità aereo non attiva"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Impostazioni"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Consente all\'applicazione di trasmettere una notifica che informa della ricezione di un messaggio SMS. Le applicazioni dannose potrebbero farne uso per creare messaggi SMS in arrivo."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"invio broadcast ricevuti tramite WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Consente all\'applicazione di trasmettere una notifica che informa della ricezione di un messaggio WAP PUSH. Le applicazioni dannose potrebbero farne uso per simulare la ricezione di messaggi MMS o per sostituire di nascosto i contenuti di qualsiasi pagina web con varianti dannose."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"invio trasmissione classificazione reti"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Consente all\'app di trasmettere una notifica indicante che le reti devono essere classificate. Opzione non necessaria per le app normali."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"numero limite di processi in esecuzione"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Consente all\'applicazione di controllare il numero massimo di processi che verranno eseguiti. Mai necessaria per le applicazioni normali."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"chiusura forzata applicazioni di background"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un display remoto. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associazione a un servizio widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"collegamento a un servizio provider di routing"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Consente al titolare di collegarsi a qualsiasi provider di routing registrato. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Consente l\'invio di intent a un amministratore del dispositivo. L\'autorizzazione non dovrebbe mai essere necessaria per le normali applicazioni."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"collegamento a ingresso TV"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Modifica stato WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Consente all\'applicazione di connettere/disconnettere il tablet dalle reti WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Consente all\'applicazione di connettere/disconnettere il telefono dalle reti WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"valutazione reti"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Consente all\'app di stilare una classifica delle reti e determinare quali di queste il tablet deve prediligere."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Consente all\'app di stilare una classifica delle reti e determinare quali di queste il telefono deve prediligere."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"accoppiamento con dispositivi Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Consente all\'applicazione di visualizzare la configurazione del Bluetooth sul tablet e di stabilire e accettare connessioni con dispositivi accoppiati."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Consente all\'applicazione di visualizzare la configurazione del Bluetooth sul telefono e di stabilire e accettare connessioni con dispositivi accoppiati."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f343f4a..537aac6 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"סינכרון"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"יש מחיקות רבות מדי של <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"שטח האחסון של הטאבלט מלא. מחק קבצים כדי לפנות מקום."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"שטח האחסון של השעון מלא. מחק כמה קבצים כדי לפנות שטח."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"שטח האחסון של הטלפון מלא. מחק חלק מהקבצים כדי לפנות שטח."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ייתכן שהרשת מנוטרת"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"על ידי צד שלישי לא מוכר"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"צלצול מופעל"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"מכבה..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"הטאבלט שלך יכבה."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"השעון יכבה."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"הטלפון שלך יכובה."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"האם ברצונך לבצע כיבוי?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"אתחל למצב בטוח"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"מצב טיסה"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"מצב טיסה מופעל"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"מצב טיסה כבוי"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"הגדרות"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
<string name="android_system_label" msgid="6577375335728551336">"מערכת Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"מאפשר לאפליקציה לשדר התראה על כך שהתקבלה הודעת SMS. אפליקציות זדוניות עלולות להשתמש בכך כדי לזייף הודעות SMS נכנסות."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"שלח שידור שהתקבל באמצעות WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"מאפשר לאפליקציה לשדר התראה על כך שהתקבלה הודעה מסוג WAP PUSH. אפליקציות זדוניות עלולות להשתמש בכך כדי לזייף קבלה של הודעות MMS או כדי להחליף בחשאי את התוכן של דף אינטרנט כלשהו בגירסאות זדוניות."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"שלח שידור לדירוג רשתות"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"מאפשר לאפליקציה לשדר התראה על כדי שיש לדרג את הרשתות. לא בשימוש עבור אפליקציות רגילות."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"הגבל את מספר התהליכים הפועלים"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"מאפשר לאפליקציה לשלוט על המספר המרבי של תהליכים שיפעלו. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"אילוץ סגירה של אפליקציות ברקע"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של צג רחוק. לעולם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"הכפפה לשירות Widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"איגוד לשירות של ספק ניתוב"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"מאפשרת לבעלים לאגד לספקי ניתוב רשומים. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"מאפשר למשתמש לשלוח כוונות למנהל התקנים. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"איגוד לקלט טלוויזיה"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"שנה את מצב WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"מאפשר לאפליקציה לחבר את הטאבלט לרשתות WiMAX ולהתנתק מהן."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"מאפשר לאפליקציה לחבר את הטלפון לרשתות WiMAX ולהתנתק מהן."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"דרג רשתות"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"מאפשר ליישום לדרג רשתות ולהשפיע על הרשתות שאותן הטאבלט יעדיף."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"מאפשר ליישום לדרג רשתות ולהשפיע על הרשתות שאותן הטלפון יעדיף."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"התאמה למכשירי Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"מאפשר לאפליקציה להציג את תצורת ה-Bluetooth בטאבלט, וכן ליצור ולקבל חיבורים עם מכשירים מותאמים."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"מאפשר לאפליקציה להציג את תצורת ה-Bluetooth בטלפון, וכן ליצור ולקבל חיבורים עם מכשירים מותאמים."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 501fb81..e334773 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同期"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>での削除が多すぎます。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"タブレットのストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"ウォッチのストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"端末のストレージに空き領域がありません。ファイルを削除して空き領域を確保してください。"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ネットワークが監視される場合があります"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"不明な第三者"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"着信音オン"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"シャットダウン中..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"タブレットの電源をOFFにします。"</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"ウォッチの電源をOFFにします。"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"携帯電話の電源を切ります。"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"シャットダウンしますか?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"再起動してセーフモードに変更"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"機内モード"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
<string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"SMSメッセージの受信通知の配信をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、受信SMSメッセージが偽造される恐れがあります。"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH受信ブロードキャストの送信"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"WAP PUSHメッセージの受信通知を配信することをアプリに許可します。この許可を悪意のあるアプリに利用されると、MMSメッセージの受信確認が偽造されたりウェブページのコンテンツが悪意のあるコンテンツに密かに置き換えられたりする恐れがあります。"</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ネットワークスコアのブロードキャスト送信"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ネットワークのスコアリングが必要であるという通知をブロードキャスト送信することをアプリに許可します。通常のアプリでは不要です。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"実行中のプロセスの数を制限"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"実行するプロセスの上限数を制御することをアプリに許可します。通常のアプリでは不要です。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"バックグラウンドのアプリの強制終了"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"リモートディスプレイのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ウィジェットサービスにバインド"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ルートプロバイダサービスへのバインド"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"登録済みのルートプロバイダにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"デバイス管理者へのintentの送信を所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"テレビの入力へのバインド"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX状態の変更"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"タブレットのWiMAXネットワークへの接続と切断をアプリに許可します。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"携帯端末のWiMAXネットワークへの接続と切断をアプリに許可します。"</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ネットワークスコア"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ネットワークを順位付けし、タブレットでのネットワークの優先順位に反映することをアプリに許可します。"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ネットワークを順位付けし、携帯電話でのネットワークの優先順位に反映することをアプリに許可します。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetoothデバイスのペアの設定"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"タブレットのBluetooth設定を表示すること、ペアの端末に接続すること/ペアの端末からの接続を受け入れることをアプリに許可します。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"携帯端末のBluetooth設定を表示すること、ペアの端末に接続すること/ペアの端末からの接続を受け入れることをアプリに許可します。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 5f7fa89..b6856c6 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"სინქრონიზაცია"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g>-ის ძალიან ბევრი წაშლილები."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ტაბლეტის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"საათის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ტელეფონის მეხსიერება გავსებულია. ადგილის გასათავისუფლებლად წაშალეთ ფაილების ნაწილი."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"შესაძლოა ქსელი მონიტორინგის ქვეშ იმყოფება"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"უცნობი მესამე მხარის მიერ"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"ზარი ჩართულია"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"გამორთვა…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"თქვენი ტაბლეტი გაითიშება."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"თქვენი საათი გაითიშება."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"თქვენი ტელეფონი გაითიშება."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"გსურთ გამორთვა?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"უსაფრთხო რეჟიმის ჩატვირთვა"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"თვითმფრინავის რეჟიმი"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"თვითმფრინავის რეჟიმი ჩართულია."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"თვითმფრინავის რეჟიმი გამორთულია."</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"აპს საშუალებას აძლევს გააგზავნოს შეტყობინება SMS შეტყობინების მიღების თაობაზე. მავნე აპლიკაციებში ეს ფუნქცია შეიძლება გამოყენებული იქნას SMS შეტყობინებების მიღების იმიტაციიისათვის."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-ით მიღებული სამაუწყებლო შეტყობინების გაგზავნა"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"აპს შეეძლება, გაგზავნოს შეტყობინება WAP PUSH შეტყობინების მიღების თაობაზე. მავნე აპებმა ეს შეიძლება გამოიყენონ MMS შეტყობინების მიღების გასაყალბებლად ან ნებისმიერი ვებგვერდის კონტენტის სახიფათო ვარიანტებით ჩუმად ჩასანაცვლებლად."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ქსელის შეფასებების მაუწყებლობის გაგზავნა"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"აპს ნებას რთავს გადასცეს შეტყობინება, რომ ქსელები შეფასებას საჭიროებს. ჩვეულებრივ აპებს ეს არასოდეს ჭირდება."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"მიმდინარე პროცესების რაოდენობის ლიმიტი"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"აპს შეეძლება, გააკონტროლოს მიმდინარე პროცესების მაქსიმალური რაოდენობა. ჩვეულებრივ აპებში არასდროს არის საჭირო."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"უკანა ფონის აპის იძულებით დახურვა"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"აპს შეეძლება ზედა დონის ინტერფეისის ვიჯეტთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"მარშრუტის სერვისის პროვაიდერთან შეკავშირება"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"საშუალებას აძლევს მფლობელს შეკავშირდეს მარშრუტების ნებისმიერ პროვაიდერთან. ჩვეულებრივ აპებს უმეტეს შემთხვევაში არ დაჭირდება."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"მოწყობილობის ადმინთან ინტერაქცია"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"აპს შეეძლება მოწყობილობის ადმინისტრატორისთვის intent ობიექტების გაგზავნა. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"TV შეყვანასთან მიბმა"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX მდგომარეობის შეცვლა"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"აპს შეეძლება, დაუკავშიროს და გამოაერთოს ტაბლეტი WiMAX ქსელებიდან."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"აპს შეეძლება, დაუკავშიროს და გამოაერთოს ტელეფონი WiMAX ქსელებიდან."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ქსელების შეფასება"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"აპს ნებას რთავს შეაფასოს ქსელები და იქონიოს ზეგავლენა, თუ რომელი ქსელი ამჯობინოს ტაბლეტმა."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"აპს ნებას რთავს შეაფასოს ქსელები და იქონიოს ზეგავლენა, თუ რომელი ქსელი ამჯობინოს ტელეფონმა."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth მოწყობილობებთან დაწყვილება"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"აპს შეეძლება, ნახოს Bluetooth-ის კონფიგურაცია ტაბლეტზე, შექმნას და მიიღოს კავშირები დაწყვილებულ მოწყობილობებთან."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"აპს შეეძლება, ნახოს Bluetooth-ის კონფიგურაცია ტელეფონზე და შექმნას და მიიღოს კავშირები დაწყვილებულ მოწყობილობებთან."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 45389f7..bac95d577 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ធ្វើសមកាលកម្ម"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"មានការលុប <xliff:g id="CONTENT_TYPE">%s</xliff:g> ច្រើនពេក។"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ឧបករណ៍ផ្ទុកនៃកុំព្យូទ័របន្ទះពេញ។ លុបឯកសារមួយចំនួន។"</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"ឧបករណ៍របស់នាឡិកាពេញ។ លុបឯកសារមួយចំនួន។"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ឧបករណ៍ផ្ទុកទូរស័ព្ទពេញ! លុបឯកសារមួយចំនួនដើម្បីបង្កើនទំហំ។"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"បណ្ដាញអាចត្រូវបានតាមដាន"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ដោយភាគីទីបីដែលមិនស្គាល់"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"បើកកម្មវិធីរោទ៍"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"កំពុងបិទ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"កុំព្យូទ័របន្ទះរបស់អ្នកនឹងបិទ។"</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"នាឡិការបស់អ្នកនឹងបិទ។"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"ទូរស័ព្ទរបស់អ្នកនឹងបិទ។"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"តើអ្នកចង់បិទ?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"ចាប់ផ្ដើមឡើងវិញដើម្បីចូលរបៀបសុវត្ថិភាព"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ពេលជិះយន្តហោះ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"បានបើករបៀបពេលជិះយន្តហោះ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"បានបិទរបៀបពេលជិះយន្តហោះ"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"ការកំណត់"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
<string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ឲ្យកម្មវិធីប្រកាសការជូនដំណឹងការទទួលសារ SMS ។ កម្មវិធីព្យាបាទអាចប្រើវាដើម្បីបន្លំសារ SMS ចូល។"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ផ្ញើការប្រកាសបានទទួល WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ឲ្យកម្មវិធីប្រកាសការជូនដំណឹងថាបានទទួលសារ WAP PUSH ។ កម្មវិធីព្យាបាទអាចប្រើវាដើម្បីក្លែងបង្កាន់ដៃសារ MMS ឬជំនួសមាតិកាទំព័របណ្ដាញណាមួយស្ងាត់ៗដោយអ្វីដែលក្លែងក្លាយ។"</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ផ្ញើពិន្ទុការប្រកាសបណ្ដាញ"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ឲ្យកម្មវិធីប្រកាសការជូនដំណឹងដែលបណ្ដាញតម្រូវឲ្យដាក់ពិន្ទុ។ មិនចាំបាច់សម្រាប់កម្មវិធីធម្មតា។"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"កំណត់ចំនួនដំណើរការដែលកំពុងដំណើរការ"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ឲ្យកម្មវិធីពិនិត្យចំនួនដំណើរការអតិបរមាដែលនឹងដំណើរការ។ មិនចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"បង្ខំឲ្យបិទកម្មវិធីក្នុងផ្ទៃខាងក្រោយ"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលនៃការបង្ហាញពីចម្ងាយ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចងសេវាកម្មធាតុក្រាហ្វិក"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មធាតុក្រាហ្វិក។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ភ្ជាប់ទៅសេវាកម្មក្រុមហ៊ុនផ្ដល់ច្រក"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅក្រុមហ៊ុនផ្ដល់ច្រកដែលបានចុះឈ្មោះ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ទាក់ទងជាមួយអ្នកគ្រប់គ្រងឧបករណ៍"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ឲ្យម្ចាស់ផ្ញើគោលបំណងទៅអ្នកគ្រប់គ្រងឧបករណ៍។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ភ្ជាប់ទៅការបញ្ចូលទូរទស្សន៍"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"ប្ដូរស្ថានភាព WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"ឲ្យកម្មវិធីតភ្ជាប់ និងផ្ដាច់កុំព្យូទ័របន្ទះពីបណ្ដាញ WiMAX ។"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"ឲ្យកម្មវិធីភ្ជាប់ទូរស័ព្ទ និងផ្ដាច់ពីបណ្ដាញ WiMAX ។"</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ដាក់ពិន្ទុបណ្ដាញ"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ឲ្យកម្មវិធីចាត់ថ្នាក់បណ្ដាញ និងមានឥទ្ធិពលលើបណ្ដាញណាមួយដែលកុំព្យូទ័របន្ទះប្រើ។"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ឲ្យកម្មវិធីចាត់ថ្នាក់បណ្ដាញ និងមានឥទ្ធិពលលើបណ្ដាញណាមួយដែលទូរស័ព្ទគួរប្រើ។"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ផ្គូផ្គងជាមួយឧបករណ៍ប៊្លូធូស"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"ឲ្យកម្មវិធីមើលការកំណត់រចនាសម្ព័ន្ធប៊្លូធូសលើកុំព្យូទ័របន្ទះ ព្រមទាំងធ្វើការតភ្ជាប់ និងទទួលជាមួយឧបករណ៍បានផ្គូផ្គង។"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ឲ្យកម្មវិធីមើលការកំណត់រចនាសម្ព័ន្ធប៊្លូធូសក្នុងទូរស័ព្ទ ដើម្បីទទួល និងតភ្ជាប់ជាមួយឧបករណ៍បានផ្គូផ្គង។"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5b2747f..7b064a3 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"동기화"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> 삭제가 너무 많습니다."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"태블릿 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"시계 저장공간이 가득 찼습니다. 일부 파일을 삭제하여 저장 여유 공간을 늘리세요."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"휴대전화 저장공간이 꽉 찼습니다. 일부 파일을 삭제하여 저장공간을 늘리세요."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"네트워크가 모니터링될 수 있음"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"알 수 없는 제3자의 모니터링"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"벨소리가 켜져 있습니다."</string>
<string name="shutdown_progress" msgid="2281079257329981203">"종료 중..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"태블릿이 종료됩니다."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"시계가 종료됩니다."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"휴대전화가 종료됩니다."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"종료하시겠습니까?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"안전 모드로 다시 부팅"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"비행기 모드"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"비행기 모드 사용중"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"비행기 모드 사용중이 아님"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"앱이 SMS 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 허용합니다. 이 경우 악성 앱이 수신된 SMS 메시지를 위조할 수 있습니다."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-수신 브로드캐스트 보내기"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"앱이 WAP PUSH 메시지를 받았다는 알림을 브로드캐스트할 수 있도록 허용합니다. 이 경우 악성 앱이 MMS 메시지를 받은 것처럼 위장하거나 웹페이지의 콘텐츠를 악성 콘텐츠로 몰래 바꿀 수 있습니다."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"네트워크 점수화 브로드캐스트 전송"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"네트워크를 점수화할 필요가 있다는 알림을 앱이 브로드캐스트할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"실행 중인 프로세스 수 제한"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"앱이 실행할 최대 프로세스 수를 제어할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"백그라운드 앱 강제 종료"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"권한을 가진 프로그램이 원격 디스플레이에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"위젯 서비스와 연결"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"경로 제공업체 서비스 사용"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"권한을 가진 프로그램이 등록된 경로 제공업체를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"권한을 가진 프로그램이 기기 관리자에게 인텐트를 보낼 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"TV 입력 사용"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX 상태 변경"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"앱이 태블릿을 WiMAX 네트워크에 연결하거나 연결을 끊을 수 있도록 허용합니다."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"앱이 휴대전화를 WiMAX 네트워크에 연결하거나 연결을 끊을 수 있도록 허용합니다."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"네트워크 점수화"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"앱이 네트워크 순위를 정하고 태블릿에서 어떤 네트워크를 선호할지 영향을 주도록 허용합니다."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"앱이 네트워크 순위를 정하고 휴대전화에서 어떤 네트워크를 선호할지 영향을 주도록 허용합니다."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"블루투스 기기와 페어링"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"앱이 태블릿의 블루투스 설정을 확인하고 페어링된 기기에 연결하며 연결을 수락할 수 있도록 허용합니다."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"앱이 휴대전화의 블루투스 설정을 확인하고 페어링된 기기에 연결하며 연결을 수락할 수 있도록 허용합니다."</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index efe3354..d486092 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -173,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ໂໝດໃນຍົນ"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ເປີດໂໝດຢູ່ໃນຍົນແລ້ວ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ປິດໂໝດໃນຍົນແລ້ວ"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
@@ -337,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"ອະນຸຍາດໃຫ້ແອັບຯ ກະຈາຍສັນຍານການແຈ້ງເຕືອນວ່າຂໍ້ຄວາມ SMS ໄດ້ຮັບແລ້ວ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດຈະໃຊ້ສິ່ງນີ້ໃນການປອມແປງຂໍ້ຄວາມ SMS ຂາເຂົ້າ."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ສົ່ງການກະຈາຍ WAP-PUSH ທີ່ໄດ້ຮັບ"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"ອະນຸຍາດໃຫ້ແອັບຯສົ່ງການແຈ້ງເຕືອນໃນເວລາທີ່ໄດ້ຮັບຂໍ້ມຄວາມ WAP PUSH. ແອັບຯທີ່ເປັນອັນຕະລາຍ ອາດໃຊ້ການກະທຳນີ້ເພື່ອປອມການໄດ້ຮັບຂໍ້ຄວາມ MMS ຫຼືລັກປ່ຽນເນື້ອຫາຂອງໜ້າເວັບຕ່າງໆ ດ້ວຍສິ່ງອັນຕະລາຍທັງຫຼາຍຢ່າງງຽບໆ."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ສົ່ງການກະຈາຍຄະແນນເຄືອຂ່າຍ"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"ອະນຸຍາດໃຫ້ແອັບຯກະຈາຍການແຈ້ງເຕືອນທີ່ເຄືອຂ່າຍຕ່າງໆຈຳເປັນຖືກໃຊ້ນັບຄະແນນ. ບໍ່ມີຄວາມຈຳເປັນໃນແອັບຯທົ່ວໄປ."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ຈຳກັດຈຳນວນຂອງໂປຣເຊສທີ່ເຮັດວຽກຢູ່"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມຈຳນວນສູງສຸດ ຂອງໂປຣເຊສທີ່ຈະເຮັດວຽກ. ບໍ່ຄວນຖືກໃຊ້ກັບແອັບພລິເຄຊັນທົ່ວໄປ."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"ບັງຄັບໃຫ້ແອັບຯທີ່ເຮັດວຽກຢູ່ພື້ນຫຼັງປິດໂຕລົງ"</string>
@@ -392,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງການສະແດງຜົນທາງໄກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ເຊື່ອມໂຍງໄປຫາບໍລິການວິດເຈັດ"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບອິນເຕີເຟດລະດັບສູງສຸດ ຂອງບໍລິການວິເຈັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"ເຊື່ອມໂຍງກັບການບໍລິການຂອງຜູ່ໃຫ້ບໍລິການເສັ້ນທາງ"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສາມາດເຊື່ອມໂຍງກັບທຸກໆຜູ່ໃຫ້ບໍລິການເສັ້ນທາງທີ່ລົງທະບຽນ. ບໍ່ຄວນຈະໄດ້ໃຊ້ໃນແອັບຯທົ່ວໄປ."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ຕິດຕໍ່ກັບຜູ່ເບິ່ງແຍງອຸປະກອນ"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສົ່ງເຈດຕະນາຫາຜູ່ເບິ່ງແຍງລະບົບອຸປະກອນ. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ຜູກກັບການປ້ອນຂໍ້ມູນເຂົ້າໂທລະທັດ"</string>
@@ -642,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"ປ່ຽນສະຖານະ WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"ອະນຸຍາດໃຫ້ແອັບຯເຊື່ອມຕໍ່ ແລະຕັດການເຊື່ອມຕໍ່ແທັບເລັດຈາກເຄືອຂ່າຍ WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"ອະນຸຍາດໃຫ້ແອັບຯເຊື່ອມຕໍ່ ແລະຕັດການເຊື່ອມຕໍ່ຂອງໂທລະສັບຈາກເຄືອຂ່າຍ WiMax ໄດ້."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ຄະແນນເຄືອຂ່າຍ"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"ອະນຸຍາດໃຫ້ແອັບຯຈັດລຳດັບເຄືອຂ່າຍ ແລະ ຊ່ວຍຕັດສິນໃຈວ່າເຄືອຂ່າຍໃດທີ່ແທັບເລັດຄວນນຳໃຊ້."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"ອະນຸຍາດໃຫ້ແອັບຯຈັດລຳດັບເຄືອຂ່າຍ ແລະ ຊ່ວຍຕັດສິນໃຈວ່າເຄືອຂ່າຍໃດທີ່ໂທລະສັບຄວນນຳໃຊ້."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ຈັບຄູ່ກັບອຸປະກອນ Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"ອະນຸຍາດໃຫ້ແອັບຯເບິ່ງການຕັ້ງຄ່າຂອງ Bluetooth ໃນແທັບເລັດ ຕະຫຼອດຈົນເຊື່ອມຕໍ່ ແລະຍອມຮັບການເຊື່ອມຕໍ່ກັບອຸປະກອນທີ່ຈັບຄູ່ກັນແລ້ວ."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"ອະນຸຍາດໃຫ້ແອັບຯເບິ່ງການຕັ້ງຄ່າຂອງ Bluetooth ໃນໂທລະສັບ, ຮວມທັງໃຫ້ສ້າງ ແລະຮັບການເຊື່ອມຕໍ່ຈາກອຸປະກອນທີ່ຈັບຄູ່ກັນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 2828dc2..c8724a3 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinchronizuoti"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Per daug <xliff:g id="CONTENT_TYPE">%s</xliff:g> trynimo."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetinio kompiuterio atmintis pilna. Kad atlaisvintumėte vietos, ištrinkite kelis failus."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Laikrodžio saugykla pilna. Ištrinkite kelis failus, kad atlaisvintumėte vietos."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefono atmintis pilna. Ištrinkite kai kuriuos failus, kad atlaisvintumėte vietos."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Tinklas gali būti stebimas"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nežinoma trečioji šalis"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Skambutis įjungtas"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Išsijungia..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Planšetinio kompiuterio veikimas bus sustabdytas."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Laikrodis išsijungs."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonas bus išjungtas."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Ar norite išjungti?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Iš naujo įkelti operacinę sistemą saugos režimu"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lėktuvo režimas"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ĮJUNGTAS lėktuvo režimas"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"lėktuvo režimas IŠJUNGTAS"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Nustatymai"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
<string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Leidžiama programai pateikti pranešimą, kad buvo gautas SMS pranešimas. Kenkėjiškos programos gali tai naudoti, kad klastotų gaunamuosius SMS pranešimus."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"siųsti „WAP-PUSH-received“ perdavimą"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Leidžiama programai pateikti pranešimą, kai gaunamas WAP PUSH pranešimas. Kenkėjiškos programos gali tai naudoti, kad klastotų MMS pranešimo gavimą ar kad nepastebimai pakeistų bet kurio tinklalapio turinį kenkėjiškais variantais."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"siųsti tinklų transliavimo įvertinimą"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Programai leidžiama transliuoti pranešimą, kad reikia įvertinti tinklus. Niekada nereikia įprastoms programoms."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"riboti vykdomų procesų skaičių"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Leidžiama programai valdyti didžiausią vykdomų procesų skaičių. Nereikalinga įprastoms programoms."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"priverstinai uždaryti fonines programas"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Leidžiama savininkui susisaistyti su aukščiausiojo lygio nuotolinio ekrano sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"susaistyti su valdiklio paslauga"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"susisaistyti su maršruto parinkimo paslauga"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Savininkui leidžiama susisaistyti su bet kokiomis registruotomis maršrutų parinkimo paslaugomis. To niekada neturėtų prireikti naudojant įprastas programas."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Leidžiama savininkui siųsti tikslus įrenginio administratoriui. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"susisaistyti su TV įvestimi"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Keisti „WiMAX“ būseną"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Leidžia programai prijungti planšetinį kompiuterį prie „WiMAX“ ryšio tinklų ir nuo jų atjungti."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Leidžia programai prijungti telefoną prie „WiMAX“ ryšio tinklų ir nuo jų atjungti."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"įvertinti tinklus"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Programai leidžiama įvertinti tinklus ir nustatyti, kuriems tinklams planšetiniame kompiuteryje turėtų būti taikoma pirmenybė."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Programai leidžiama įvertinti tinklus ir nustatyti, kuriems tinklams telefone turėtų būti taikoma pirmenybė."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"susieti su „Bluetooth“ įrenginiais"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Leidžiama programai peržiūrėti „Bluetooth“ konfigūraciją planšetiniame kompiuteryje ir užmegzti bei priimti ryšius iš susietų įrenginių."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Leidžiama programai peržiūrėti „Bluetooth“ konfigūraciją telefone ir užmegzti bei priimti ryšius iš susietų įrenginių."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index c51cf90..f2aec67 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizācija"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Pārāk daudz <xliff:g id="CONTENT_TYPE">%s</xliff:g> dzēsto vienumu."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Planšetdatora atmiņa ir pilna. Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Pulksteņa atmiņa ir pilna. Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Tālruņa atmiņa ir pilna! Dzēsiet dažus failus, lai atbrīvotu vietu."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Iespējams, tīklā veiktās darbības tiek pārraudzītas."</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Nezināma trešā puse"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Zvanītājs ieslēgts"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Notiek izslēgšana..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Planšetdators tiks beidzēts."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Pulkstenis tiks izslēgts."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tālrunis tiks izslēgts."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vai vēlaties izslēgt?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Atsāknēšana drošajā režīmā"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lidojuma režīms"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lidojuma režīms ir IESLĒGTS."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lidojuma režīms ir IZSLĒGTS."</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Iestatījumi"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
<string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ļauj lietotnei pārraidīt paziņojumu par saņemtu īsziņu. Ļaunprātīgas lietotnes to var izmantot, lai viltotu ienākošas īsziņas."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"sūtīt WAP-PUSH-saņemto apraidi"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ļauj lietotnei pārraidīt paziņojumu par to, ka ir saņemts WAP PUSH ziņojums. Ļaunprātīgas lietotnes to var izmantot, lai viltotu multiziņas saņemšanu vai jebkuras tīmekļa lapas saturu nemanāmi nomainītu ar ļaunprātīgiem variantiem."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"apraidīt ziņojumu par tīklu vērtēšanu"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ļauj lietotnei apraidīt paziņojumu, ka tīkli ir jānovērtē. Parastām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ierobežot aktīvo procesu skaitu"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ļauj lietotnei kontrolēt izpildāmo procesu maksimālo skaitu. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"veikt fonā darbojošos lietotņu piespiedu aizvēršanu"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ļauj īpašniekam izveidot saiti ar attāla displeja augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"saistīt ar logrīka pakalpojumu"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Saistīšana ar maršruta nodrošinātāja pakalpojumu"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ļauj īpašniekam saistīt jebkādus reģistrētus maršrutēšanas nodrošinātājus. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ļauj īpašniekam nosūtīt informāciju par nodomiem ierīces administratoram. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"Izveidot saiti ar TV ieeju"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX statusa mainīšana"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ļauj lietotnei izveidot un pārtraukt planšetdatora savienojumu ar WiMAX tīkliem."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ļauj lietotnei izveidot un pārtraukt tālruņa savienojumu ar WiMAX tīkliem."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"vērtēt tīklus"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ļauj lietotnei ranžēt tīklus un ietekmēt to, kuriem tīkliem planšetdators dos priekšroku."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ļauj lietotnei ranžēt tīklus un ietekmēt to, kuriem tīkliem tālrunis dos priekšroku."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"savienot pārī ar Bluetooth ierīcēm"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ļauj lietotnei skatīt Bluetooth konfigurāciju planšetdatorā, kā arī veidot un pieņemt savienojumus ar pārī savienotām ierīcēm."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ļauj lietotnei skatīt Bluetooth konfigurāciju tālrunī, kā arī veidot un pieņemt savienojumus ar pārī savienotām ierīcēm."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index c8c8fac..1006907f 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синк"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Хэт олон <xliff:g id="CONTENT_TYPE">%s</xliff:g> устгах."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Таблетийн сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Цагны сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Утасны сан дүүрсэн. Зай чөлөөлөх бол зарим файлыг устгана уу."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сүлжээ хянагдаж байж болзошгүй"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Тодорхойгүй гуравдагч талаас"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Хонх ассан"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Унтрааж байна…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таны таблет унтрах болно."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Таны цаг унтрах болно."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Таны утас унтрах болно."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Та унтраах уу?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Аюулгүй горимоор дахин асаах"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Нислэгийн горим"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Нислэгийн горим асав"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Нислэгийн горим унтарсан"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Тохиргоо"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Апп нь SMS мессеж хүлээн авсан талаарх мэдэгдлийг өргөн дамжуулах боломжтой. Хортой апп энийг ашиглан ирсэн SMS мессежийг хуурамчаар хийх боломжтой."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH-хүлээн авав өргөн дамжууллыг илгээх"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Аппликешн нь WAP PUSH мессеж хүлээж авсан мэдэгдлийг өргөн дамжуулах боломжтой. Хортой апп нь энийг ашиглан MMS мессеж хүлээн авсан гэж хуурамчаар мэдэгдэх эсвэл хортой хувьсагч агуулсан веб хуудасны контентыг чимээгүй орлуулах боломжтой."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"бүртгэгдсэн сүлжээнүүд рүү түгээх"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Апп-д сүлжээнүүдэд бүртгэгдсэн байх шаардлагатай мэдэгдлийг түгээх боломжийг олгоно. Энгийн апп-д хэзээ ч шаардагдахгүй."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ажиллаж байгаа процессийн тоог хязгаарлах"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Апп нь нэг зэрэг ажиллах процессийн тооны дээд утгыг удирдах боломжтой. Энгийн апп-д хэзээ ч ашиглагдахгүй."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"арын апп-г хүчээр хаах"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Эзэмшигчид алсын дэлгэц дэх дээд давхаргын интерфэйстэй холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет үйлчилгээтэй холбох"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Эзэмшигч нь виджет үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"маршрут нийлүүлэгчийн үйлчилгээтэй холбогдох"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Эзэмшигчид бүртгэгдсэн маршрут нийлүүлэгчтэй холбогдох боломж олгоно. Энгийн апп-уудад хэзээ ч шаардагдахгүй."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"төхөөрөмжийн админтай харилцан үйлчлэх"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Эзэмшигч нь төхөөрөмжийн админруу интент илгээх боломжтой. Энгийн апп-д шаардлагагүй."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ТВ оролт холбох"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX статусыг өөрчлөх"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Апп нь WiMAX сүлжээнд таблетыг холбох болон салгах боломжтой."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Апп нь WiMAX сүлжээнд утсыг холбох болон салгах боломжтой."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"бүртгэгдсэн сүлжээ"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Апп-д сүлжээнүүдийг эрэмбэлж, аль сүлжээнд таблетыг холбоход нөлөөлөх боломж олгоно."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Апп-д сүлжээнүүдийг эрэмбэлж, аль сүлжээнд утсыг холбоход нөлөөлөх боломж олгоно."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Блютүүт төхөөрөмжтэй хос үүсгэх"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Апп нь таблет дээрх блютүүт тохиргоог харах боломжтой ба хос болох төхөөрөмжтэй холболтыг зөвшөөрөх болон хийх боломжтой."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Апп нь утсан дээрх Блютүүт тохиргоог харах боломжтой ба хос болох төхөөрөмжтэй холболтыг зөвшөөрөх болон хийх боломжтой."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 0e15840..d3b5987 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Penyegerakan"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Terlalu banyak pemadaman <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Storan tablet penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Storan tontonan penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Storan telefon penuh. Padamkan beberapa fail untuk mengosongkan ruang."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rangkaian mungkin dipantau"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Oleh pihak ketiga yang tidak diketahui"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Pendering dihidupkan"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Mematikan..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet anda akan dimatikan."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Tontonan anda akan dimatikan."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon anda akan dimatikan."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Adakah anda mahu menutup?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"But semula ke mod selamat"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod pesawat"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mod Pesawat DIHIDUPKAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mod Pesawat DIMATIKAN"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Membenarkan apl untuk menyiarkan pemberitahuan bahawa mesej SMS telah diterima. Apl hasad boleh menggunakannya untuk memalsukan mesej SMS masuk."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"hantar siaran WAP-TOLAK-diterima"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Membenarkan apl untuk menyiarkan pemberitahuan bahawa mesej WAP PUSH telah diterima. Apl hasad boleh menggunakannya untuk memalsukan penerimaan mesej MMS atau secara diam-diam menggantikan kandungan mana-mana laman web dengan varian hasad."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"hantar siaran markah rangkaian"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Membenarkan apl menyiarkan pemberitahuan bahawa rangkaian perlu diberi markah. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"hadkan bilangan proses yang dijalankan"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Membenarkan apl untuk mengawal bilangan maksimum proses yang akan berlangsung. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"memaksa apl latar belakang untuk menutup"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"terikat kepada perkhidmatan pembekal laluan"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Membenarkan pemegang untuk terikat kepada mana-mana pembekal laluan yang berdaftar. Tidak sekali-kali diperlukan untuk apl normal."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Membenarkan pemegang menghantar tujuan kepada pentadbir peranti. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"ikat kepada input TV"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Tukar keadaan WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Membenarkan apl untuk menyambungkan tablet ke dan menyahsambungkan tablet dari rangkaian WiMaX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Membenarkan apl untuk menyambungkan telefon ke dan menyahsambung telefon dari rangkaian WiMaX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"beri markah kepada rangkaian"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Membenarkan apl menilai rangkaian dan mempengaruhi rangkaian yang harus dipilih oleh tablet."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Membenarkan apl menilai rangkaian dan mempengaruhi rangkaian yang harus dipilih oleh telefon."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"berpasangan dengan peranti Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Membenarkan apl melihat konfigurasi Bluetooth pada tablet dan untuk membuat serta menerima sambungan dengan peranti yang dipasangkan."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Membenarkan apl melihat konfigurasi Bluetooth pada telefon dan membuat serta menerima sambungan dengan peranti yang dipasangkan."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 781f7d1..d95d6f1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisering"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"For mange slettinger av <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Nettbrettlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Klokkens lagringsplass er full. Slett filer for å frigjøre plass."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonlageret er fullt. Slett noen filer for å frigjøre lagringsplass."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nettverket blir muligens overvåket"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en ukjent tredjepart"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringelyd på"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Avslutter…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Nettbrettet slås av."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Klokken slås av."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonen kommer til å slås av."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slå av?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Start på nytt i sikker modus"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flymodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flymodus er på"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flymodus er av"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Lar appen kringkaste et varsel om at en SMS-melding er mottatt. Ondsinnede apper kan bruke dette til å forfalske innkommende SMS-meldinger."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"kringkaste melding om mottatt WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Lar appen kringkaste et varsel om at en WAP-PUSH-melding er mottatt. Ondsinnede apper kan bruke dette til å forfalske MMS-meldingskvitteringer, eller ubemerket erstatte innholdet av alle slags nettsider med ondsinnede varianter."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"sende kringkasting om nettverksvurdering"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Gir appen tillatelse til å kringkaste et varsel om at nettverk må vurderes. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"begrense antallet kjørende prosesser"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Lar appen kontrollere det maksimale antallet prosesser som kjører. Aldri nødvendig for vanlige apper."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinge bakgrunnsapper til å lukkes"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lar innehaveren binde seg til det øverste grensesnittnivået for ekstern skjerm. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"binde til modultjenste"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"binde seg til en ruteleverandørtjeneste"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Innehaveren av tillatelsen kan binde seg til ruteleverandører. Dette er ikke nødvendig for vanlige apper."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunisere med enhetsadministrator"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lar innehaveren sende hensikter til en enhetsadministrator. Skal aldri være nødvendig for normale apper."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"binde applikasjonen til en TV-inngang"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Endre WiMAX-status"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Lar appen koble nettbrettet til og fra WiMAX-nettverk."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Lar appen koble telefonen til og fra WiMAX-nettverk."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"vurdere nettverk"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Gir appen tillatelse til å rangere nettverk, og påvirke hvilket nettverk nettbrettet skal foretrekke."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Gir appen tillatelse til å rangere nettverk, og påvirke hvilket nettverk telefonen skal foretrekke."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"koble til Bluetooth-enheter"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Lar appen se Bluetooth-konfigurasjonen på nettbrettet, samt opprette og godta tilkoblinger med sammenkoblede enheter."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Lar appen se Bluetooth-konfigurasjonen på telefonen, samt opprette og godta tilkoblinger med sammenkoblede enheter."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index c45f65d..c629254 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchroniseren"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Te veel verwijderen voor <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletgeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Horlogegeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefoongeheugen is vol. Verwijder enkele bestanden om ruimte vrij te maken."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Netwerk kan worden gecontroleerd"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Door een onbekende derde partij"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Belsoftware aan"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Uitschakelen..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Uw tablet wordt uitgeschakeld."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Uw horloge wordt uitgeschakeld."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Uw telefoon wordt uitgeschakeld."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Wilt u afsluiten?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Opnieuw opstarten in veilige modus"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Vliegmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Vliegmodus is AAN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Vliegmodus is UIT"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Instellingen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Hiermee kan de app een melding verzenden dat een sms\'je is ontvangen. Schadelijke apps kunnen dit gebruiken om inkomende sms\'jes te vervalsen."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Hiermee kan de app een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke apps kunnen dit gebruiken om de ontvangst van MMS-berichten te vervalsen of de inhoud van een webpagina ongemerkt te vervangen door schadelijke varianten."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"melding verzenden dat netwerken een score moeten krijgen"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Hiermee kan de app een melding uitzenden dat netwerken een score moeten krijgen. Nooit vereist voor normale apps."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"aantal actieve processen beperken"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Hiermee kan de app het maximale aantal processen beheren dat kan worden uitgevoerd. Nooit nodig voor normale apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"achtergrondapps gedwongen stoppen"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een extern display. Nooit vereist voor normale apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"verbinden met een widgetservice"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"binden aan de service van een routeprovider"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Hiermee kan de houder binden aan geregistreerde routeproviders. Nooit gebruikt voor normale apps."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Hiermee kan de houder intenties verzenden naar een apparaatbeheerder. Nooit vereist voor normale apps."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"binden aan een tv-ingang"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-status wijzigen"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Hiermee kan de app de tablet verbinden met WiMAX-netwerken en de verbinding daarmee verbreken."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Hiermee kan de app de telefoon verbinden met WiMAX-netwerken en de verbinding daarmee verbreken."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"score toekennen aan netwerken"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Hiermee kan de app netwerken rangschikken en beïnvloeden aan welke netwerken de tablet de voorkeur moet geven."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Hiermee kan de app netwerken rangschikken en beïnvloeden aan welke netwerken de telefoon de voorkeur moet geven."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"koppelen met Bluetooth-apparaten"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Hiermee kan de app de Bluetooth-configuratie van de tablet bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Hiermee kan de app de Bluetooth-configuratie van de telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 3ebe3f1..34d43de 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizuj"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Zbyt wiele usuwanych <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pamięć tabletu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Pamięć w zegarku jest pełna. Usuń niektóre pliki, by zwolnić miejsce."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pamięć telefonu jest pełna. Usuń niektóre pliki, aby zwolnić miejsce."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieć może być monitorowana"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Przez nieznany podmiot zewnętrzny"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Dzwonek włączony"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Wyłączanie..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet zostanie wyłączony."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Zegarek zostanie wyłączony."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon zostanie wyłączony"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Czy chcesz wyłączyć?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Uruchom w trybie awaryjnym"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Tryb samolotowy"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Tryb samolotowy jest włączony"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Tryb samolotowy jest wyłączony"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Ustawienia"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
<string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Pozwala aplikacji na wysyłanie powiadomienia, że została odebrana wiadomość SMS. Złośliwe aplikacje mogą to wykorzystać do fałszowania przychodzących wiadomości SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"wysyłanie transmisji informującej o otrzymaniu wiadomości WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Pozwala aplikacji na nadanie powiadomienia o odebraniu wiadomości WAP PUSH. Złośliwe aplikacje mogą to wykorzystać do fałszowania potwierdzenia odbioru wiadomości MMS lub do niezauważalnego podmieniania zawartości dowolnej strony internetowej jej szkodliwymi wariantami."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"rozsyłanie informacji o ocenie sieci"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Pozwala aplikacji na wysłanie powiadomienia, że sieci wymagają oceny. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ograniczanie liczby uruchomionych procesów"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Pozwala aplikacji na kontrolowanie maksymalnej liczby uruchamianych procesów. Nigdy niewykorzystywane przez normalne aplikacje."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"wymuszanie zamknięcia aplikacji w tle"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu wyświetlacza zdalnego. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"powiązanie z usługą widżetów"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"powiązanie z usługą dostawcy tras"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umożliwia właścicielowi powiązanie z dowolnymi zarejestrowanymi dostawcami tras. Nie powinno być nigdy potrzebne w normalnych aplikacjach."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Zezwala na wysyłanie intencji do administratora urządzenia. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"powiązanie z wejściem TV"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"zmienianie stanu WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Pozwala aplikacji na nawiązywanie i kończenie połączeń z sieciami WiMAX w tablecie."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Pozwala aplikacji na nawiązywanie i kończenie połączeń z sieciami WiMAX w telefonie."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocenianie sieci"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Pozwala aplikacji na ocenę sieci i wybieranie sieci preferowanych przez tablet."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Pozwala aplikacji na ocenę sieci i wybieranie sieci preferowanych przez telefon."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"parowanie z urządzeniami Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Pozwala aplikacji na dostęp do konfiguracji Bluetooth na tablecie oraz na nawiązywanie i akceptowanie połączeń ze sparowanych urządzeń."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Pozwala aplikacji na dostęp do konfiguracji Bluetooth na telefonie oraz na nawiązywanie i akceptowanie połączeń ze sparowanych urządzeń."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 7267cf2..6996d13 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronização"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminações de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Elimine alguns ficheiros para libertar espaço."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"O armazenamento de visualizações está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telemóvel está cheio. Elimine alguns ficheiros para libertar espaço."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorizada"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por um terceiro desconhecido"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ativada"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"A encerrar..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"O seu tablet irá encerrar."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"As suas visualizações vão ser encerradas."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será encerrado."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Pretende encerrar?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo de avião"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"O modo de voo está ativado"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"O modo de voo está desativado"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Definições"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que a aplicação difunda uma notificação de que foi recebida uma mensagem SMS. As aplicações maliciosas podem utilizar este recurso para forjar mensagens SMS recebidas."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar difusão recebida através de PUSH WAP"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que a aplicação difunda uma notificação de que foi recebida uma mensagens PUSH WAP. As aplicações maliciosas podem utilizar isto para forjar um recibo de mensagem MMS ou substituir, de forma silenciosa, o conteúdo de qualquer página Web por variantes maliciosas."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmissão de pontuação de redes"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite à aplicação transmitir uma notificação de que é necessário pontuar as redes. Nunca é necessário para aplicações normais."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"número limite de processos em execução"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite a uma aplicação controlar o número máximo de processos que será executado. Nunca é necessário para aplicações normais."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forçar as aplicações em segundo plano a fechar"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite ao detentor associar a interface de nível superior a um ecrã remoto. Nunca deve ser necessário para aplicações normais."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a um serviço de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"vincular a serviço de fornecedor de trajeto"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite ao titular vincular a quaisquer fornecedores de trajeto registado. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite ao titular enviar intenções para um administrador do aparelho. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"vincular a uma entrada de TV"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Alterar estado do WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que a aplicação ligue e desligue o tablet de redes WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que a aplicação ligue e desligue o telemóvel de redes WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"pontuar redes"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite à aplicação classificar redes e influenciar as redes que o tablet deve preferir."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite à aplicação classificar redes e influenciar as redes que o telemóvel deve preferir."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"sincronizar com dispositivos Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que a aplicação visualize a configuração do Bluetooth no tablet e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que a aplicação visualize a configuração do Bluetooth no telemóvel e que estabeleça e aceite ligações com dispositivos emparelhados."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 690d047..a0124ca 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizar"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Muitas exclusões de <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"O armazenamento do tablet está cheio. Exclua alguns arquivos para liberar espaço."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Armazenamento do relógio cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"O armazenamento do telefone está cheio. Exclua alguns arquivos para liberar espaço."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"A rede pode ser monitorada"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Por terceiros desconhecidos"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Campainha ligada"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Encerrando…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Seu tablet será desligado."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Seu relógio será desligado."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"O seu telefone será desligado."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Deseja desligar?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reiniciar no modo de segurança"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite que o aplicativo transmita uma notificação quando uma mensagem SMS foi recebida. Aplicativos maliciosos podem usar esse recurso para forjar mensagens SMS recebidas."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"enviar transmissão WAP-PUSH recebida"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite que o aplicativo transmita uma notificação quando uma mensagem WAP PUSH for recebida. Aplicativos maliciosos podem usar esse recurso para forjar o recebimento de mensagens MMS ou substituir o conteúdo de qualquer página da web com variantes maliciosas."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"enviar transmissão de avaliação de redes"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite que o aplicativo transmita uma notificação informando que as redes devem ser avaliadas. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar número de processos em execução"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite que o aplicativo controle o máximo de processos que serão executados. Nunca é necessário para aplicativos normais."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forçar encerramento de aplicativos em segundo plano"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite que o proprietário use a interface de nível superior de uma tela remota. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para aplicativos normais."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"usar um serviço provedor de rotas"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite que o proprietário use qualquer provedor de rotas registrado. Não deve ser necessário para aplicativos comuns."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite que o proprietário envie tentativas ao administrador de um aparelho. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"associar a uma entrada de TV"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Alterar estado do WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite que o aplicativo conecte e desconecte o tablet de redes WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite que o aplicativo conecte e desconecte o telefone de redes WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"avaliar redes"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite que o aplicativo classifique as redes e influencie a escolha de redes pelo tablet."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite que o aplicativo classifique as redes e influencie a escolha de redes pelo smartphone."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"parear com dispositivos Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite que o aplicativo acesse a configuração do Bluetooth no tablet, além de fazer e aceitar conexões com dispositivos pareados."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite que o aplicativo acesse a configuração do Bluetooth no telefone, além de fazer e aceitar conexões com dispositivos pareados."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index a9e0d4e..dc710d4 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -218,6 +218,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modus d\'aviun"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Il modus d\'aviun è activà"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Il modus d\'aviun è deactivà."</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<!-- no translation found for status_bar_notification_info_overflow (5301981741705354993) -->
<skip />
<string name="safeMode" msgid="2788228061547930246">"Modus segirà"</string>
@@ -614,6 +616,10 @@
<skip />
<!-- no translation found for permdesc_bindRemoteViews (4717987810137692572) -->
<skip />
+ <!-- no translation found for permlab_bindRouteProvider (4869394607915096847) -->
+ <skip />
+ <!-- no translation found for permdesc_bindRouteProvider (4703804520859960329) -->
+ <skip />
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacziun cun in administratur dad apparats"</string>
<!-- no translation found for permdesc_bindDeviceAdmin (569715419543907930) -->
<skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ebcf7d6..0757578 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronizare"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Prea multe ştergeri <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Stocarea pe tabletă este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Spațiul de stocare de pe ceas este plin! Ștergeți câteva fișiere pentru a elibera spațiu."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Stocarea pe telefon este plină. Ștergeţi câteva fişiere pentru a elibera spaţiu."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Rețeaua poate fi monitorizată"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"De o terță parte necunoscută"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Sonerie activată"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Se închide..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Computerul dvs. tablet PC se va închide."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ceasul dvs. se va închide."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonul dvs. se va închide."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Doriţi să închideţi?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reporniţi în modul sigur"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod Avion"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modul Avion este ACTIVAT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modul avion este DEZACTIVAT"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permite aplicaţiei să difuzeze o notificare de primire a unui mesaj SMS. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a deturna primirea mesajelor SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"trimitere mesaj difuzat primit prin WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permite aplicaţiei să difuzeze o notificare de primire a unui mesaj WAP PUSH. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a deturna primirea mesajelor MMS sau pentru a înlocui fără a vă înştiinţa conţinutul oricărei pagini web cu variante rău intenţionate."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"trimiteți transmisia cu rețelele punctate"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Permite aplicației să transmită o notificare de care rețelele au nevoie pentru a fi punctate. Nu este necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitare număr de procese în derulare"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permite aplicaţiei să controleze numărul maxim de procese care vor rula. Nu este niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"forţează închiderea aplicaţiilor de fundal"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite proprietarului să se conecteze la interfața de nivel superior a unui ecran la distanță. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"conectare la un serviciu widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"se conectează la un serviciu de furnizare a traseelor"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Permite titularului să se conecteze la furnizorii de trasee înregistrați. Nu este necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permite proprietarului să trimită intenţii către un administrator al dispozitivului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"se conectează la o intrare TV"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Schimbaţi starea WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Permite aplicaţiei să conecteze şi să deconecteze tableta la şi de la reţelele WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Permite aplicaţiei să conecteze şi să deconecteze telefonul la şi de la reţelele WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"rețele punctate"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Permite aplicației să clasifice rețelele și să stabilească ce rețele preferă tableta."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Permite aplicației să clasifice rețelele și să stabilească ce rețele preferă telefonul."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"conectează dispozitive Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Permite aplicaţiei să vadă configuraţia tabletei Bluetooth, să efectueze şi să accepte conexiuni cu dispozitive împerecheate."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Permite aplicaţiei să vadă configuraţia telefonului Bluetooth, să efectueze şi să accepte conexiuni cu dispozitive împerecheate."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 25fe679..f826f1a 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхр."</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Слишком много удалений <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Память планшетного ПК заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Память устройства заполнена. Удалите файлы, чтобы освободить место."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Память телефона заполнена. Удалите какие-нибудь файлы, чтобы освободить место."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Сеть может отслеживаться"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"администратором"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Звонок включен"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Выключение..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Планшетный ПК будет отключен."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Устройство будет отключено."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефон будет выключен."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Завершить работу?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Переход в безопасный режим"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим полета"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Выключить"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Включить"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Приложение сможет уведомлять о получении SMS. Вредоносные программы смогут таким образом подделывать входящие SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"Отправка уведомлений о доставке SMS с ссылкой на WAP-страницу"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Приложение сможет уведомлять о получении сообщений WAP PUSH. Вредоносные программы смогут таким образом фальсифицировать получение MMS или незаметно подменять содержание любой страницы вредоносными данными."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"Отправка уведомлений о рейтинге сетей"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Приложение сможет отправлять уведомления о том, что сети необходимо присвоить рейтинг. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"Ограничение количества запущенных процессов"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Приложение сможет управлять максимальным количеством процессов, которые могут быть запущены. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"Закрытие фоновых приложений"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Приложение сможет подключаться к базовому интерфейсу удаленного дисплея. Это разрешение обычно используется только специальными приложениями."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"Подключение к службе виджетов"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Подключение к серверам поставщиков маршрутов"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Приложение сможет подключаться к серверам зарегистрированных поставщиков маршрутов. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Приложение сможет отправлять объекты intent администратору устройства. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"Подключение к ТВ-входу"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Изменение статуса WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Приложение сможет подключать устройство к сетям WiMAX и отключать его от них."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Приложение сможет подключать устройство к сетям WiMAX и отключать его от них."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"Определение рейтинга сетей"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Приложение сможет присваивать сетям рейтинг и решать, к каким из них устройство должно подключаться в первую очередь."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Приложение сможет присваивать сетям рейтинг и решать, к каким из них устройство должно подключаться в первую очередь."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Установление связи с устройствами Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Приложение сможет просматривать конфигурацию Bluetooth на планшетном ПК, а также запрашивать и подтверждать соединение с другими устройствами."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Приложение сможет просматривать конфигурацию Bluetooth на телефоне, а также запрашивать и подтверждать соединение с другими устройствами."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 229e9f3..09cf7f6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronizovať"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Príliš veľa odstránených položiek služby <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Ukladací priestor tabletu je plný. Odstráňte niektoré súbory a uvoľnite miesto."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Ukladací priestor hodiniek je plný. Uvoľnite miesto odstránením niektorých súborov."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pamäť telefónu je plná. Odstráňte niektoré súbory a uvoľnite miesto."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Sieť môže byť monitorovaná"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Neznámou treťou stranou"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Zvonenie je zapnuté"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Prebieha vypínanie..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Váš tablet bude vypnutý."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Hodinky sa vypnú."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Váš telefón bude vypnutý."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Chcete zariadenie vypnúť?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Reštartovať do núdzového režimu"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V lietadle"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V lietadle je ZAPNUTÝ"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V lietadle je VYPNUTÝ"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Umožňuje aplikácii vysielať oznámenie, že správa SMS bola doručená. Škodlivé aplikácie môžu toto nastavenie použiť na falšovanie prichádzajúcich správ SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"odoslanie vysielania typu WAP-PUSH-received"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Umožňuje aplikácii vysielať oznámenie, že správa WAP PUSH bola doručená. Škodlivé aplikácie môžu použiť toto nastavenie na vytvorenie potvrdenia o doručení správy MMS alebo na utajené nahradenie obsahu akejkoľvek stránky škodlivými variantmi."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"odoslanie skóre vysielaných sieťami"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Umožňuje aplikácii vysielať upozornenie, že je potrebné zadať skóre sietí. Bežné aplikácie toto povolenie nepotrebujú."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"obmedzenie počtu spustených procesov"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Umožňuje aplikácii kontrolovať maximálny počet spustených procesov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vynútiť zavretie aplikácií na pozadí"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania vzdialeného displeja. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"viazať sa k službe miniaplikácie"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"viazanie na službu poskytovateľa cesty"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Umožňuje držiteľovi viazať sa na akýchkoľvek registrovaných poskytovateľov cesty. Normálne aplikácie by toto povolenie nemali nikdy nepotrebovať."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Umožňuje držiteľovi odosielať informácie správcovi zariadenia. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"viazanie na televízny vstup"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Zmeniť stav siete WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Umožňuje aplikácii pripojiť tablet k sieťam WiMAX a odpojiť ho od nich."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Umožňuje aplikácii pripojiť telefón k sieťam WiMAX a odpojiť ho od nich."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"zadanie skóre sietí"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Umožňuje aplikácii hodnotiť siete a ovplyvňovať, ktoré siete by mal tablet preferovať."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Umožňuje aplikácii hodnotiť siete a ovplyvňovať, ktoré siete by mal telefón preferovať."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"párovať so zariadeniami Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na tablete. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Umožňuje aplikácii zobraziť informácie o konfigurácii Bluetooth na telefóne. Taktiež jej umožňuje nadväzovať a akceptovať spojenia so spárovanými zariadeniami."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index de57325..00649f4 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizacija"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Preveč izbrisov vsebine <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pomnilnik tabličnega računalnika je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Shramba ure je polna. Izbrišite nekaj datotek, da sprostite prostor."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Pomnilnik telefona je poln. Izbrišite nekaj datotek, da sprostite prostor."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Omrežje je lahko nadzorovano"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Neznana tretja oseba"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Vklopi zvonjenje"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Se zaustavlja ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablični računalnik se bo zaustavil."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ura se bo izklopila."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon bo zaustavljen."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Ali želite izklopiti napravo?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Vnovičen zagon v varnem načinu"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način za letalo"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Način za letalo je VKLOPLJEN"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Način za letalo je IZKLOPLJEN"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Nastavitve"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Programu omogoča oddajo obvestila o prejetih sporočilih SMS. Zlonamerni programi lahko to uporabijo za ponarejanje dohodnih SMS-ov."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"pošiljanje oddaje, prejete s potisnim sporočilom WAP"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Programu omogoča oddajo obvestila, da je bilo potisno sporočilo WAP prejeto. Zlonamerni programi lahko to uporabijo za ponarejanje potrdila o prejemu sporočila MMS ali za neopazno menjavo vsebine poljubne spletne strani z zlonamernimi različicami."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"pošiljanje oddaj o ocenjevanju omrežij"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Aplikaciji dovoli oddajo obvestila, da je treba omrežja oceniti. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"omejevanje števila izvajajočih se procesov"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Programu omogoča nadzor največjega števila postopkov, ki se bodo izvajali. Tega nikoli ni treba uporabiti za navadne programe."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"vsiljeno zapiranje aplikacij v ozadju"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Imetniku omogoča povezovanje z vmesnikom oddaljenega prikaza najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"poveži s storitvijo pripomočka"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne programe."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"Povezava s storitvijo ponudnika poti"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Omogoča imetniku, da se povezuje z registriranimi ponudniki poti. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Omogoča lastniku, da pošlje namere skrbniku naprave. Nikoli se ne uporablja za navadne programe."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"povezava s TV-vhodom"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Sprememba stanja omrežja WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Aplikaciji omogoča, da vzpostavi povezavo med tabličnim računalnikom in omrežjem WiMAX ter jo prekine."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Aplikaciji omogoča, da vzpostavi povezavo med telefonom in omrežjem WiMAX ter jo prekine."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ocenjevanje omrežij"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Aplikaciji dovoli, da omrežja razvršča in vpliva na to, katera naj tablični računalnik prednostno izbere."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Aplikaciji dovoli, da omrežja razvršča in vpliva na to, katera naj telefon prednostno izbere."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"seznanitev z napravami Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Aplikaciji omogoča ogled konfiguracije Bluetootha tabličnega računalnika ter vzpostavljanje in sprejemanje povezave s seznanjenimi napravami."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Aplikaciji omogoča ogled konfiguracije Bluetootha telefona ter ustvarjanje in sprejemanje povezave s seznanjenimi napravami."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4bf015f..d363771 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизација"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Превише <xliff:g id="CONTENT_TYPE">%s</xliff:g> избрисаних ставки."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Меморија таблета је пуна! Избришите неке датотеке да бисте ослободили простор."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Меморија сата је пуна. Избришите неке датотеке да бисте ослободили простор."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Складиште телефона је пуно! Избришите неке датотеке како бисте ослободили простор."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежа се можда надгледа"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Од стране непознате треће стране"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Звоно је укључено"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Искључивање…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Таблет ће се искључити."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Сат ће се угасити."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Телефон ће се искључити."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Да ли желите да искључите телефон?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Поново покрени систем у безбедном режиму"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим рада у авиону"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим рада у авиону је УКЉУЧЕН"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим рада у авиону је ИСКЉУЧЕН"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дозвољава апликацији да емитује обавештење да је SMS порука примљена. Злонамерне апликације на тај начин могу да фалсификују долазне SMS поруке."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"слање примљених PUSH емитовања преко WAP-а"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дозвољава апликацији да емитује обавештење да је примљена PUSH порука преко WAP-а. Злонамерне апликације то могу да искористе да фалсификују пријем MMS порука или да кришом замене садржај било које веб-странице уносом злонамерног садржаја."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"шаљи обавештења о тестирању мрежа"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Омогућава апликацији да емитује обавештење да је потребно тестирање мрежа. Никада није потребно за стандардне апликације."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"ограничење броја покренутих процеса"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дозвољава апликацији да управља максималним бројем процеса који ће моћи да се покрену. Никада није потребна уобичајеним апликацијама."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"принудно затварање позадинских апликација"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозвољава власнику да се повеже са интерфејсом удаљеног екрана највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обавезивање на услугу виџета"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"повежи са услугом добављача путања"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Дозвољава власнику да се повеже са добављачима путања. Никада не би требало да буде потребно за обичне апликације."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Омогућава да власник шаље своје намере администратору уређаја. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"повезивање са ТВ улазом"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Промени WiMAX статус"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Дозвољава апликацији да повезује таблет са WiMAX мрежама и прекида везе са њима."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Дозвољава апликацији да повезује телефон са WiMAX мрежама и прекида везе са њима."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"тестирај мреже"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Омогућава апликацији да рангира мреже и утиче на то које су мреже примарне на таблету."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Омогућава апликацији да рангира мреже и утиче на то које су мреже примарне на телефону."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"упаривање са Bluetooth уређајима"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Дозвољава апликацији да прегледа конфигурацију Bluetooth-а на таблету, као и да успоставља и прихвата везе са упареним уређајима."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Дозвољава апликацији да прегледа конфигурацију Bluetooth-а на телефону, као и да успоставља и прихвата везе са упареним уређајима."</string>
@@ -904,7 +901,7 @@
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Откључавање налога"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Превише покушаја уноса шаблона"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Корисничко име (адреса е-поште)"</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Корисничко име (имејл адреса)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Лозинка"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Пријави ме"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Неважеће корисничко име или лозинка."</string>
@@ -1561,7 +1558,7 @@
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (адреса е-поште)"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (имејл адреса)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 24b032e..7ec4f41 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synkronisera"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"För många <xliff:g id="CONTENT_TYPE">%s</xliff:g>-borttagningar."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Pekdatorns lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Klockans lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Mobilens lagringsutrymme är fullt. Ta bort några filer för att frigöra utrymme."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Nätverket kan vara övervakat"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Av en okänd tredje part"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringsignal på"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Avslutar…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din surfplatta stängs av."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Klockan stängs av."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon stängs av."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vill du stänga av?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Starta om i felsäkert läge"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flygplansläge"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flygplansläge är AKTIVERAT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flygplansläge är INAKTIVERAT"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Inställningar"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Tillåter att appen sänder ut en avisering när SMS tas emot. Skadliga appar kan använda detta för att förfalska inkommande SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"skicka WAP-PUSH-mottagen sändning"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Tillåter att appen skickar ett meddelande om att ett WAP PUSH-meddelande har tagits emot. Skadliga appar kan använda detta för att förfalska mottagning av MMS eller för att obemärkt byta ut innehållet på en webbsida mot skadligt innehåll."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"skicka betyg som nätverk skickar"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Tillåter att appen skickar ett meddelande om att nätverket måste betygsättas. Ska inte behövas för vanliga appar."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"begränsa antalet processer som körs"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Tillåter att appen styr högsta antalet processer som körs. Behövs inte för vanliga appar."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"tvinga bakgrundsappar att avslutas"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en fjärrskärm. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind till en widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bind till en ruttleverantörstjänst"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Tillåter att innehavaren binds till en registrerad ruttleverantör. Detta ska inte behövas för vanliga appar."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga appar behöver aldrig göra detta."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"binda till en tv-insignal"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"ändra WiMAX-status"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Tillåter att appen ansluter surfplattan till eller kopplar från WiMAX-nätverk."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Tillåter att appen ansluter mobilen till eller kopplar från WiMAX-nätverk."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"betygsätt nätverk"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Tillåter att appen betygsätter nätverk och påverkar vilka nätverk som ska användas i första hand av surfplattan."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Tillåter att appen betygsätter nätverk och påverkar vilka nätverk som ska användas i första hand av mobilen."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"koppla till Bluetooth-enheter"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Tillåter att appen kommer åt pekdatorns Bluetooth-konfiguration och upprättar och godkänner anslutningar till parkopplade enheter."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Tillåter att appen kommer åt mobilens Bluetooth-konfiguration och upprättar och godkänner anslutningar till parkopplade enheter."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 233bd7a..40adc3e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sawazisha"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Ufutaji mwingi sana <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Hifadhi ya kompyuta kibao imejaa. Futa baadhi ya faili ili kupata nafasi."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Hifadhi ya saa imejaa. Futa baadhi ya faili ili uweze kupata nafasi."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Hifadhi ya simu imejaa. Futa baadhi ya faili ili uweze kupata nafasi."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Huenda mtandao unafuatiliwa"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Na mtu mwingine asiyejulikana"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Programu ya milio imewashwa"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Inafunga..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Kompyuta kibao yako itazima."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Saa yako itajizima."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Simu yako itazima."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Unataka kuzima?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Washa upya kwa hali salama"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Hali ya ndege"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Hali ya ndege IMEWASHWA"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Hali ya ndege IMEZIMWA"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
<string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Huruhusu programu kutangaza taarifa kwamba ujumbe wa SMS umeingia. Programu hasidi zinaweza kutumia hii kubuni SMS zinazoingia."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"tuma tangazo lililopokewa la MSUKUMO WA WAP"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Inaruhusu programu kutangaza taarifa kwamba ujumbe wa WAP PUSH umepokewa. Programu hasidi zinaweza kutumia hii kubuni risiti ya ujumbe wa MMS au polepole kubadilisha maudhui yoyote ya ukurasa wa tovuti na vibadala vibovu."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"tuma tangazo la alama za mitandao"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Huruhusu programu kutangaza arifa kuwa mitandao inafaa kupewa alama. Haihitajiki kamwe kwa programu za kawaida."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"zuia idadi ya michakato inayoendeshwa"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Inaruhusu programu kudhibiti upeo wa idadi ya michakato ambayo itaendeshwa. Kamwe hazihitajiki kwa programu za kwaida."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"lazimisha programu za usuli kufunga"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Huruhusu mtumiaji kujifungia kiolesura cha kiwango cha juu cha mwonekano wa mbali. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bandika kwenye huduma ya mtoa huduma za njia"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Huruhusu mmiliki kubandika kwenye watoa huduma za njia waliosajiliwa. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Inamruhusu mmiliki kutuma malengo kwa msimamizi wa kifaa. Haipaswi kuhitajika kwa programu za kawaida."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bandika kwenye zana za data ya runinga"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Badilisha hali ya WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Inaruhusu programu kuunganisha kompyuta kibao, na kukata kompyuta kibao kutoka mitandao ya WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Inaruhusu programu kuunganisha simu kwenye, na kukata simu kutoka mitandao ya WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ipe mitandao alama"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Huruhusu programu kupanga mitandao kwa alama na kushawishi mitandao ambayo kompyuta kibao inapaswa kupendelea."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Huruhusu programu kupanga mitandao kwa alama na kushawishi mitandao ambayo simu inapaswa kupendelea."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"oanisha na vifaa vya Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Inaruhusu programu kuona usanidi wa Bluetooth kwenye kompyuta kibao, na kuunda na kukubali miunganisho kwa vifaa vilivyooanishwa."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Inaruhusu programu kuona usanidi wa Bluetooth kwenye simu, na kuunda na kukubali miunganisho kwa vifaa vilivyooanishwa."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 452c02d..c211018 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"ซิงค์"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"มีการลบ <xliff:g id="CONTENT_TYPE">%s</xliff:g> มากเกินไป"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"ที่จัดเก็บข้อมูลของแท็บเล็ตเต็ม ลบไฟล์บางไฟล์เพื่อเพิ่มพื้นที่ว่าง"</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"ที่เก็บข้อมูลนาฬิกาเต็ม โปรดลบไฟล์บางไฟล์เพื่อเพิ่มพื้นที่ว่าง"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ที่เก็บข้อมูลโทรศัพท์เต็ม ลบบางไฟล์เพื่อเพิ่มที่ว่าง"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"เครือข่ายอาจได้รับการตรวจสอบ"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"โดยบุคคลที่สามที่ไม่รู้จัก"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"เปิดเสียง"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"กำลังปิดระบบ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"แท็บเล็ตของคุณจะปิดการทำงาน"</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"นาฬิกาจะปิดการทำงาน"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"โทรศัพท์ของคุณจะปิดเครื่อง"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"คุณต้องการปิดการทำงานหรือไม่"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"รีบูตเข้าสู่โหมดปลอดภัย"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"โหมดใช้งานบนเครื่องบิน"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"เปิดโหมดใช้งานบนเครื่องบิน"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"โหมดใช้งานบนเครื่องบินปิดทำงานอยู่"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"การตั้งค่า"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
<string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
@@ -333,16 +332,14 @@
<string name="permdesc_getTopActivityInfo" msgid="2512448855496067131">"ช่วยให้เจ้าของสามารถดึงข้อมูลส่วนตัวเกี่ยวกับแอปพลิเคชันปัจจุบันในส่วนหน้าของหน้าจอ"</string>
<string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"ตรวจสอบและควบคุมแอปพลิเคชันทั้งหมดที่เปิดใช้งาน"</string>
<string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"อนุญาตให้แอปพลิเคชันตรวจสอบและควบคุมวิธีการที่ระบบเปิดกิจกรรมต่างๆ แอปพลิเคชันที่เป็นอันตรายอาจทำอันตรายแก่ระบบได้อย่างสิ้นเชิง การอนุญาตนี้จำเป็นสำหรับการพัฒนาเท่านั้น ไม่ใช้สำหรับแอปพลิเคชันทั่วไปโดยเด็ดขาด"</string>
- <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพคเกจออก"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าแพคเกจของแอปพลิเคชันหนึ่งๆ ได้ถูกนำออกไปแล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติแอปพลิเคชันอื่นๆ ที่กำลังทำงานอยู่"</string>
+ <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"ส่งการกระจายข้อมูลว่ามีการนำแพ็กเกจออก"</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าแพ็กเกจของแอปพลิเคชันหนึ่งๆ ได้ถูกนำออกไปแล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติแอปพลิเคชันอื่นๆ ที่กำลังทำงานอยู่"</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"ส่งการกระจายข้อมูลว่าได้รับ SMS"</string>
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าได้รับข้อความ SMS แล้ว แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ปลอมข้อความ SMS ที่เข้ามา"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ส่งการกระจายข้อมูลว่าได้รับ WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"อนุญาตให้แอปพลิเคชันกระจายข้อมูลการแจ้งเตือนว่าได้รับข้อความ WAP PUSH แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ปลอมการแจ้งรับข้อความ MMS หรือแอบเปลี่ยนเนื้อหาในหน้าเว็บโดยใช้ตัวแปรที่เป็นอันตราย"</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ส่งเผยแพร่การให้คะแนนเครือข่าย"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"อนุญาตให้แอปนี้เผยแพร่ข้อมูลการแจ้งเตือนว่าเครือข่ายจะต้องผ่านการให้คะแนน ไม่จำเป็นสำหรับแอปทั่วไป"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"จำกัดจำนวนกระบวนการที่กำลังทำงาน"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"อนุญาตให้แอปพลิเคชันควบคุมจำนวนสูงสุดของกระบวนการที่จะเรียกใช้ ไม่จำเป็นต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"บังคับปิดแอปพลิเคชันในพื้นหลัง"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"อนุญาตให้ผู้ใช้ผูกกับอินเทอร์เฟซระดับสูงสุดของจอแสดงผลระยะไกล ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"เชื่อมโยงกับบริการวิดเจ็ต"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"เชื่อมโยงกับบริการของผู้ให้บริการเส้นทาง"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"ช่วยให้เจ้าของสามารถเชื่อมโยงกับผู้ให้บริการเส้นทางที่ลงทะเบียนรายใดก็ได้ ไม่จำเป็นสำหรับแอปทั่วไป"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"อนุญาตให้ผู้ใช้ส่งการติดต่อไปยังโปรแกรมควบคุมอุปกรณ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"เชื่อมโยงกับอินพุตทีวี"</string>
@@ -412,7 +411,7 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้แท็บเล็ตทำงานช้าลง"</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้โทรศัพท์ทำงานช้าลง"</string>
<string name="permlab_deletePackages" msgid="184385129537705938">"ลบแอปพลิเคชัน"</string>
- <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพคเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
+ <string name="permdesc_deletePackages" msgid="7411480275167205081">"อนุญาตให้แอปพลิเคชันลบแพ็กเกจ Android แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ลบแอปพลิเคชันที่สำคัญ"</string>
<string name="permlab_clearAppUserData" msgid="274109191845842756">"ลบข้อมูลของแอปพลิเคชันอื่น"</string>
<string name="permdesc_clearAppUserData" msgid="4625323684125459488">"อนุญาตให้แอปพลิเคชันล้างข้อมูลผู้ใช้"</string>
<string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"ลบแคชของแอปพลิเคชันอื่น"</string>
@@ -420,7 +419,7 @@
<string name="permlab_getPackageSize" msgid="7472921768357981986">"วัดพื้นที่เก็บข้อมูลของแอปพลิเคชัน"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"อนุญาตให้แอปพลิเคชันเรียกดูรหัส ข้อมูล และขนาดแคชของตน"</string>
<string name="permlab_installPackages" msgid="2199128482820306924">"ติดตั้งแอปพลิเคชันโดยตรง"</string>
- <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพคเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"อนุญาตให้แอปพลิเคชันติดตั้งแพ็กเกจ Android ใหม่หรือที่อัปเดต แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการเพิ่มแอปพลิเคชันใหม่ๆ ด้วยสิทธิ์ที่สูงนี้ได้ตามต้องการ"</string>
<string name="permlab_clearAppCache" msgid="7487279391723526815">"ลบข้อมูลแคชของแอปพลิเคชันทั้งหมด"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของแท็บเล็ต โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
<string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"อนุญาตให้แอปพลิเคชันสร้างพื้นที่ว่างในที่จัดเก็บข้อมูลของโทรศัพท์ โดยลบไฟล์ในไดเรกทอรีแคชของแอปพลิเคชันอื่นๆ ซึ่งอาจทำให้แอปพลิเคชันอื่นเริ่มทำงานช้ากว่าเดิมเนื่องจากต้องดึงข้อมูลของตนซ้ำ"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"เปลี่ยนสถานะของ WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"อนุญาตให้แอปพลิเคชันเชื่อมต่อและยกเลิกการเชื่อมต่อแท็บเล็ตกับเครือข่าย WiMAX"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"อนุญาตให้แอปพลิเคชันเชื่อมต่อและยกเลิกการเชื่อมต่อโทรศัพท์กับเครือข่าย WiMAX"</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ให้คะแนนเครือข่าย"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"อนุญาตให้แอปนี้จัดลำดับเครือข่าย ซึ่งมีผลต่อการเลือกใช้เครือข่ายของแท็บเล็ต"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"อนุญาตให้แอปนี้จัดอันดับเครือข่ายและมีผลต่อการเลือกใช้เครือข่ายของโทรศัพท์"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"จับคู่กับอุปกรณ์บลูทูธ"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"อนุญาตให้แอปพลิเคชันดูการกำหนดค่าบลูทูธของแท็บเล็ต ตลอดจนเชื่อมต่อและยอมรับการเชื่อมต่อกับอุปกรณ์ที่จับคู่ไว้"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"อนุญาตให้แอปพลิเคชันดูการกำหนดค่าบลูทูธของโทรศัพท์ ตลอดจนเชื่อมต่อและยอมรับการเชื่อมต่อกับอุปกรณ์ที่จับคู่ไว้"</string>
@@ -949,7 +945,7 @@
<string name="hour_cap_ampm" msgid="2083465992940444366">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<string name="factorytest_failed" msgid="5410270329114212041">"การทดสอบจากโรงงานล้มเหลว"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"การทำงาน FACTORY_TEST ได้รับการสนับสนุนเฉพาะสำหรับแพ็คเก็จที่ติดตั้งใน /system/app เท่านั้น"</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"ไม่พบแพคเกจที่มีการทำงาน FACTORY_TEST"</string>
+ <string name="factorytest_no_action" msgid="872991874799998561">"ไม่พบแพ็กเกจที่มีการทำงาน FACTORY_TEST"</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"รีบูต"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"หน้าเว็บที่ \"<xliff:g id="TITLE">%s</xliff:g>\" ระบุว่า:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
@@ -988,10 +984,10 @@
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"อนุญาตให้แอปพลิเคชันเพิ่มข้อความลงในกล่องข้อความเสียงของคุณ"</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"แก้ไขการอนุญาตเกี่ยวกับการระบุตำแหน่งทางภูมิศาสตร์ของเบราว์เซอร์"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"อนุญาตให้แอปพลิเคชันแก้ไขการอนุญาตตำแหน่งทางภูมิศาสตร์ของเบราว์เซอร์ แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ในการส่งข้อมูลตำแหน่งไปยังเว็บไซต์ต่างๆ ได้ตามต้องการ"</string>
- <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ยืนยันแพคเกจ"</string>
- <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพคเกจสามารถติดตั้งได้หรือไม่"</string>
- <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพคเกจ"</string>
- <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"ยืนยันแพ็กเกจ"</string>
+ <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพ็กเกจสามารถติดตั้งได้หรือไม่"</string>
+ <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพ็กเกจ"</string>
+ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพ็กเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"เข้าถึงผู้ให้บริการเนื้อหาจากภายนอก"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index dc7de15..a7b7b8f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"I-sync"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Masyadong maraming pagtanggal ng <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Puno na ang storage ng tablet. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Puno na ang storage ng relo. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Puno na ang storage ng telepono. Magtanggal ng ilang file upang magbakante ng espasyo."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Maaaring sinusubaybayan ang network"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ng isang di-kilalang third party"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"I-on ang ringer"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Nagsa-shut down…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Mag-shut down ang iyong tablet."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Magsa-shut down ang iyong relo."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Magsa-shut down ang iyong telepono."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Nais mo bang mag-shut down?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Mag-reboot sa safe mode"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Airplane mode"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Naka-ON ang airplane mode"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Naka-OFF ang airplane mode"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Pinapayagan ang app na mag-broadcast ng isang notification na natanggap ang isang mensaheng SMS. Maaari itong gamitin ng nakakahamak na apps upang dayain ang papasok na mga mensaheng SMS."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"ipadala ang WAP-PUSH-natanggap na pag-broadcast"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Pinapayagan ang app na mag-broadcast ng isang notification na natanggap ang isang mensaheng WAP PUSH. Maaari itong gamitin ng nakakahamak na apps upang dayain ang pagtanggap ng mensaheng MMS o upang tahimik na palitan ang nilalaman ng anumang webpage ng mga nakakahamak na variant."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"magpadala ng broadcast ng mga network ng score"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Nagbibigay-daan sa app na mag-broadcast ng notification na kailangang ma-score ng mga network. Hindi kailanman kinakailangan para sa mga normal na app."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitahan ang numero ng mga tumatakbong proseso"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Pinapayagan ang app na kontrolin ang maximum na bilang ng mga proseso na tatakbo. Hindi kailanman kinakailangan para sa normal na apps."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"pwersahin ang mga app sa background na magsara"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Binibigyang-daan ang may-hawak na masaklaw ang pinakamataas na antas ng interface ng isang remote na display. Hindi dapat kailanman kailanganin ng normal na apps."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"itali sa serbisyo ng widget"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"mag-bind sa isang serbisyo ng route provider"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Nagbibigay-daan sa may-pahintulot na mag-bind sa anumang nakarehistrong route provider. Hindi dapat kailanganin kailanman ng mga normal na app."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Pinapayagan ang mga may-ari na magpadala ng mga layunin sa administrator ng device. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"i-bind sa isang TV input"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Baguhin ang katayuan ng WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Pinapayagan ang app na ikonekta ang tablet at idiskonekta ang tablet mula sa mga WiMAX network."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Pinapayagan ang app na ikonekta ang telepono at idiskonekta ang telepono mula sa mga WiMAX network."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"mga network ng score"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Nagbibigay-daan sa app na iranggo ang mga network at impluwensiyahan kung aling mga network ang dapat na piliin ng tablet."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Nagbibigay-daan sa app na iranggo ang mga network at impluwensiyahan kung aling mga network ang dapat na piliin ng telepono."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ipares sa mga Bluetooth device"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Pinapayagan ang app na tingnan ang configuration ng Bluetooth sa tablet, at na gumawa at tumanggap ng mga koneksyong may mga nakapares na device."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Pinapayagan ang app na tingnan ang configuration ng Bluetooth sa telepono, at na gumawa at tumanggap ng mga koneksyong may mga nakapares na device."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index db8c9d4..bc73a93f8 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Senk."</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Çok fazla <xliff:g id="CONTENT_TYPE">%s</xliff:g> silme var."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Tabletin depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Saat depolama alanınız dolu. Lütfen yer boşaltmak için bazı dosyaları silin."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Telefonun depolama alanı dolu! Yer açmak için bazı dosyaları silin."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Ağ izlenebilir"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Bunu, bilinmeyen üçüncü taraflar yapabilir"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Telefon zili açık"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Kapanıyor…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tabletiniz kapanacak."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Saatiniz kapatılacak."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefonunuz kapanacak."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Kapatmak istiyor musunuz?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Güvenli modda yeniden aç"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Uçak modu"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Uygulamaya, SMS mesajı alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte SMS mesajları göndermek için bunu kullanabilir."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"WAP-PUSH ile alınan yayın gönder"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Uygulamaya, WAP PUSH mesajı alındığına dair bildirim yayınlama izni verir. Kötü amaçlı uygulamalar sahte MMS bildirimleri oluşturmak veya bir web sayfasının içeriğini sessiz şekilde zararlı öğelerle değiştirmek için bunu kullanabilir."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"ağları puanlama yayını gönderme"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Uygulamaya, ağların puanlanması gerektiği bildirimini yayınlama izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"çalışan işlem sayısını sınırla"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Uygulamaya, çalışacak süreçlerin azami sayısını denetleme izni verir. Normal uygulamalar için gerekli değildir."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"arka plan uygulamaları kapanmaya zorla"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"İzin sahibine, bir uzak ekranın en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bir widget hizmetine bağla"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"rota sağlayıcı hizmetine bağlanma"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"İzin verilen uygulamaya tüm kayıtlı rota sağlayıcılarına bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cihazın sahibinin cihaz yöneticisine amaç göndermesine izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"TV girişine bağlanma"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX durumunu değiştir"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Uygulamaya, tableti WiMAX ağlarına bağlanma veya bağlantıyı kesme izni verir."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Uygulamaya, telefonu WiMAX ağlarına bağlanma veya bağlantıyı kesme izni verir."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"ağları puanlama"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Uygulamaya, ağları sıralama ve tabletin tercih edeceği ağları etkileme izni verir."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Uygulamaya, ağları sıralama ve telefonunun tercih edeceği ağları etkileme izni verir."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"Bluetooth cihazlarla eşle"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Uygulamaya, tabletteki Bluetooth yapılandırmasını görüntüleme, eşleştirilmiş cihazlarla bağlantı yapma ve bu tür bağlantıları kabul etme izni verir."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Uygulamaya, telefondaki Bluetooth yapılandırmasını görüntüleme, eşleştirilmiş cihazlarla bağlantı yapma ve bu tür bağlantıları kabul etme izni verir."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 388d124..75d77c8 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -173,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим польоту"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим польоту ВВІМК."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим польоту ВИМК."</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Налаштування"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
@@ -337,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дозволяє програмі передавати сповіщення про отримання SMS повідомлення. Шкідливі програми можуть використовувати це для підробки вхідних SMS повідомлень."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"надсил. запис, отр. через WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дозволяє програмі передавати сповіщення про отримання повідомлення WAP PUSH. Шкідливі програми можуть використовувати це для підробки отримання MMS повідомлень або для непомітної заміни вмісту будь-якої веб-сторінки шкідливими варіантами."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"надсилати сповіщення про оцінку мереж"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Дозволяє додатку передавати сповіщення про оцінку мереж. Ніколи не застосовується для звичайних додатків."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"обмежувати кількість запущ. процесів"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дозволяє програмі контролювати максимальну кількість процесів, які буде запущено. Ніколи не вимагається для звичайних програм."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"примусово закривати фонові програми"</string>
@@ -392,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня віддаленого екрана. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прив\'язувати до служби віджетів"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"підключитися до служби постачання маршрутів"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Дозволяє власникові підключатися до зареєстрованих постачальників маршрутів. Звичайні додатки ніколи не використовують цей дозвіл."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дозволяє власнику надсилати задавані функції адміністратору пристрою. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"підключатися до TV-входу"</string>
@@ -642,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Змінити стан WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Дозволяє програмі під’єднувати планшетний ПК до мереж WiMAX і від’єднувати його від них."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Дозволяє програмі під’єднувати телефон до мереж WiMAX і від’єднувати його від них."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"оцінювати мережі"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Дозволяє додатку оцінювати мережі та впливати на вибір мережі планшетом."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Дозволяє додатку оцінювати мережі та впливати на вибір мережі телефоном."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"створювати пару з пристроями Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Дозволяє програмі переглядати конфігурацію Bluetooth на планшетному ПК, а також створювати та приймати з’єднання зі спареними пристроями."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Дозволяє програмі переглядати конфігурацію Bluetooth на телефоні, а також створювати та приймати з’єднання зі спареними пристроями."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index afde154..a1c03ad 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -175,6 +175,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Chế độ trên máy bay"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Chế độ trên máy bay BẬT"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Chế độ trên máy bay TẮT"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
<string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
@@ -339,10 +341,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Cho phép ứng dụng truyền phát thông báo cho biết đã nhận được tin nhắn SMS. Ứng dụng độc hại có thể sử dụng quyền này để giả mạo tin nhắn SMS đến."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"gửi truyền phát WAP-PUSH nhận được"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Cho phép ứng dụng truyền phát thông báo cho biết rằng đã nhận được tin nhắn WAP PUSH. Ứng dụng độc hại có thể sử dụng quyền này để giả mạo xác nhận đã nhận được tin nhắn MMS hoặc ngầm thay thế nội dung của bất kỳ trang web nào bằng các biến thể độc hại."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"gửi chương trình phát mạng điểm số"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Cho phép ứng dụng truyền thông báo rằng các mạng cần để được tính điểm. Không bao giờ cần cho ứng dụng thông thường."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"giới hạn số quá trình đang chạy"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Cho phép ứng dụng kiểm soát số quy trình tối đa sẽ chạy. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"buộc ứng dụng nền đóng"</string>
@@ -394,6 +394,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của màn hình từ xa. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"liên kết với dịch vụ tiện ích con"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"liên kết với dịch vụ nhà cung cấp định tuyến"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Cho phép chủ sở hữu liên kết với bất kỳ nhà cung cấp định tuyến đã đăng ký nào. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Cho phép chủ sở hữu gửi các ý định đến quản trị viên thiết bị. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"liên kết với đầu vào TV"</string>
@@ -644,12 +646,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Thay đổi trạng thái WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Cho phép ứng dụng kết nối máy tính bảng và ngắt kết nối máy tính bảng khỏi mạng WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Cho phép ứng dụng kết nối điện thoại và ngắt kết nối điện thoại khỏi mạng WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"mạng điểm số"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Cho phép ứng dụng xếp hạng mạng và ảnh hưởng đến việc máy tính bảng nên ưu tiên mạng nào."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Cho phép ứng dụng xếp hạng các mạng và ảnh hưởng đến việc điện thoại nên ưu tiên mạng nào."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ghép nối với thiết bị Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Cho phép ứng dụng xem cấu hình của Bluetooth trên máy tính bảng và tạo và chấp nhận các kết nối với các thiết bị được ghép nối."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Cho phép ứng dụng xem cấu hình của Bluetooth trên điện thoại, tạo và chấp nhận các kết nối với các thiết bị được ghép nối."</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
new file mode 100644
index 0000000..4c4d0ce
--- /dev/null
+++ b/core/res/res/values-watch/config.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for watch products. Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Only show power and settings items due to smaller real estate. -->
+ <string-array translatable="false" name="config_globalActionsList">
+ <item>power</item>
+ <item>settings</item>
+ </string-array>
+
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 38ce45d..134cf9a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同步"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"太多<xliff:g id="CONTENT_TYPE">%s</xliff:g>删除项。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板电脑存储空间已满。请删除一些文件以腾出空间。"</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"手表存储空间已满。请删除一些文件以腾出空间。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手机存储空间已满。请删除一些文件以腾出空间。"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"网络可能会受到监控"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"受到不明第三方的监控"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"振铃器开启"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"正在关机..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板电脑会关闭。"</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手表即将关机。"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"您的手机将会关机。"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"您要关机吗?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"重新启动并进入安全模式"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飞行模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允许应用广播一条有关已收到短信的通知。恶意应用可能借此伪造接到的短信。"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"发送 WAP-PUSH 收到的广播"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允许应用广播一条有关已收到 WAP PUSH 短信的通知。恶意应用可能借此伪造短信接收,或在后台将任意网页的内容替换为恶意内容。"</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"发送网络评分广播通知"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允许应用广播“需要为网络评分”的通知。普通应用绝不需要此权限。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"限制运行的进程个数"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允许应用控制将运行的进程数上限。普通应用绝不需要此权限。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"强制关闭后台应用"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"绑定到路由程序服务"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允许应用绑定到任何已注册的路由程序。普通应用绝不需要此权限。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允许用户将意向发送给设备管理员。普通应用绝不需要此权限。"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"绑定至电视输入设备"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"更改 WiMAX 状态"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允许该应用建立和断开平板电脑与 WiMAX 网络之间的连接。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允许该应用建立和断开手机与 WiMAX 网络之间的连接。"</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"为网络评分"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允许应用为网络评分,并控制平板电脑应优先使用的网络。"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允许应用为网络评分,并控制手机应优先使用的网络。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"与蓝牙设备配对"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允许该应用查看平板电脑上的蓝牙配置,以及建立和接受与配对设备的连接。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允许该应用查看手机上的蓝牙配置,以及建立和接受与配对设备的连接。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e4f54af..2d3c418 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Google Sync"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"手錶的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手機的儲存空間已滿。請刪除一些檔案,以騰出可用空間。"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網絡可能會受到監控"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"由不明的第三方監管"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"鈴聲開啟"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"正在關機..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板電腦將會關機。"</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手錶即將關機。"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"您的手機即將關機。"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"您要關機嗎?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"重新啟動進入安全模式"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛行模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛行模式為 [關閉]"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"設定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允許應用程式在收到短訊時發出通知。惡意應用程式可能會藉此偽造外來短訊。"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"傳送可由 WAP PUSH 接收的廣播"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允許應用程式在收到 WAP PUSH 訊息時發送通知。惡意應用程式可能會藉此偽造 MMS 訊息回條或私自以惡意內容更換網頁。"</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"傳送網絡計分廣播"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允許應用程式廣播網絡需要計分的通知,但一般應用程式並不需要使用。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程序數目上限"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允許應用程式控制可執行程序的數量上限 (不建議一般應用程式使用)。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"強制關閉背景應用程式"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端屏螢的頂層介面 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (不建議一般應用程式使用)。"</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"繫結至路由供應商服務"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允許應用程式繫結至任何已註冊的路由供應商,但一般應用程式並不需要使用。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (不建議一般應用程式使用)。"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"繫結至電視訊號輸入裝置"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"更改 WiMAX 狀態"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允許應用程式建立或中斷平板電腦與 WiMAX 網絡的連線。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允許應用程式建立或中斷手機與 WiMAX 網絡的連線。"</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"為網絡計分"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允許應用程式為網絡排名,及決定平板電腦偏好使用的網絡。"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允許應用程式為網絡排名,及決定手機偏好使用的網絡。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"與藍牙裝置配對"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允許應用程式查看平板電腦的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允許應用程式查看手機的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 9b89c75..e309acc 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"同步處理"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"同時刪除太多 <xliff:g id="CONTENT_TYPE">%s</xliff:g>。"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"平板電腦的儲存空間已滿。請刪除一些檔案,以釋放出可用空間。"</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"手錶儲存空間已用盡,請刪除一些檔案以釋出可用空間。"</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"手機儲存空間已滿。請刪除一些檔案,以釋放可用空間。"</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"網路可能會受到監控"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"受到不明的第三方監控"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"鈴聲開啟"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"關機中…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"您的平板電腦將會關機。"</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"您的手錶即將關機。"</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"手機即將關機。"</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"您要關機嗎?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"重新啟動進入安全模式"</string>
@@ -175,6 +173,8 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛航模式"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛航模式為 [關閉]"</string>
+ <!-- no translation found for global_action_settings (1756531602592545966) -->
+ <skip />
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
@@ -339,10 +339,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"允許應用程式在收到 SMS 簡訊時發出通知。請注意,惡意應用程式可能利用此功能偽造外來的 SMS 簡訊。"</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"送出「WAP PUSH 已接收」廣播"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"允許應用程式在收到 WAP PUSH 訊息時發送通知。請注意,惡意應用程式可能利用此功能偽造 MMS 簡訊回條,或私自將網頁內容更換為惡意陷阱。"</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"傳送網路計分廣播通知"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"允許應用程式廣播「網路需計分」的通知訊息 (一般應用程式並不需要)。"</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"執行程序限制數"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"允許應用程式控制可執行程序的數量上限 (一般應用程式不需使用)。"</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"強制關閉背景應用程式"</string>
@@ -394,6 +392,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端螢幕的頂層介面 (一般應用程式不需使用)。"</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"繫結至路由供應商服務"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"允許應用程式繫結至任何已註冊的路由供應商 (一般應用程式並不需要)。"</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"允許應用程式將調用請求傳送至裝置管理員 (一般應用程式不需使用)。"</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"繫結至電視訊號輸入裝置"</string>
@@ -644,12 +644,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"變更 WiMAX 狀態"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"允許應用程式建立或中斷平板電腦與 WiMAX 網路的連線。"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"允許應用程式建立或中斷手機與 WiMAX 網路的連線。"</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"為網路計分"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"允許應用程式建立網路排名,決定平板電腦偏好使用的網路。"</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"允許應用程式建立網路排名,決定手機偏好使用的網路。"</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"與藍牙裝置配對"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"允許應用程式查看平板電腦的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"允許應用程式查看手機的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e552c4e..4e36a1b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -135,8 +135,7 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Vumelanisa"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Kunokususa <xliff:g id="CONTENT_TYPE">%s</xliff:g> okuningi kakhulu."</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Isilondolozi sethebhulethi sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
- <!-- no translation found for low_memory (4415914910770005166) -->
- <skip />
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Isitoreji sokubuka sigcwele. Susa amanye amafayela ukukhulula isikhala."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"Isilondolozi sefoni sigcwele! Susa amanye amafayela ukukhulula isikhala."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Inethiwekhi ingase inganyelwe"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Ngenkampani yangaphandle engaziwa"</string>
@@ -154,8 +153,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Iringa iyasebenza"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Ivala shaqa..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Ithebhulethi yakho izocima."</string>
- <!-- no translation found for shutdown_confirm (3490275567476369184) -->
- <skip />
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Ukubuka kwakho kuzocima."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ifoni yakho izocima."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Ingabe ufuna ukucisha?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"Qala kabusha emodini ephephile"</string>
@@ -175,6 +173,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Imodi yendiza"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Imodi yendiza IVULIWE"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Imodi yendiza IVALIWE"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Izilungiselelo"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
<string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
@@ -339,10 +338,8 @@
<string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-SMS utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja imiyalezo ye-SMS engenayo."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"thumela umsakazo otholwe nge-WAP-PUSH"</string>
<string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Ivumela uhlelo lokusebenza ukuthi isakaze isaziso sokuthi umyalezo we-WAP PUSH utholakele. Izuhlelo lokusebenza ezinobungozi zingasebenzisa lokhu ukufoja ukutholakala kwemiyalezo ye-S noma zisuse okuqukethwe kwanoma iliphi ikhasi lewebhu eliqukethe okunobungozi."</string>
- <!-- no translation found for permlab_broadcastScoreNetworks (6432008366605475024) -->
- <skip />
- <!-- no translation found for permdesc_broadcastScoreNetworks (7652980974435077828) -->
- <skip />
+ <string name="permlab_broadcastScoreNetworks" msgid="6432008366605475024">"thumela ukusakaza kwamanethiwekhi ayisikolo"</string>
+ <string name="permdesc_broadcastScoreNetworks" msgid="7652980974435077828">"Ivumela uhlelo lokusebenza ukusakaza isaziso sokuthi amanethiwekhi adinga isikolo. Awadingeki kuzinhlelo zokusebenza ezivamile."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"khawula inani lezinqubo ezisebenzayo"</string>
<string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Ivumela uhlelo lokusebenza ukuthi ilawule isibalo esikhulu sezinto eziqhubekayo eziyosebenza. Ayidingakeli izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_setAlwaysFinish" msgid="550958507798796965">"phoqa izinhlelo zokusebenza ezingemuva ukuthi zivaleke"</string>
@@ -394,6 +391,8 @@
<string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo esisezingeni eliphezulu sesibonisi sesilawuli kude. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
<string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
+ <string name="permlab_bindRouteProvider" msgid="4869394607915096847">"bophezela kusevisi yomhlinzeki womzila"</string>
+ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Ivumela isibambi ukubophezela kunoma yimuphi umhlinzeki womzila obhalisiwe. Akufanele kudingeke izinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
<string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Ivumela ummeli ukuthumela okuqukethwe kumphathi wedivaysi. Akusoze kwadingeka kwizinhlelo zokusebenza ezivamile."</string>
<string name="permlab_bindTvInput" msgid="5601264742478168987">"bophezela kokokufaka kwe-TV"</string>
@@ -644,12 +643,9 @@
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Shintsha isimo se-WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ivumela uhlelo lokusebenza ukuxhuma ithebhulethi nokunqamula ithebhulethi kumanethiwekhi e-WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ivumela uhlelo lokusebenza ukuxhuma ifoni nokuyinqamula kumanethiwekhi e-WiMAX."</string>
- <!-- no translation found for permlab_scoreNetworks (6445777779383587181) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1304304745850215556) -->
- <skip />
- <!-- no translation found for permdesc_scoreNetworks (1831501848178651379) -->
- <skip />
+ <string name="permlab_scoreNetworks" msgid="6445777779383587181">"amanethiwekhi ayisikolo"</string>
+ <string name="permdesc_scoreNetworks" product="tablet" msgid="1304304745850215556">"Ivumela uhlelo lokusebenza ukuthi lilinganise amanethiwekhi futhi lithuthukise ukuthi imaphi amanethiwekhi ithebhulethi okufanele iwakhethe."</string>
+ <string name="permdesc_scoreNetworks" product="default" msgid="1831501848178651379">"Ivumela uhlelo lokusebenza ukuthi lilinganise amanethiwekhi futhi lithuthukise ukuthi imaphi amanethiwekhi ifoni okufanele iwakhethe."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"matanisa namadivayisi e-Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth kuthebhulethi, nokwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ivumela uhlelo lokusebenza ukubuka ukucushwa kwe-Bluetooth efonini, ukwenza futhi nokwamukela uxhumo namadivayisi amatanisiwe."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 782066e..326485d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2357,6 +2357,10 @@
Activity to UI element in the called Activity. Names should be unique in the
View hierarchy. -->
<attr name="sharedElementName" format="string" />
+
+ <!-- Specifies that this view should permit nested scrolling within a compatible
+ ancestor view. -->
+ <attr name="nestedScrollingEnabled" format="boolean" />
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -4504,6 +4508,8 @@
result to valid color values. Saturate(S + D) -->
<enum name="add" value="16" />
</attr>
+ <!-- Specifies the alpha multiplier to apply to the base drawable. -->
+ <attr name="alpha" />
</declare-styleable>
<!-- Drawable used to draw 9-patches. -->
@@ -4523,6 +4529,8 @@
<!-- When a tint color is set, specifies its Porter-Duff blending mode. The
default value is src_in, which treats the drawable as an alpha mask. -->
<attr name="tintMode" />
+ <!-- Specifies the alpha multiplier to apply to the base drawable. -->
+ <attr name="alpha" />
</declare-styleable>
<!-- Drawable used to draw a single color. -->
@@ -6259,13 +6267,21 @@
</declare-styleable>
<!-- Use <code>recognition-service</code> as the root tag of the XML resource that
- describes a {@link android.speech.RecognitionService}, which is reference from
+ describes a {@link android.speech.RecognitionService}, which is referenced from
its {@link android.speech.RecognitionService#SERVICE_META_DATA} meta-data entry.
Described here are the attributes that can be included in that tag. -->
<declare-styleable name="RecognitionService">
<attr name="settingsActivity" />
</declare-styleable>
+ <!-- Use <code>voice-interaction-service</code> as the root tag of the XML resource that
+ describes a {@link android.service.voice.VoiceInteractionService}, which is referenced from
+ 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="settingsActivity" />
+ </declare-styleable>
+
<!-- Attributes used to style the Action Bar. -->
<declare-styleable name="ActionBar">
<!-- The type of navigation to use. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b14453a..cce4dbd 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -746,7 +746,14 @@
selected a new global font size. -->
<flag name="fontScale" value="0x40000000" />
</attr>
-
+
+ <!-- Indicate that the activity can be launched as the embedded child of another
+ activity. Particularly in the case where the child lives in a container
+ such as a Display owned by another activity.
+
+ <p>The default value of this attribute is <code>false</code>. -->
+ <attr name="allowEmbedded" format="boolean" />
+
<!-- Descriptive text for the associated data. -->
<attr name="description" format="reference" />
@@ -1541,6 +1548,7 @@
primary user. Can only be used with receivers. -->
<attr name="primaryUserOnly" format="boolean" />
<attr name="persistable" />
+ <attr name="allowEmbedded" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/colors_quantum.xml b/core/res/res/values/colors_quantum.xml
index ebe4a49..f8f192f 100644
--- a/core/res/res/values/colors_quantum.xml
+++ b/core/res/res/values/colors_quantum.xml
@@ -118,11 +118,11 @@
<!-- Text & foreground colors -->
- <color name="primary_text_quantum_light">#de000000</color>
+ <color name="primary_text_default_quantum_light">#de000000</color>
<color name="secondary_text_quantum_light">#8a000000</color>
<color name="tertiary_text_quantum_light">#4d000000</color>
- <color name="primary_text_quantum_dark">#deffffff</color>
+ <color name="primary_text_default_quantum_dark">#deffffff</color>
<color name="secondary_text_quantum_dark">#8affffff</color>
<color name="tertiary_text_quantum_dark">#4dffffff</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f549290..f919c9f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -807,6 +807,21 @@
<item>com.android.location.fused</item>
</string-array>
+ <!-- This string array can be overriden to enable test location providers initially. -->
+ <!-- Array of "[locationProviderName],[requiresNetwork],
+ [requiresSatellite],[requiresCell],[hasMonetaryCost],
+ [supportAltitute],[supportsSpeed],[supportsBearing],
+ [powerRequirement],[accuracy]" -->
+ <!-- powerRequirement is defined in android.location.Criteria
+ 0 = NO_REQUIREMENT / 1 = POWER_LOW / 2 = POWER_MEDIUM / 3 = POWER_HIGH -->
+ <!-- accuracy is defined in anroid.location.Criteria
+ 1 = ACCURACY_FINE / 2 = ACCURACY_COARSE -->
+ <string-array name="config_testLocationProviders" translatable="false">
+ <!-- Example test network location provider
+ <item>network,false,false,false,false,true,true,true,1,2</item>
+ -->
+ </string-array>
+
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
<bool name="config_bluetooth_sco_off_call">true</bool>
@@ -1429,4 +1444,28 @@
2 - The device DOES NOT have a permanent menu key; ignore autodetection. -->
<integer name="config_overrideHasPermanentMenuKey">0</integer>
+ <!-- default window inset isRound property -->
+ <bool name="config_windowIsRound">false</bool>
+
+ <!-- Package name for default network scorer app; overridden by product overlays. -->
+ <string name="config_defaultNetworkScorerPackageName"></string>
+
+ <!-- Defines the default set of global actions. Actions may still be disabled or hidden based
+ on the current state of the device.
+ Each item must be one of the following strings:
+ "power" = Power off
+ "settings" = An action to launch settings
+ "airplane" = Airplane mode toggle
+ "bugreport" = Take bug report, if available
+ "silent" = silent mode
+ "users" = list of users
+ -->
+ <string-array translatable="false" name="config_globalActionsList">
+ <item>power</item>
+ <item>airplane</item>
+ <item>bugreport</item>
+ <item>silent</item>
+ <item>users</item>
+ </string-array>
+
</resources>
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
index 02e61e2..cebee12 100644
--- a/core/res/res/values/dimens_quantum.xml
+++ b/core/res/res/values/dimens_quantum.xml
@@ -47,4 +47,6 @@
<dimen name="text_size_menu_quantum">14sp</dimen>
<dimen name="text_size_button_quantum">14sp</dimen>
+ <dimen name="floating_window_z">16dp</dimen>
+ <dimen name="floating_window_margin">32dp</dimen>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9712c03..6491b33 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2094,7 +2094,8 @@
<public type="attr" name="banner" id="0x10103f2" />
<public type="attr" name="windowSwipeToDismiss" id="0x10103f3" />
- <public type="attr" name="isGame" />
+ <public type="attr" name="isGame" id="0x10103f4" />
+ <public type="attr" name="allowEmbedded" id="0x10103f5" />
<!-- ===============================================================
Resources added in version 21 of the platform
@@ -2153,6 +2154,7 @@
<public type="attr" name="colorPrimary" />
<public type="attr" name="colorPrimaryDark" />
<public type="attr" name="colorAccent" />
+ <public type="attr" name="nestedScrollingEnabled" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b0e1150..cb52db2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -399,6 +399,9 @@
<!-- status message in phone options dialog for when airplane mode is off -->
<string name="global_actions_airplane_mode_off_status">Airplane mode is OFF</string>
+ <!-- label for item that launches settings in phone options dialog [CHAR LIMIT=15]-->
+ <string name="global_action_settings">Settings</string>
+
<!-- Text to use when the number in a notification info is too large
(greater than status_bar_notification_info_maxnum, defined in
values/config.xml) and must be truncated. May need to be localized
@@ -1065,6 +1068,12 @@
interface of a wallpaper. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindVoiceInteraction">bind to a voice interactor</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindVoiceInteraction">Allows the holder to bind to the top-level
+ interface of a voice interaction service. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindRemoteDisplay">bind to a remote display</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
@@ -1077,6 +1086,12 @@
interface of a widget service. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindRouteProvider">bind to a route provider service</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindRouteProvider">Allows the holder to bind to any registered
+ route providers. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindDeviceAdmin">interact with a device admin</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindDeviceAdmin">Allows the holder to send intents to
@@ -2039,6 +2054,11 @@
<string name="permdesc_bindNotificationListenerService">Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindConditionProviderService">bind to a condition provider service</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindConditionProviderService">Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_invokeCarrierSetup">invoke the carrier-provided configuration app</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_invokeCarrierSetup">Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps.</string>
@@ -3788,6 +3808,8 @@
<!-- Label to show for a service that is running because it is observing
the user's notifications. -->
<string name="notification_listener_binding_label">Notification listener</string>
+ <!-- Label to show for a service that is running because it is providing conditions. -->
+ <string name="condition_provider_service_binding_label">Condition provider</string>
<!-- Do Not Translate: Alternate eri.xml -->
<string name="alternate_eri_file">/data/eri.xml</string>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index bdc7ad0..57f2443 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -480,16 +480,23 @@
<style name="Widget.Quantum.AbsListView" parent="Widget.AbsListView"/>
<style name="Widget.Quantum.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
- <item name="dropDownSelector">@drawable/list_selector_holo_dark</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
</style>
<style name="Widget.Quantum.CompoundButton" parent="Widget.CompoundButton"/>
- <style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox"/>
- <style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton"/>
+
+ <style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
+ <item name="background">?attr/selectableItemBackground</item>
+ </style>
+
+ <style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
+ <item name="background">?attr/selectableItemBackground</item>
+ </style>
<style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
<item name="button">@drawable/btn_star_quantum</item>
+ <item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.CompoundButton.Switch">
@@ -501,6 +508,7 @@
<item name="thumbTextPadding">12dip</item>
<item name="switchMinWidth">72dip</item>
<item name="switchPadding">16dip</item>
+ <item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.EditText" parent="Widget.EditText"/>
@@ -619,6 +627,7 @@
<item name="paddingStart">16dip</item>
<item name="paddingEnd">16dip</item>
<item name="mirrorForRtl">true</item>
+ <item name="background">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.RatingBar" parent="Widget.RatingBar">
@@ -645,7 +654,7 @@
<style name="Widget.Quantum.Spinner" parent="Widget.Spinner.DropDown">
<item name="background">@drawable/spinner_background_quantum</item>
- <item name="dropDownSelector">@drawable/list_selector_holo_dark</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
@@ -704,7 +713,7 @@
<style name="Widget.Quantum.QuickContactBadgeSmall.WindowLarge" parent="Widget.QuickContactBadgeSmall.WindowLarge"/>
<style name="Widget.Quantum.ListPopupWindow" parent="Widget.ListPopupWindow">
- <item name="dropDownSelector">@drawable/list_selector_holo_dark</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
@@ -842,11 +851,19 @@
<style name="Widget.Quantum.Light.AbsListView" parent="Widget.Quantum.AbsListView"/>
<style name="Widget.Quantum.Light.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
- <item name="dropDownSelector">@drawable/list_selector_holo_light</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
</style>
+ <style name="Widget.Quantum.Light.CompoundButton" parent="Widget.Quantum.CompoundButton"/>
<style name="Widget.Quantum.Light.CompoundButton.CheckBox" parent="Widget.Quantum.CompoundButton.CheckBox"/>
+ <style name="Widget.Quantum.Light.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
+ <style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
+
+ <style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch">
+ <item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
+ </style>
+
<style name="Widget.Quantum.Light.ListView.DropDown" parent="Widget.Quantum.ListView.DropDown"/>
<style name="Widget.Quantum.Light.EditText" parent="Widget.Quantum.EditText"/>
<style name="Widget.Quantum.Light.ExpandableListView" parent="Widget.Quantum.ExpandableListView"/>
@@ -916,13 +933,12 @@
<item name="maxHeight">16dip</item>
</style>
- <style name="Widget.Quantum.Light.CompoundButton.RadioButton" parent="Widget.Quantum.CompoundButton.RadioButton"/>
<style name="Widget.Quantum.Light.ScrollView" parent="Widget.Quantum.ScrollView"/>
<style name="Widget.Quantum.Light.HorizontalScrollView" parent="Widget.Quantum.HorizontalScrollView"/>
<style name="Widget.Quantum.Light.Spinner" parent="Widget.Quantum.Spinner">
<item name="background">@drawable/spinner_background_quantum</item>
- <item name="dropDownSelector">@drawable/list_selector_holo_light</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
@@ -932,7 +948,6 @@
<style name="Widget.Quantum.Light.Spinner.DropDown" parent="Widget.Quantum.Spinner.DropDown"/>
<style name="Widget.Quantum.Light.Spinner.DropDown.ActionBar" parent="Widget.Quantum.Spinner.DropDown.ActionBar"/>
- <style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.Quantum.CompoundButton.Star"/>
<style name="Widget.Quantum.Light.TabWidget" parent="Widget.Quantum.TabWidget"/>
<style name="Widget.Quantum.Light.WebTextView" parent="Widget.Quantum.WebTextView"/>
<style name="Widget.Quantum.Light.WebView" parent="Widget.Quantum.WebView"/>
@@ -947,7 +962,7 @@
<style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowLarge" parent="Widget.Quantum.QuickContactBadgeSmall.WindowLarge"/>
<style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.ListPopupWindow">
- <item name="dropDownSelector">@drawable/list_selector_holo_light</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum</item>
<item name="popupBackground">?attr/colorBackground</item>
<item name="dropDownVerticalOffset">0dip</item>
<item name="dropDownHorizontalOffset">0dip</item>
@@ -989,10 +1004,6 @@
<item name="backgroundSplit">?attr/colorPrimary</item>
</style>
- <style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch">
- <item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
- </style>
-
<style name="Widget.Quantum.Light.FastScroll" parent="Widget.Quantum.FastScroll"/>
<style name="Widget.Quantum.Light.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton">
@@ -1008,16 +1019,16 @@
<!-- Dialog styles -->
<style name="AlertDialog.Quantum" parent="AlertDialog">
- <item name="fullDark">?attr/colorBackground</item>
- <item name="topDark">?attr/colorBackground</item>
- <item name="centerDark">?attr/colorBackground</item>
- <item name="bottomDark">?attr/colorBackground</item>
- <item name="fullBright">?attr/colorBackground</item>
- <item name="topBright">?attr/colorBackground</item>
- <item name="centerBright">?attr/colorBackground</item>
- <item name="bottomBright">?attr/colorBackground</item>
- <item name="bottomMedium">?attr/colorBackground</item>
- <item name="centerMedium">?attr/colorBackground</item>
+ <item name="fullDark">@color/transparent</item>
+ <item name="topDark">@color/transparent</item>
+ <item name="centerDark">@color/transparent</item>
+ <item name="bottomDark">@color/transparent</item>
+ <item name="fullBright">@color/transparent</item>
+ <item name="topBright">@color/transparent</item>
+ <item name="centerBright">@color/transparent</item>
+ <item name="bottomBright">@color/transparent</item>
+ <item name="bottomMedium">@color/transparent</item>
+ <item name="centerMedium">@color/transparent</item>
<item name="layout">@layout/alert_dialog_quantum</item>
<item name="listLayout">@layout/select_dialog_quantum</item>
<item name="progressLayout">@layout/progress_dialog_quantum</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b0f19ec..431dab8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -291,6 +291,7 @@
<java-symbol type="bool" name="config_wifi_batched_scan_supported" />
<java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
+ <java-symbol type="bool" name="config_windowIsRound" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
@@ -986,6 +987,7 @@
<java-symbol type="array" name="config_operatorConsideredNonRoaming" />
<java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" />
<java-symbol type="array" name="config_callBarringMMI" />
+ <java-symbol type="array" name="config_globalActionsList" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="indicator_input_error" />
@@ -1229,6 +1231,7 @@
<java-symbol type="xml" name="sms_short_codes" />
<java-symbol type="xml" name="audio_assets" />
<java-symbol type="xml" name="global_keys" />
+ <java-symbol type="xml" name="default_zen_mode_config" />
<java-symbol type="raw" name="accessibility_gestures" />
<java-symbol type="raw" name="incognito_mode_start_page" />
@@ -1387,6 +1390,7 @@
<java-symbol type="string" name="global_actions_airplane_mode_on_status" />
<java-symbol type="string" name="global_actions_toggle_airplane_mode" />
<java-symbol type="string" name="global_action_bug_report" />
+ <java-symbol type="string" name="global_action_settings" />
<java-symbol type="string" name="global_action_silent_mode_off_status" />
<java-symbol type="string" name="global_action_silent_mode_on_status" />
<java-symbol type="string" name="global_action_toggle_silent_mode" />
@@ -1440,6 +1444,7 @@
<java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="array" name="config_locationProviderPackageNames" />
+ <java-symbol type="array" name="config_testLocationProviders" />
<java-symbol type="array" name="config_defaultNotificationVibePattern" />
<java-symbol type="array" name="config_notificationFallbackVibePattern" />
<java-symbol type="array" name="config_onlySingleDcAllowed" />
@@ -1459,6 +1464,7 @@
<java-symbol type="color" name="input_method_navigation_guard" />
<java-symbol type="drawable" name="ic_notification_ime_default" />
<java-symbol type="drawable" name="ic_menu_refresh" />
+ <java-symbol type="drawable" name="ic_settings" />
<java-symbol type="drawable" name="stat_notify_car_mode" />
<java-symbol type="drawable" name="stat_notify_disabled" />
<java-symbol type="drawable" name="stat_notify_disk_full" />
@@ -1574,6 +1580,7 @@
<java-symbol type="string" name="low_internal_storage_view_text" />
<java-symbol type="string" name="low_internal_storage_view_title" />
<java-symbol type="string" name="notification_listener_binding_label" />
+ <java-symbol type="string" name="condition_provider_service_binding_label" />
<java-symbol type="string" name="report" />
<java-symbol type="string" name="select_input_method" />
<java-symbol type="string" name="select_keyboard_layout_notification_title" />
@@ -1624,6 +1631,7 @@
<java-symbol type="bool" name="config_powerDecoupleAutoSuspendModeFromDisplay" />
<java-symbol type="bool" name="config_powerDecoupleInteractiveModeFromDisplay" />
<java-symbol type="string" name="config_customAdbPublicKeyConfirmationComponent" />
+ <java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
@@ -1794,6 +1802,7 @@
<java-symbol type="attr" name="amPmSelectedBackgroundColor" />
<java-symbol type="attr" name="numbersSelectorColor" />
<java-symbol type="attr" name="timePickerHeaderTimeLabelTextAppearance" />
+ <java-symbol type="attr" name="nestedScrollingEnabled" />
<java-symbol type="style" name="TextAppearance.Holo.TimePicker.TimeLabel" />
<java-symbol type="layout" name="time_picker_holo" />
<java-symbol type="layout" name="time_header_label" />
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index c2e31f4..9f76eae 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -125,7 +125,7 @@
<item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
<item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
- <item name="listChoiceBackgroundIndicator">@drawable/list_selector_holo_dark</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
<item name="activatedBackgroundIndicator">@drawable/activated_background_quantum</item>
@@ -468,7 +468,7 @@
<item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
<item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
- <item name="listChoiceBackgroundIndicator">@drawable/list_selector_holo_light</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
<item name="activatedBackgroundIndicator">@drawable/activated_background_quantum</item>
@@ -898,7 +898,7 @@
<style name="Theme.Quantum.Dialog">
<item name="windowFrame">@null</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
- <item name="windowBackground">?attr/colorBackground</item>
+ <item name="windowBackground">@drawable/dialog_background_quantum</item>
<item name="windowIsFloating">true</item>
<item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@style/Animation.Quantum.Dialog</item>
@@ -964,8 +964,6 @@
its pixels. -->
<style name="Theme.Quantum.Dialog.NoFrame">
<item name="windowBackground">@color/transparent</item>
- <item name="windowFrame">@null</item>
- <item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@null</item>
<item name="backgroundDimEnabled">false</item>
<item name="windowIsTranslucent">true</item>
@@ -981,7 +979,6 @@
<style name="Theme.Quantum.Dialog.Alert">
<item name="windowBackground">@color/transparent</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
- <item name="windowContentOverlay">@null</item>
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
@@ -1102,7 +1099,6 @@
<style name="Theme.Quantum.Light.Dialog.Alert">
<item name="windowBackground">@color/transparent</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
- <item name="windowContentOverlay">@null</item>
<item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
<item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
@@ -1112,7 +1108,6 @@
<style name="Theme.Quantum.Light.Dialog.TimePicker">
<item name="windowBackground">@color/transparent</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
- <item name="windowContentOverlay">@null</item>
</style>
<!-- Theme for a presentation window on a secondary display. -->
diff --git a/media/java/android/media/session/MediaSessionToken.aidl b/core/res/res/xml/default_zen_mode_config.xml
similarity index 62%
copy from media/java/android/media/session/MediaSessionToken.aidl
copy to core/res/res/xml/default_zen_mode_config.xml
index 5812682..1bdc1ec 100644
--- a/media/java/android/media/session/MediaSessionToken.aidl
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -1,4 +1,7 @@
-/* Copyright 2014, The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
@@ -12,7 +15,10 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+-->
-package android.media.session;
-
-parcelable MediaSessionToken;
+<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
+<zen version="1">
+ <allow calls="false" messages="false" />
+ <sleep startHour="22" startMin="0" endHour="7" endMin="0" />
+</zen>
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
index 60b6dc1..cbfa84d 100644
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ b/core/tests/bluetoothtests/AndroidManifest.xml
@@ -31,5 +31,8 @@
<instrumentation android:name="android.bluetooth.BluetoothTestRunner"
android:targetPackage="com.android.bluetooth.tests"
android:label="Bluetooth Tests" />
+ <instrumentation android:name="android.bluetooth.BluetoothInstrumentation"
+ android:targetPackage="com.android.bluetooth.tests"
+ android:label="Bluetooth Test Utils" />
</manifest>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
new file mode 100644
index 0000000..34393f9
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.bluetooth;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Bundle;
+
+public class BluetoothInstrumentation extends Instrumentation {
+
+ private BluetoothTestUtils mUtils = null;
+ private BluetoothAdapter mAdapter = null;
+ private Bundle mArgs = null;
+
+ private BluetoothTestUtils getBluetoothTestUtils() {
+ if (mUtils == null) {
+ mUtils = new BluetoothTestUtils(getContext(),
+ BluetoothInstrumentation.class.getSimpleName());
+ }
+ return mUtils;
+ }
+
+ private BluetoothAdapter getBluetoothAdapter() {
+ if (mAdapter == null) {
+ mAdapter = ((BluetoothManager)getContext().getSystemService(
+ Context.BLUETOOTH_SERVICE)).getAdapter();
+ }
+ return mAdapter;
+ }
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ super.onCreate(arguments);
+ mArgs = arguments;
+ start();
+ }
+
+ @Override
+ public void onStart() {
+ String command = mArgs.getString("command");
+ if ("enable".equals(command)) {
+ enable();
+ } else if ("disable".equals(command)) {
+ disable();
+ } else if ("unpairAll".equals(command)) {
+ unpairAll();
+ } else if ("getName".equals(command)) {
+ getName();
+ } else {
+ finish(null);
+ }
+ }
+
+ public void enable() {
+ getBluetoothTestUtils().enable(getBluetoothAdapter());
+ finish(null);
+ }
+
+ public void disable() {
+ getBluetoothTestUtils().disable(getBluetoothAdapter());
+ finish(null);
+ }
+
+ public void unpairAll() {
+ getBluetoothTestUtils().unpairAll(getBluetoothAdapter());
+ finish(null);
+ }
+
+ public void getName() {
+ String name = getBluetoothAdapter().getName();
+ Bundle bundle = new Bundle();
+ bundle.putString("name", name);
+ finish(bundle);
+ }
+
+ public void finish(Bundle result) {
+ if (result == null) {
+ result = new Bundle();
+ }
+ finish(Activity.RESULT_OK, result);
+ }
+}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index 4858be8..8fbd214 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -34,6 +34,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
public class BluetoothTestUtils extends Assert {
@@ -893,6 +894,17 @@
}
/**
+ * Deletes all pairings of remote devices
+ * @param adapter the BT adapter
+ */
+ public void unpairAll(BluetoothAdapter adapter) {
+ Set<BluetoothDevice> devices = adapter.getBondedDevices();
+ for (BluetoothDevice device : devices) {
+ unpair(adapter, device);
+ }
+ }
+
+ /**
* Connects a profile from the local device to a remote device and checks to make sure that the
* profile is connected and that the correct actions were broadcast.
*
diff --git a/core/tests/coretests/src/android/net/NetworkScorerApplicationTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
similarity index 95%
rename from core/tests/coretests/src/android/net/NetworkScorerApplicationTest.java
rename to core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index 6d5ede8..cac6b93 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerApplicationTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -33,7 +33,7 @@
import java.util.Iterator;
-public class NetworkScorerApplicationTest extends InstrumentationTestCase {
+public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
@Mock private Context mMockContext;
@Mock private PackageManager mMockPm;
@@ -64,7 +64,7 @@
setScorers(package1, package2, package3);
Iterator<String> result =
- NetworkScorerApplication.getAllValidScorers(mMockContext).iterator();
+ NetworkScorerAppManager.getAllValidScorers(mMockContext).iterator();
assertTrue(result.hasNext());
assertEquals("package1", result.next());
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 6fb8946..cd45017 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -19,12 +19,14 @@
import android.content.ContentUris;
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
import java.io.File;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
-import junit.framework.TestCase;
public class UriTest extends TestCase {
@@ -752,4 +754,54 @@
assertEquals("d e", Uri.parse("http://a/b?c=d%20e").getQueryParameter("c"));
assertEquals("d e", Uri.parse("http://a/b?c=d+e").getQueryParameter("c"));
}
+
+ public void testPathPrefixMatch() {
+ // Exact match
+ assertTrue(Uri.parse("content://com.example/path").isPathPrefixMatch(
+ Uri.parse("content://com.example/path/")));
+ assertTrue(Uri.parse("content://com.example/path").isPathPrefixMatch(
+ Uri.parse("content://com.example/path")));
+ assertTrue(Uri.parse("content://com.example///path///").isPathPrefixMatch(
+ Uri.parse("content://com.example/path/")));
+ assertTrue(Uri.parse("content://com.example/path").isPathPrefixMatch(
+ Uri.parse("content://com.example///path///")));
+
+ // Child match
+ assertTrue(Uri.parse("content://com.example/path/to/child").isPathPrefixMatch(
+ Uri.parse("content://com.example/path/")));
+ assertTrue(Uri.parse("content://com.example/path/to/child").isPathPrefixMatch(
+ Uri.parse("content://com.example/path")));
+
+ // Extra parameters
+ assertTrue(Uri.parse("content://com.example/path#fragment").isPathPrefixMatch(
+ Uri.parse("content://com.example/path/")));
+ assertTrue(Uri.parse("content://com.example/path?q=v").isPathPrefixMatch(
+ Uri.parse("content://com.example/path/")));
+ assertTrue(Uri.parse("content://com.example/path/?q=v").isPathPrefixMatch(
+ Uri.parse("content://com.example/path/")));
+
+ // Different path
+ assertFalse(Uri.parse("content://com.example/path").isPathPrefixMatch(
+ Uri.parse("content://com.example/path/deeper/")));
+ assertFalse(Uri.parse("content://com.example/path2").isPathPrefixMatch(
+ Uri.parse("content://com.example/path")));
+
+ // Top-level match
+ assertTrue(Uri.parse("content://com.example/path/").isPathPrefixMatch(
+ Uri.parse("content://com.example/")));
+ assertTrue(Uri.parse("content://com.example/path/").isPathPrefixMatch(
+ Uri.parse("content://com.example")));
+
+ // Different prefixes
+ assertFalse(Uri.parse("content://com.example/path/").isPathPrefixMatch(
+ Uri.parse("file://com.example/path/")));
+ assertFalse(Uri.parse("content://com.example/path/").isPathPrefixMatch(
+ Uri.parse("content://org.example/path/")));
+
+ // Escaping
+ assertTrue(Uri.parse("content://com.example/path path/").isPathPrefixMatch(
+ Uri.parse("content://com.example/path%20path/")));
+ assertFalse(Uri.parse("content://com.example/path/path").isPathPrefixMatch(
+ Uri.parse("content://com.example/path%2Fpath")));
+ }
}
diff --git a/data/keyboards/Vendor_1949_Product_0401.kl b/data/keyboards/Vendor_1949_Product_0401.kl
new file mode 100644
index 0000000..ab24bcd
--- /dev/null
+++ b/data/keyboards/Vendor_1949_Product_0401.kl
@@ -0,0 +1,27 @@
+# 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.
+
+# Amazon Fire TV remote
+
+key 103 DPAD_UP
+key 108 DPAD_DOWN
+key 105 DPAD_LEFT
+key 106 DPAD_RIGHT
+key 96 DPAD_CENTER
+key 158 BACK
+key 172 HOME
+key 168 MEDIA_REWIND
+key 208 MEDIA_FAST_FORWARD
+key 164 MEDIA_PLAY_PAUSE
+key 217 ASSIST
diff --git a/docs/html/design/media/dialogs_examples.png b/docs/html/design/media/dialogs_examples.png
index c136476..6ffcee2 100644
--- a/docs/html/design/media/dialogs_examples.png
+++ b/docs/html/design/media/dialogs_examples.png
Binary files differ
diff --git a/docs/html/design/media/navigation_drawer_titles_icons.png b/docs/html/design/media/navigation_drawer_titles_icons.png
index 7cf1e0c..902a72d 100644
--- a/docs/html/design/media/navigation_drawer_titles_icons.png
+++ b/docs/html/design/media/navigation_drawer_titles_icons.png
Binary files differ
diff --git a/docs/html/design/media/selection_adjusting_actions.png b/docs/html/design/media/selection_adjusting_actions.png
index 0799b6b..32a7fec 100644
--- a/docs/html/design/media/selection_adjusting_actions.png
+++ b/docs/html/design/media/selection_adjusting_actions.png
Binary files differ
diff --git a/docs/html/design/media/touch_feedback_communication.png b/docs/html/design/media/touch_feedback_communication.png
index f8162d0..1d4a9dc 100644
--- a/docs/html/design/media/touch_feedback_communication.png
+++ b/docs/html/design/media/touch_feedback_communication.png
Binary files differ
diff --git a/docs/html/design/media/ui_overview_notifications.png b/docs/html/design/media/ui_overview_notifications.png
index 6043412..7975657 100644
--- a/docs/html/design/media/ui_overview_notifications.png
+++ b/docs/html/design/media/ui_overview_notifications.png
Binary files differ
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 826dcff..a0f7ce1 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -56,6 +56,7 @@
<li><a href="#Music">Music or Video</a>
<ol>
<li><a href="#PlayMedia">Play a media file</a></li>
+ <li><a href="#PlaySearch">Play music based on a search query</a></li>
</ol>
</li>
<li><a href="#Phone">Phone</a>
@@ -1287,9 +1288,251 @@
</pre>
+<h3 id="PlaySearch">Play music based on a search query</h3>
+
+<p>To play music based on a search query, use the
+{@link android.provider.MediaStore#INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH} intent. An app may fire
+this intent in response to the user's voice command to play music. The receiving app for this
+intent performs a search within its inventory to match existing content to the given query and
+starts playing that content.</p>
+
+<p>This intent should include the {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} string
+extra, which specifies the inteded search mode. For example, the search mode can specify whether
+the search is for an artist name or song name.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.MediaStore#INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+<dl>
+<dt>{@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS MediaStore.EXTRA_MEDIA_FOCUS} (required)</dt>
+<dd>
+<p>Indicates the search mode (whether the user is looking for a particular artist, album, song,
+playlist, or radio channel). Most search modes take additional extras. For example, if the user
+is interested in listening to a particular song, the intent might have three additional extras:
+the song title, the artist, and the album. This intent supports the following search modes for
+each value of {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS}:</p>
+<dl>
+<dt><p><em>Any</em> - <code>"vnd.android.cursor.item/*"</p></code></dt>
+<dd>
+<p>Play any music. The receiving app should play some music based on a smart choice, such
+as the last playlist the user listened to.</p>
+<p>Additional extras:</p>
+<ul>
+ <li>{@link android.app.SearchManager#QUERY} (required) - An empty string. This extra is always
+ provided for backward compatibility: existing apps that do not know about search modes can
+ process this intent as an unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Unstructured</em> - <code>"vnd.android.cursor.item/*"</code></p></dt>
+<dd>
+<p>Play a particular song, album or genre from an unstructured search query. Apps may generate
+an intent with this search mode when they can't identify the type of content the user wants to
+listen to. Apps should use more specific search modes when possible.</p>
+<p>Additional extras:</p>
+<ul>
+ <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination
+ of: the artist, the album, the song name, or the genre.</li>
+</ul>
+</dd>
+<dt><p><em>Genre</em> -
+{@link android.provider.MediaStore.Audio.Genres#ENTRY_CONTENT_TYPE Audio.Genres.ENTRY_CONTENT_TYPE}</p></dt>
+<dd>
+<p>Play music of a particular genre.</p>
+<p>Additional extras:</p>
+<ul>
+ <li><code>"android.intent.extra.genre"</code> (required) - The genre.</li>
+ <li>{@link android.app.SearchManager#QUERY} (required) - The genre. This extra is always provided
+ for backward compatibility: existing apps that do not know about search modes can process
+ this intent as an unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Artist</em> -
+{@link android.provider.MediaStore.Audio.Artists#ENTRY_CONTENT_TYPE Audio.Artists.ENTRY_CONTENT_TYPE}</p></dt>
+<dd>
+<p>Play music from a particular artist.</p>
+<p>Additional extras:</p>
+<ul>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} (required) - The artist.</li>
+ <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+ <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination of
+ the artist or the genre. This extra is always provided for backward compatibility:
+ existing apps that do not know about search modes can process this intent as an unstructured
+ search.</li>
+</ul>
+</dd>
+<dt><p><em>Album</em> -
+{@link android.provider.MediaStore.Audio.Albums#ENTRY_CONTENT_TYPE Audio.Albums.ENTRY_CONTENT_TYPE}</p></dt>
+<dd>
+<p>Play music from a particular album.</p>
+<p>Additional extras:</p>
+<ul>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} (required) - The album.</li>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
+ <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+ <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination of
+ the album or the artist. This extra is always provided for backward
+ compatibility: existing apps that do not know about search modes can process this intent as an
+ unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Song</em> - <code>"vnd.android.cursor.item/audio"</code></p></dt>
+<dd>
+<p>Play a particular song.</p>
+<p>Additional extras:</p>
+<ul>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} - The album.</li>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
+ <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_TITLE} (required) - The song name.</li>
+ <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination of:
+ the album, the artist, the genre, or the title. This extra is always provided for
+ backward compatibility: existing apps that do not know about search modes can process this
+ intent as an unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Radio channel</em> - <code>"vnd.android.cursor.item/radio"</code></p></dt>
+<dd>
+<p>Play a particular radio channel or a radio channel that matches some criteria specified
+by additional extras.</p>
+<p>Additional extras:</p>
+<ul>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} - The album.</li>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
+ <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+ <li><code>"android.intent.extra.radio_channel"</code> - The radio channel.</li>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_TITLE} - The song name that the radio
+ channel is based on.</li>
+ <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination
+ of: the album, the artist, the genre, the radio channel, or the title. This extra is
+ always provided for backward compatibility: existing apps that do not know about search
+ modes can process this intent as an unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Playlist</em> - {@link android.provider.MediaStore.Audio.Playlists#ENTRY_CONTENT_TYPE Audio.Playlists.ENTRY_CONTENT_TYPE}</p></dt>
+<dd>
+<p>Play a particular playlist or a playlist that matches some criteria specified
+by additional extras.</p>
+<p>Additional extras:</p>
+<ul>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} - The album.</li>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
+ <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+ <li><code>"android.intent.extra.playlist"</code> - The playlist.</li>
+ <li>{@link android.provider.MediaStore#EXTRA_MEDIA_TITLE} - The song name that the playlist is
+ based on.</li>
+ <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination
+ of: the album, the artist, the genre, the playlist, or the title. This extra is always
+ provided for backward compatibility: existing apps that do not know about search modes can
+ process this intent as an unstructured search.</li>
+</ul>
+</dd>
+</dl>
+</dd>
+</dl>
+</dd>
+</dl>
+<p><b>Example intent:</b></p>
+<p>If the user wants to listen to a radio station that plays songs from a particular artist,
+a search app may generate the following intent:</p>
+<pre>
+public void playSearchRadioByArtist(String artist) {
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH);
+ intent.putExtra(MediaStore.EXTRA_MEDIA_FOCUS,
+ "vnd.android.cursor.item/radio");
+ intent.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist);
+ intent.putExtra(SearchManager.QUERY, artist);
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ }
+}
+</pre>
+
+<p><b>Example intent filter:</b></p>
+<pre>
+<activity ...>
+ <intent-filter>
+ <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+</activity>
+</pre>
+<p>When handling this intent, your activity should check the value of the
+{@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} extra in the incoming
+{@link android.content.Intent} to determine the search mode. Once your activity has identified
+the search mode, it should read the values of the additional extras for that particular search mode.
+With this information your app can then perform the search within its inventory to play the
+content that matches the search query. For example:</p>
+<pre>
+protected void onCreate(Bundle savedInstanceState) {
+ ...
+ Intent intent = this.getIntent();
+ if (intent.getAction().compareTo(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) == 0) {
+
+ String mediaFocus = intent.getStringExtra(MediaStore.EXTRA_MEDIA_FOCUS);
+ String query = intent.getStringExtra(SearchManager.QUERY);
+
+ // Some of these extras may not be available depending on the search mode
+ String album = intent.getStringExtra(MediaStore.EXTRA_MEDIA_ALBUM);
+ String artist = intent.getStringExtra(MediaStore.EXTRA_MEDIA_ARTIST);
+ String genre = intent.getStringExtra("android.intent.extra.genre");
+ String playlist = intent.getStringExtra("android.intent.extra.playlist");
+ String rchannel = intent.getStringExtra("android.intent.extra.radio_channel");
+ String title = intent.getStringExtra(MediaStore.EXTRA_MEDIA_TITLE);
+
+ // Determine the search mode and use the corresponding extras
+ if (mediaFocus == null) {
+ // 'Unstructured' search mode (backward compatible)
+ playUnstructuredSearch(query);
+
+ } else if (mediaFocus.compareTo("vnd.android.cursor.item/*") == 0) {
+ if (query.isEmpty()) {
+ // 'Any' search mode
+ playResumeLastPlaylist();
+ } else {
+ // 'Unstructured' search mode
+ playUnstructuredSearch(query);
+ }
+
+ } else if (mediaFocus.compareTo(MediaStore.Audio.Genres.ENTRY_CONTENT_TYPE) == 0) {
+ // 'Genre' search mode
+ playGenre(genre);
+
+ } else if (mediaFocus.compareTo(MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE) == 0) {
+ // 'Artist' search mode
+ playArtist(artist, genre);
+
+ } else if (mediaFocus.compareTo(MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE) == 0) {
+ // 'Album' search mode
+ playAlbum(album, artist);
+
+ } else if (mediaFocus.compareTo("vnd.android.cursor.item/audio") == 0) {
+ // 'Song' search mode
+ playSong(album, artist, genre, title);
+
+ } else if (mediaFocus.compareTo("vnd.android.cursor.item/radio") == 0) {
+ // 'Radio channel' search mode
+ playRadioChannel(album, artist, genre, rchannel, title);
+
+ } else if (mediaFocus.compareTo(MediaStore.Audio.Playlists.ENTRY_CONTENT_TYPE) == 0) {
+ // 'Playlist' search mode
+ playPlaylist(album, artist, genre, playlist, title);
+ }
+ }
+}
+</pre>
+
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 4903852..f09ff9e 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -899,8 +899,9 @@
{@code tools/} path:
<pre class="no-pretty-print">adb shell bmgr enable true</pre>
</li>
- <li>If using a device, open the system <b>Settings</b>, select <b>Privacy</b>, then enable
-<b>Back up my data</b> and <b>Automatic restore</b>.
+ <li>If using a device, open the system <b>Settings</b>, select
+ <b>Backup & reset</b>, then enable
+ <b>Back up my data</b> and <b>Automatic restore</b>.</li>
</ul>
</li>
<li>Open your application and initialize some data
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index a122443..a61696a 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -1126,8 +1126,8 @@
uses a string array as the data source:</p>
<pre>
-SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list,
- android.R.layout.simple_spinner_dropdown_item);
+SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this,
+ R.array.action_list, android.R.layout.simple_spinner_dropdown_item);
</pre>
<p>The {@link android.widget.ArrayAdapter#createFromResource createFromResource()} method takes
@@ -1145,7 +1145,7 @@
<item>Venus</item>
<item>Earth</item>
</string-array>
-</pre>
+</resources>
</pre>
<p>The {@link android.widget.ArrayAdapter} returned by {@link
@@ -1179,10 +1179,13 @@
public boolean onNavigationItemSelected(int position, long itemId) {
// Create new fragment from our own Fragment class
ListContentFragment newFragment = new ListContentFragment();
- FragmentTransaction ft = openFragmentTransaction();
+ FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+
// Replace whatever is in the fragment container with this fragment
- // and give the fragment a tag name equal to the string at the position selected
+ // and give the fragment a tag name equal to the string at the position
+ // selected
ft.replace(R.id.fragment_container, newFragment, strings[position]);
+
// Apply changes
ft.commit();
return true;
@@ -1210,7 +1213,8 @@
@Override
public void onAttach(Activity activity) {
// This is the first callback received; here we can set the text for
- // the fragment as defined by the tag specified during the fragment transaction
+ // the fragment as defined by the tag specified during the fragment
+ // transaction
super.onAttach(activity);
mText = getTag();
}
diff --git a/docs/html/images/activity_lifecycle.png b/docs/html/images/activity_lifecycle.png
index 71ffe9f..879f51f 100644
--- a/docs/html/images/activity_lifecycle.png
+++ b/docs/html/images/activity_lifecycle.png
Binary files differ
diff --git a/docs/html/images/admin/device-admin-activate-prompt.png b/docs/html/images/admin/device-admin-activate-prompt.png
index 1ebe719..3786788 100644
--- a/docs/html/images/admin/device-admin-activate-prompt.png
+++ b/docs/html/images/admin/device-admin-activate-prompt.png
Binary files differ
diff --git a/docs/html/images/axis_device.png b/docs/html/images/axis_device.png
index dd9c23b..f1f666a 100644
--- a/docs/html/images/axis_device.png
+++ b/docs/html/images/axis_device.png
Binary files differ
diff --git a/docs/html/images/developing/ddms-network.png b/docs/html/images/developing/ddms-network.png
index 5bf4ce6..5aa1290 100644
--- a/docs/html/images/developing/ddms-network.png
+++ b/docs/html/images/developing/ddms-network.png
Binary files differ
diff --git a/docs/html/images/developing/hv_device_window.png b/docs/html/images/developing/hv_device_window.png
index d2a1ddc..2bb80a8 100644
--- a/docs/html/images/developing/hv_device_window.png
+++ b/docs/html/images/developing/hv_device_window.png
Binary files differ
diff --git a/docs/html/images/efficient-downloads/mobile_radio_state_machine.png b/docs/html/images/efficient-downloads/mobile_radio_state_machine.png
index 98e9398..e06608b 100644
--- a/docs/html/images/efficient-downloads/mobile_radio_state_machine.png
+++ b/docs/html/images/efficient-downloads/mobile_radio_state_machine.png
Binary files differ
diff --git a/docs/html/images/fundamentals/fragments.png b/docs/html/images/fundamentals/fragments.png
index 8abaeba..cb7204b 100644
--- a/docs/html/images/fundamentals/fragments.png
+++ b/docs/html/images/fundamentals/fragments.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle.png b/docs/html/images/opengl/ogl-triangle.png
index 6fefe1f..66047ab 100644
--- a/docs/html/images/opengl/ogl-triangle.png
+++ b/docs/html/images/opengl/ogl-triangle.png
Binary files differ
diff --git a/docs/html/images/publishing/publishing_preparing.png b/docs/html/images/publishing/publishing_preparing.png
index 07fcc58..40c0ac6 100644
--- a/docs/html/images/publishing/publishing_preparing.png
+++ b/docs/html/images/publishing/publishing_preparing.png
Binary files differ
diff --git a/docs/html/images/screens_support/compat-zoom-thumb.png b/docs/html/images/screens_support/compat-zoom-thumb.png
index 9d76e20..244800b 100644
--- a/docs/html/images/screens_support/compat-zoom-thumb.png
+++ b/docs/html/images/screens_support/compat-zoom-thumb.png
Binary files differ
diff --git a/docs/html/images/sdk_manager_packages.png b/docs/html/images/sdk_manager_packages.png
index eddd80c..a0e8108 100644
--- a/docs/html/images/sdk_manager_packages.png
+++ b/docs/html/images/sdk_manager_packages.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointswindow.png b/docs/html/images/tools/as-breakpointswindow.png
index e5ae19d..a40b459 100644
--- a/docs/html/images/tools/as-breakpointswindow.png
+++ b/docs/html/images/tools/as-breakpointswindow.png
Binary files differ
diff --git a/docs/html/images/tools/as-buildvariants.png b/docs/html/images/tools/as-buildvariants.png
index 8e05a1e..a245163 100644
--- a/docs/html/images/tools/as-buildvariants.png
+++ b/docs/html/images/tools/as-buildvariants.png
Binary files differ
diff --git a/docs/html/images/tools/as-mainscreen.png b/docs/html/images/tools/as-mainscreen.png
index 6f2bc3c..da399d7 100644
--- a/docs/html/images/tools/as-mainscreen.png
+++ b/docs/html/images/tools/as-mainscreen.png
Binary files differ
diff --git a/docs/html/images/tools/as-theme-db.png b/docs/html/images/tools/as-theme-db.png
index a9e34c7..beade0d 100644
--- a/docs/html/images/tools/as-theme-db.png
+++ b/docs/html/images/tools/as-theme-db.png
Binary files differ
diff --git a/docs/html/images/tools/sdk-manager-support-libs.png b/docs/html/images/tools/sdk-manager-support-libs.png
index a44f4bb..3796800 100644
--- a/docs/html/images/tools/sdk-manager-support-libs.png
+++ b/docs/html/images/tools/sdk-manager-support-libs.png
Binary files differ
diff --git a/docs/html/images/training/app-navigation-multiple-sizes-multipane-good.png b/docs/html/images/training/app-navigation-multiple-sizes-multipane-good.png
index 1a8766f..3588318 100644
--- a/docs/html/images/training/app-navigation-multiple-sizes-multipane-good.png
+++ b/docs/html/images/training/app-navigation-multiple-sizes-multipane-good.png
Binary files differ
diff --git a/docs/html/images/training/basics/intent-chooser.png b/docs/html/images/training/basics/intent-chooser.png
index 14b6c45..8a8d33938 100644
--- a/docs/html/images/training/basics/intent-chooser.png
+++ b/docs/html/images/training/basics/intent-chooser.png
Binary files differ
diff --git a/docs/html/images/training/basics/network-settings1.png b/docs/html/images/training/basics/network-settings1.png
index 8395abc..9eaf207d 100644
--- a/docs/html/images/training/basics/network-settings1.png
+++ b/docs/html/images/training/basics/network-settings1.png
Binary files differ
diff --git a/docs/html/images/training/basics/network-settings2.png b/docs/html/images/training/basics/network-settings2.png
index 4e02c09..5f4dc63 100644
--- a/docs/html/images/training/basics/network-settings2.png
+++ b/docs/html/images/training/basics/network-settings2.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/adt-new-activity.png b/docs/html/images/training/firstapp/adt-new-activity.png
index 6d89e4b..2c32dcc 100644
--- a/docs/html/images/training/firstapp/adt-new-activity.png
+++ b/docs/html/images/training/firstapp/adt-new-activity.png
Binary files differ
diff --git a/docs/html/images/ui/clipboard/copy_paste_framework.png b/docs/html/images/ui/clipboard/copy_paste_framework.png
index 9409a5d..57facaa 100644
--- a/docs/html/images/ui/clipboard/copy_paste_framework.png
+++ b/docs/html/images/ui/clipboard/copy_paste_framework.png
Binary files differ
diff --git a/docs/html/images/ui/dialog_checkboxes.png b/docs/html/images/ui/dialog_checkboxes.png
index af84b6a..8f272e5 100644
--- a/docs/html/images/ui/dialog_checkboxes.png
+++ b/docs/html/images/ui/dialog_checkboxes.png
Binary files differ
diff --git a/docs/html/resources/articles/images/inputmethod_lifecycle_image.png b/docs/html/resources/articles/images/inputmethod_lifecycle_image.png
index a975aa7..5f7cf95 100644
--- a/docs/html/resources/articles/images/inputmethod_lifecycle_image.png
+++ b/docs/html/resources/articles/images/inputmethod_lifecycle_image.png
Binary files differ
diff --git a/docs/html/resources/articles/images/spellcheck_lifecycle.png b/docs/html/resources/articles/images/spellcheck_lifecycle.png
index 4349d63..00bd461 100644
--- a/docs/html/resources/articles/images/spellcheck_lifecycle.png
+++ b/docs/html/resources/articles/images/spellcheck_lifecycle.png
Binary files differ
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index e4cf1bc..e12dfd8 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
page.title=Installing the Eclipse Plugin
-adt.zip.version=22.6.2
-adt.zip.download=ADT-22.6.2.zip
-adt.zip.bytes=14586842
-adt.zip.checksum=f660959fa71262b4285bcb64be284bf5
+adt.zip.version=22.6.3
+adt.zip.download=ADT-22.6.3.zip
+adt.zip.bytes=14590813
+adt.zip.checksum=3982259fd2cc81e53bbbe05dcd6529a7
@jd:body
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index d106f4a..124e58d 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -53,10 +53,49 @@
<p>For a summary of all known issues in ADT, see <a
href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
-
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>ADT 22.6.3</a> <em>(April 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+<dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Java 1.6 or higher is required.</li>
+ <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+ <li>This version of ADT is designed for use with
+ <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.6.3</a>.
+ If you haven't already installed SDK Tools r22.6.3 into your SDK, use the
+ Android SDK Manager to do so.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed a problem where the AVD manager allowed creating Android Wear virtual devices
+ with a target API Level lower than 19.</li>
+ <li>Fixed the description of Android Wear system images in the SDK Manager.</li>
+ </ul>
+ </dd>
+
+ <dt>Known Issues:</dt>
+ <dd>
+ <p>When you create an Android Wear virtual device in the AVD manager, a target API Level
+ lower than 19 may be selected by default. Make sure you select the target API Level 19
+ when creating Android Wear virtual devices.</p>
+ </dd>
+</dl>
+</div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>ADT 22.6.2</a> <em>(March 2014)</em>
</p>
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index a22dc90..0ac1881 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -245,8 +245,8 @@
but it always increases your app complexity. In general, you should only use the NDK
if it is essential to your app—never because you simply prefer to program in C/C++.</p>
- <p>Typical good candidates for the NDK are self-contained, CPU-intensive operations that don't
- allocate much memory, such as signal processing, physics simulation, and so on. When examining
+ <p>Typical good candidates for the NDK are CPU-intensive workloads such as game engines,
+ signal processing, physics simulation, and so on. When examining
whether or not you should develop in native code, think about your requirements and see if the
Android framework APIs provide the functionality that you need.</p>
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 14b5505..9b06a9d 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,6 +28,46 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 22.6.3</a> <em>(April 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 18 or later.</li>
+ <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+ designed for use with ADT 22.6.3 and later. If you haven't already, update your
+ <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.6.3.</li>
+ <li>If you are developing outside Eclipse, you must have
+ <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed a problem where the AVD manager allowed creating Android Wear virtual devices
+ with a target API Level lower than 19.</li>
+ <li>Fixed the description of Android Wear system images in the SDK Manager.</li>
+ </ul>
+ </dd>
+
+ <dt>Known Issues:</dt>
+ <dd>
+ <p>When you create an Android Wear virtual device in the AVD manager, a target API Level
+ lower than 19 may be selected by default. Make sure you select the target API Level 19
+ when creating Android Wear virtual devices.</p>
+ </dd>
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>SDK Tools, Revision 22.6.2</a> <em>(March 2014)</em>
</p>
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 1252ee2..ae3eae1 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -168,21 +168,10 @@
}
/**
- * Gets the native canvas pointer.
- *
- * @return The native pointer.
- *
- * @hide
- */
- public long getNativeCanvas() {
- return mNativeCanvas;
- }
-
- /**
* Returns null.
- *
+ *
* @deprecated This method is not supported and should not be invoked.
- *
+ *
* @hide
*/
@Deprecated
@@ -233,14 +222,14 @@
mBitmap = bitmap;
}
-
+
/**
* Set the viewport dimensions if this canvas is GL based. If it is not,
* this method is ignored and no exception is thrown.
*
* @param width The width of the viewport
* @param height The height of the viewport
- *
+ *
* @hide
*/
public void setViewport(int width, int height) {
@@ -389,7 +378,14 @@
paint != null ? paint.mNativePaint : 0,
saveFlags);
}
-
+
+ /**
+ * Convenience for saveLayer(bounds, paint, {@link #ALL_SAVE_FLAG})
+ */
+ public int saveLayer(RectF bounds, Paint paint) {
+ return saveLayer(bounds, paint, ALL_SAVE_FLAG);
+ }
+
/**
* Helper version of saveLayer() that takes 4 values rather than a RectF.
*/
@@ -401,6 +397,13 @@
}
/**
+ * Convenience for saveLayer(left, top, right, bottom, paint, {@link #ALL_SAVE_FLAG})
+ */
+ public int saveLayer(float left, float top, float right, float bottom, Paint paint) {
+ return saveLayer(left, top, right, bottom, paint, ALL_SAVE_FLAG);
+ }
+
+ /**
* This behaves the same as save(), but in addition it allocates an
* offscreen bitmap. All drawing calls are directed there, and only when
* the balancing call to restore() is made is that offscreen transfered to
@@ -420,7 +423,14 @@
alpha = Math.min(255, Math.max(0, alpha));
return native_saveLayerAlpha(mNativeCanvas, bounds, alpha, saveFlags);
}
-
+
+ /**
+ * Convenience for saveLayerAlpha(bounds, alpha, {@link #ALL_SAVE_FLAG})
+ */
+ public int saveLayerAlpha(RectF bounds, int alpha) {
+ return saveLayerAlpha(bounds, alpha, ALL_SAVE_FLAG);
+ }
+
/**
* Helper for saveLayerAlpha() that takes 4 values instead of a RectF.
*/
@@ -431,6 +441,13 @@
}
/**
+ * Helper for saveLayerAlpha(left, top, right, bottom, alpha, {@link #ALL_SAVE_FLAG})
+ */
+ public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha) {
+ return saveLayerAlpha(left, top, right, bottom, alpha, ALL_SAVE_FLAG);
+ }
+
+ /**
* This call balances a previous call to save(), and is used to remove all
* modifications to the matrix/clip state since the last save call. It is
* an error to call restore() more times than save() was called.
@@ -1058,11 +1075,20 @@
* @param paint The paint used to draw the roundRect
*/
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
- if (rect == null) {
- throw new NullPointerException();
- }
- native_drawRoundRect(mNativeCanvas, rect, rx, ry,
- paint.mNativePaint);
+ drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
+ }
+
+ /**
+ * Draw the specified round-rect using the specified paint. The roundrect
+ * will be filled or framed based on the Style in the paint.
+ *
+ * @param rx The x-radius of the oval used to round the corners
+ * @param ry The y-radius of the oval used to round the corners
+ * @param paint The paint used to draw the roundRect
+ */
+ public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ Paint paint) {
+ native_drawRoundRect(mNativeCanvas, left, top, right, bottom, rx, ry, paint.mNativePaint);
}
/**
@@ -1799,8 +1825,8 @@
boolean useCenter,
long nativePaint);
private static native void native_drawRoundRect(long nativeCanvas,
- RectF rect, float rx,
- float ry, long nativePaint);
+ float left, float top, float right, float bottom,
+ float rx, float ry, long nativePaint);
private static native void native_drawPath(long nativeCanvas,
long nativePath,
long nativePaint);
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 4ea7ec7..b5c0801 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -16,18 +16,21 @@
package android.graphics;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Drawable;
import android.view.View;
/**
- * Defines an area of content.
+ * Defines a simple shape, used for bounding graphical regions.
*
- * Can be used with a View or Drawable to drive the shape of shadows cast by a
- * View, and allowing Views to clip inner content.
+ * Can be used with a View, or computed by a Drawable, to drive the shape of shadows cast by a
+ * View.
*
* @see View#setOutline(Outline)
- * @see View#setClipToOutline(boolean)
+ * @see Drawable#getOutline(Outline)
*/
-public class Outline {
+public final class Outline {
/** @hide */
public Rect mRect;
@@ -44,46 +47,74 @@
public Outline() {}
/**
+ * Constructs an Outline with a copy of the data in src.
+ */
+ public Outline(@Nullable Outline src) {
+ set(src);
+ }
+
+ /** @hide */
+ public void markInvalid() {
+ mRadius = 0;
+ mRect = null;
+ mPath = null;
+ }
+
+ /**
* Returns whether the Outline is valid for use with a View.
* <p>
* Outlines are invalid when constructed until a setter method is called.
*/
- public final boolean isValid() {
+ public boolean isValid() {
return mRect != null || mPath != null;
}
/**
- * @hide
- */
- public final boolean canClip() {
- return mPath == null;
- }
-
- /**
* Replace the contents of this Outline with the contents of src.
+ *
+ * @param src Source outline to copy from.
*/
- public void set(Outline src) {
- if (src.mPath != null) {
- if (mPath == null) {
- mPath = new Path();
- }
- mPath.set(src.mPath);
+ public void set(@Nullable Outline src) {
+ if (src == null) {
+ mRadius = 0;
mRect = null;
- }
- if (src.mRect != null) {
- if (mRect == null) {
- mRect = new Rect();
+ mPath = null;
+ } else {
+ if (src.mPath != null) {
+ if (mPath == null) {
+ mPath = new Path();
+ }
+ mPath.set(src.mPath);
+ mRect = null;
}
- mRect.set(src.mRect);
+ if (src.mRect != null) {
+ if (mRect == null) {
+ mRect = new Rect();
+ }
+ mRect.set(src.mRect);
+ }
+ mRadius = src.mRadius;
}
- mRadius = src.mRadius;
}
/**
* Sets the Outline to the rounded rect defined by the input rect, and corner radius.
- * <p>
- * Outlines produced by this method support
- * {@link View#setClipToOutline(boolean) View clipping.}
+ */
+ public void setRect(int left, int top, int right, int bottom) {
+ setRoundRect(left, top, right, bottom, 0.0f);
+ }
+
+ /**
+ * Convenience for {@link #setRect(int, int, int, int)}
+ */
+ public void setRect(@NonNull Rect rect) {
+ setRect(rect.left, rect.top, rect.right, rect.bottom);
+ }
+
+ /**
+ * Sets the Outline to the rounded rect defined by the input rect, and corner radius.
+ *
+ * Passing a zero radius is equivalent to calling {@link #setRect(int, int, int, int)}
*/
public void setRoundRect(int left, int top, int right, int bottom, float radius) {
if (mRect == null) mRect = new Rect();
@@ -93,11 +124,33 @@
}
/**
- * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}.
- *
- * @hide
+ * Convenience for {@link #setRoundRect(int, int, int, int, float)}
*/
- public void setConvexPath(Path convexPath) {
+ public void setRoundRect(@NonNull Rect rect, float radius) {
+ setRoundRect(rect.left, rect.top, rect.right, rect.bottom, radius);
+ }
+
+ /**
+ * Sets the outline to the oval defined by input rect.
+ */
+ public void setOval(int left, int top, int right, int bottom) {
+ mRect = null;
+ if (mPath == null) mPath = new Path();
+ mPath.reset();
+ mPath.addOval(left, top, right, bottom, Path.Direction.CW);
+ }
+
+ /**
+ * Convenience for {@link #setOval(int, int, int, int)}
+ */
+ public void setOval(@NonNull Rect rect) {
+ setOval(rect.left, rect.top, rect.right, rect.bottom);
+ }
+
+ /**
+ * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}.
+ */
+ public void setConvexPath(@NonNull Path convexPath) {
if (!convexPath.isConvex()) {
throw new IllegalArgumentException("path must be convex");
}
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index c07a6da..c600f47 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -499,11 +499,7 @@
* @param dir The direction to wind the rectangle's contour
*/
public void addRect(RectF rect, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
- detectSimplePath(rect.left, rect.top, rect.right, rect.bottom, dir);
- native_addRect(mNativePath, rect, dir.nativeInt);
+ addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
}
/**
@@ -527,11 +523,17 @@
* @param dir The direction to wind the oval's contour
*/
public void addOval(RectF oval, Direction dir) {
- if (oval == null) {
- throw new NullPointerException("need oval parameter");
- }
+ addOval(oval.left, oval.top, oval.right, oval.bottom, dir);
+ }
+
+ /**
+ * Add a closed oval contour to the path
+ *
+ * @param dir The direction to wind the oval's contour
+ */
+ public void addOval(float left, float top, float right, float bottom, Direction dir) {
isSimplePath = false;
- native_addOval(mNativePath, oval, dir.nativeInt);
+ native_addOval(mNativePath, left, top, right, bottom, dir.nativeInt);
}
/**
@@ -756,10 +758,10 @@
private static native void native_arcTo(long nPath, RectF oval,
float startAngle, float sweepAngle, boolean forceMoveTo);
private static native void native_close(long nPath);
- private static native void native_addRect(long nPath, RectF rect, int dir);
private static native void native_addRect(long nPath, float left, float top,
float right, float bottom, int dir);
- private static native void native_addOval(long nPath, RectF oval, int dir);
+ private static native void native_addOval(long nPath, float left, float top,
+ float right, float bottom, int dir);
private static native void native_addCircle(long nPath, float x, float y, float radius, int dir);
private static native void native_addArc(long nPath, RectF oval,
float startAngle, float sweepAngle);
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 66a88a2..60b4615 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -484,6 +484,15 @@
copyBounds(mDstRect);
}
+ final int restoreAlpha;
+ if (state.mBaseAlpha != 1.0f) {
+ final Paint p = getPaint();
+ restoreAlpha = p.getAlpha();
+ p.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
+ } else {
+ restoreAlpha = -1;
+ }
+
final boolean clearColorFilter;
if (mTintFilter != null && paint.getColorFilter() == null) {
paint.setColorFilter(mTintFilter);
@@ -537,6 +546,10 @@
if (clearColorFilter) {
paint.setColorFilter(null);
}
+
+ if (restoreAlpha >= 0) {
+ paint.setAlpha(restoreAlpha);
+ }
}
@Override
@@ -762,6 +775,10 @@
paint.setDither(dither);
}
+ if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_alpha] == 0) {
+ state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, 1.0f);
+ }
+
if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_gravity] == 0) {
final int gravity = a.getInt(
R.styleable.BitmapDrawable_gravity, Gravity.FILL);
@@ -818,6 +835,10 @@
paint.setDither(dither);
}
+ if (a.hasValue(R.styleable.BitmapDrawable_alpha)) {
+ state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, state.mBaseAlpha);
+ }
+
if (a.hasValue(R.styleable.BitmapDrawable_gravity)) {
final int gravity = a.getInt(
R.styleable.BitmapDrawable_gravity, Gravity.FILL);
@@ -933,6 +954,7 @@
int[] mThemeAttrs;
int mChangingConfigurations;
int mGravity = Gravity.FILL;
+ float mBaseAlpha = 1.0f;
Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
Shader.TileMode mTileModeX = null;
Shader.TileMode mTileModeY = null;
@@ -954,6 +976,7 @@
mTileModeX = bitmapState.mTileModeX;
mTileModeY = bitmapState.mTileModeY;
mTargetDensity = bitmapState.mTargetDensity;
+ mBaseAlpha = bitmapState.mBaseAlpha;
mPaint = new Paint(bitmapState.mPaint);
mRebuildShader = bitmapState.mRebuildShader;
mAutoMirrored = bitmapState.mAutoMirrored;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 21cd5db..b9d5e19 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -518,9 +518,16 @@
public void removeHotspot(int key) {}
/**
- * Removes all hotspots from the drawable.
+ * Immediately removes all hotspots from the drawable.
*/
public void clearHotspots() {}
+
+ /**
+ * Sets the bounds to which hotspots are constrained.
+ *
+ * @hide until we finalize these APIs
+ */
+ public void setHotspotBounds(int left, int top, int right, int bottom) {}
/**
* Whether this drawable requests projection.
@@ -857,22 +864,21 @@
}
/**
- * Returns the outline for this drawable if defined, null if not.
+ * Called to get the drawable to populate the Outline.
* <p>
- * This method will be called by a View on its background Drawable after
- * bounds change, if the View's Outline isn't set explicitly. This allows
- * the background Drawable to provide the shape of the shadow casting
- * portion of the View. It can also serve to clip the area of the View if
- * if {@link View#setClipToOutline(boolean)} is set on the View.
- * <p>
- * The Outline queried by the View will not be modified, and is treated as
- * a static shape that only needs to be requeried when the drawable's bounds
- * change.
+ * This method will be called by a View on its background Drawable after bounds change, or its
+ * Drawable is invalidated, if the View's Outline isn't set explicitly. This allows the
+ * background Drawable to define the shape of the shadow cast by the View.
*
- * @see View#setOutline(android.view.Outline)
- * @see View#setClipToOutline(boolean)
+ * The default behavior defines the outline to be the bounding rectangle. Subclasses that wish
+ * to convey a different shape must override this method.
+ *
+ * @see View#setOutline(android.graphics.Outline)
*/
- public Outline getOutline() { return null; }
+ public boolean getOutline(Outline outline) {
+ outline.setRect(getBounds());
+ return true;
+ }
/**
* Make this drawable mutable. This operation cannot be reversed. A mutable
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 05df3bc..1f8b51d 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -238,6 +238,35 @@
}
@Override
+ public void setHotspot(int key, float x, float y) {
+ if (mCurrDrawable != null) {
+ mCurrDrawable.setHotspot(key, x, y);
+ }
+ }
+
+ @Override
+ public void removeHotspot(int key) {
+ if (mCurrDrawable != null) {
+ mCurrDrawable.removeHotspot(key);
+ }
+ }
+
+ @Override
+ public void clearHotspots() {
+ if (mCurrDrawable != null) {
+ mCurrDrawable.clearHotspots();
+ }
+ }
+
+ @Override
+ public boolean supportsHotspots() {
+ if (mCurrDrawable != null) {
+ return mCurrDrawable.supportsHotspots();
+ }
+ return false;
+ }
+
+ @Override
protected boolean onStateChange(int[] state) {
if (mLastDrawable != null) {
return mLastDrawable.setState(state);
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 1b5cefe..dc06350 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -139,8 +139,7 @@
private final Path mPath = new Path();
private final RectF mRect = new RectF();
- private Outline mOutline;
-
+
private Paint mLayerPaint; // internal, used if we use saveLayer()
private boolean mRectIsDirty; // internal state
private boolean mMutated;
@@ -573,15 +572,11 @@
mStrokePaint.setColorFilter(mColorFilter);
}
}
-
+
switch (st.mShape) {
case RECTANGLE:
if (st.mRadiusArray != null) {
- if (mPathIsDirty || mRectIsDirty) {
- mPath.reset();
- mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
- mPathIsDirty = mRectIsDirty = false;
- }
+ buildPathIfDirty();
canvas.drawPath(mPath, mFillPaint);
if (haveStroke) {
canvas.drawPath(mPath, mStrokePaint);
@@ -638,7 +633,16 @@
}
}
}
-
+
+ private void buildPathIfDirty() {
+ final GradientState st = mGradientState;
+ if (mPathIsDirty || mRectIsDirty) {
+ mPath.reset();
+ mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
+ mPathIsDirty = mRectIsDirty = false;
+ }
+ }
+
private Path buildRing(GradientState st) {
if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
mPathIsDirty = false;
@@ -862,7 +866,7 @@
float x0, x1, y0, y1;
if (st.mGradient == LINEAR_GRADIENT) {
- final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
+ final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
switch (st.mOrientation) {
case TOP_BOTTOM:
x0 = r.left; y0 = r.top;
@@ -1428,42 +1432,40 @@
}
@Override
- public Outline getOutline() {
+ public boolean getOutline(Outline outline) {
final GradientState st = mGradientState;
final Rect bounds = getBounds();
switch (st.mShape) {
case RECTANGLE:
if (st.mRadiusArray != null) {
- return null;
+ buildPathIfDirty();
+ outline.setConvexPath(mPath);
+ return true;
}
+
float rad = 0;
if (st.mRadius > 0.0f) {
// clamp the radius based on width & height, matching behavior in draw()
rad = Math.min(st.mRadius,
Math.min(bounds.width(), bounds.height()) * 0.5f);
}
- if (mOutline == null) {
- mOutline = new Outline();
- }
- mOutline.setRoundRect(bounds.left, bounds.top,
- bounds.right, bounds.bottom, rad);
- return mOutline;
- case LINE: {
+ outline.setRoundRect(bounds, rad);
+ return true;
+ case OVAL:
+ outline.setOval(bounds);
+ return true;
+ case LINE:
float halfStrokeWidth = mStrokePaint.getStrokeWidth() * 0.5f;
float centerY = bounds.centerY();
int top = (int) Math.floor(centerY - halfStrokeWidth);
int bottom = (int) Math.ceil(centerY + halfStrokeWidth);
- if (mOutline == null) {
- mOutline = new Outline();
- }
- mOutline.setRoundRect(bounds.left, top, bounds.right, bottom, 0);
- return mOutline;
- }
+ outline.setRect(bounds.left, top, bounds.right, bottom);
+ return true;
default:
// TODO: investigate
- return null;
+ return false;
}
}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index b366987..639d719 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -290,6 +290,26 @@
return false;
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isProjected() {
+ if (super.isProjected()) {
+ return true;
+ }
+
+ final ChildDrawable[] layers = mLayerState.mChildren;
+ final int N = mLayerState.mNum;
+ for (int i = 0; i < N; i++) {
+ if (layers[i].mDrawable.isProjected()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
/**
* Add a new layer to this drawable. The new layer is identified by an id.
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 3e9ca0a..21992ce 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -241,6 +241,15 @@
canvas.scale(-1.0f, 1.0f);
}
+ final int restoreAlpha;
+ if (mNinePatchState.mBaseAlpha != 1.0f) {
+ final Paint p = getPaint();
+ restoreAlpha = p.getAlpha();
+ p.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f));
+ } else {
+ restoreAlpha = -1;
+ }
+
mNinePatch.draw(canvas, bounds, mPaint);
if (needsMirroring) {
@@ -250,6 +259,10 @@
if (clearColorFilter) {
mPaint.setColorFilter(null);
}
+
+ if (restoreAlpha >= 0) {
+ mPaint.setAlpha(restoreAlpha);
+ }
}
@Override
@@ -491,6 +504,10 @@
}
}
+ if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_alpha] == 0) {
+ ninePatchState.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, 1.0f);
+ }
+
// Apply the constant state to the paint.
initializeWithState(ninePatchState, r);
@@ -584,6 +601,10 @@
}
}
+ if (a.hasValue(R.styleable.NinePatchDrawable_alpha)) {
+ state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, 1.0f);
+ }
+
// Apply the constant state to the paint.
initializeWithState(state, r);
@@ -689,12 +710,13 @@
Mode mTintMode = Mode.SRC_IN;
Rect mPadding;
Insets mOpticalInsets;
+ float mBaseAlpha = 1.0f;
boolean mDither;
int[] mThemeAttrs;
int mChangingConfigurations;
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
boolean mAutoMirrored;
-
+
NinePatchState() {
// Empty constructor.
}
@@ -726,6 +748,7 @@
mThemeAttrs = state.mThemeAttrs;
mPadding = state.mPadding;
mOpticalInsets = state.mOpticalInsets;
+ mBaseAlpha = state.mBaseAlpha;
mDither = state.mDither;
mChangingConfigurations = state.mChangingConfigurations;
mTargetDensity = state.mTargetDensity;
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 03dd841..e3f57e9 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -62,27 +62,31 @@
/** Whether the center is within the parent bounds. */
private boolean mInside;
+
+ /** Whether to pulse this ripple. */
+ boolean mPulse;
/** Enter state. A value in [0...1] or -1 if not set. */
- private float mEnterState = -1;
+ float mEnterState = -1;
/** Exit state. A value in [0...1] or -1 if not set. */
- private float mExitState = -1;
+ float mExitState = -1;
/** Outside state. A value in [0...1] or -1 if not set. */
- private float mOutsideState = -1;
+ float mOutsideState = -1;
/** Pulse state. A value in [0...1] or -1 if not set. */
- private float mPulseState = -1;
+ float mPulseState = -1;
/**
* Creates a new ripple with the specified parent bounds, padding, initial
* position, and screen density.
*/
- public Ripple(Rect bounds, Rect padding, float x, float y, float density) {
+ public Ripple(Rect bounds, Rect padding, float x, float y, float density, boolean pulse) {
mBounds = bounds;
mPadding = padding;
mInside = mBounds.contains((int) x, (int) y);
+ mPulse = pulse;
mX = x;
mY = y;
@@ -115,6 +119,16 @@
}
}
+ public void onBoundsChanged() {
+ final boolean inside = mBounds.contains((int) mX, (int) mY);
+ if (mInside != inside) {
+ if (mAnimator != null) {
+ mAnimator.outside();
+ }
+ mInside = inside;
+ }
+ }
+
public RippleAnimator animate() {
if (mAnimator == null) {
mAnimator = new RippleAnimator(this);
@@ -125,8 +139,8 @@
public boolean draw(Canvas c, Paint p) {
final Rect bounds = mBounds;
final Rect padding = mPadding;
- final float dX = Math.max(mX, bounds.right - mX);
- final float dY = Math.max(mY, bounds.bottom - mY);
+ final float dX = Math.max(mX - bounds.left, bounds.right - mX);
+ final float dY = Math.max(mY - bounds.top, bounds.bottom - mY);
final int maxRadius = (int) Math.ceil(Math.sqrt(dX * dX + dY * dY));
final float enterState = mEnterState;
@@ -308,9 +322,11 @@
MathUtils.constrain((currentTime - mOutsideTime) / (float) OUTSIDE_DURATION, 0, 1));
// Pulse is a little more complicated.
- final long pulseTime = (currentTime - mEnterTime - ENTER_DURATION - PULSE_DELAY);
- mTarget.mPulseState = pulseTime < 0 ? -1
- : (pulseTime % (PULSE_INTERVAL + PULSE_DURATION)) / (float) PULSE_DURATION;
+ if (mTarget.mPulse) {
+ final long pulseTime = (currentTime - mEnterTime - ENTER_DURATION - PULSE_DELAY);
+ mTarget.mPulseState = pulseTime < 0 ? -1
+ : (pulseTime % (PULSE_INTERVAL + PULSE_DURATION)) / (float) PULSE_DURATION;
+ }
}
}
}
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 96309f9..61b1b85 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -21,6 +21,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
@@ -496,6 +497,16 @@
}
@Override
+ public boolean getOutline(Outline outline) {
+ if (mShapeState.mShape == null) {
+ // don't publish outline without a shape
+ return false;
+ }
+
+ return mShapeState.mShape.getOutline(outline);
+ }
+
+ @Override
public ConstantState getConstantState() {
mShapeState.mChangingConfigurations = getChangingConfigurations();
return mShapeState;
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 5f59467..824e108 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -25,12 +25,13 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
-import android.graphics.drawable.Ripple.RippleAnimator;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.Ripple.RippleAnimator;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.SparseArray;
import com.android.internal.R;
@@ -39,12 +40,15 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.Arrays;
/**
* Documentation pending.
*/
public class TouchFeedbackDrawable extends LayerDrawable {
+ private static final String LOG_TAG = TouchFeedbackDrawable.class.getSimpleName();
private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
+ private static final PorterDuffXfermode SRC_OVER = new PorterDuffXfermode(Mode.SRC_OVER);
/** The maximum number of ripples supported. */
private static final int MAX_RIPPLES = 10;
@@ -52,6 +56,9 @@
private final Rect mTempRect = new Rect();
private final Rect mPaddingRect = new Rect();
+ /** Current ripple effect bounds, used to constrain ripple effects. */
+ private final Rect mHotspotBounds = new Rect();
+
/** Current drawing bounds, used to compute dirty region. */
private final Rect mDrawingBounds = new Rect();
@@ -82,6 +89,9 @@
/** Whether the animation runnable has been posted. */
private boolean mAnimating;
+ /** Whether bounds are being overridden. */
+ private boolean mOverrideBounds;
+
TouchFeedbackDrawable() {
this(new TouchFeedbackState(null, null, null), null, null);
}
@@ -96,6 +106,26 @@
protected boolean onStateChange(int[] stateSet) {
super.onStateChange(stateSet);
+ // TODO: Implicitly tie states to ripple IDs. For now, just clear
+ // focused and pressed if they aren't in the state set.
+ boolean hasFocused = false;
+ boolean hasPressed = false;
+ for (int i = 0; i < stateSet.length; i++) {
+ if (stateSet[i] == R.attr.state_pressed) {
+ hasPressed = true;
+ } else if (stateSet[i] == R.attr.state_focused) {
+ hasFocused = true;
+ }
+ }
+
+ if (!hasPressed) {
+ removeHotspot(R.attr.state_pressed);
+ }
+
+ if (!hasFocused) {
+ removeHotspot(R.attr.state_focused);
+ }
+
if (mRipplePaint != null && mState.mTint != null) {
final ColorStateList stateList = mState.mTint;
final int newColor = stateList.getColorForState(stateSet, 0);
@@ -110,6 +140,47 @@
return false;
}
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+
+ if (!mOverrideBounds) {
+ mHotspotBounds.set(bounds);
+ }
+
+ onHotspotBoundsChange();
+ }
+
+ private void onHotspotBoundsChange() {
+ final int x = mHotspotBounds.centerX();
+ final int y = mHotspotBounds.centerY();
+ final int N = mActiveRipplesCount;
+ for (int i = 0; i < N; i++) {
+ if (mState.mPinned) {
+ mActiveRipples[i].move(x, y);
+ }
+ mActiveRipples[i].onBoundsChanged();
+ }
+ }
+
+ @Override
+ public boolean setVisible(boolean visible, boolean restart) {
+ if (!visible) {
+ if (mTouchedRipples != null) {
+ mTouchedRipples.clear();
+ }
+
+ if (mActiveRipplesCount > 0) {
+ Arrays.fill(mActiveRipples, null);
+ mActiveRipplesCount = 0;
+ mAnimating = false;
+ unscheduleSelf(mAnimationRunnable);
+ }
+ }
+
+ return super.setVisible(visible, restart);
+ }
+
/**
* @hide
*/
@@ -167,6 +238,27 @@
super.inflate(r, parser, attrs, theme);
setTargetDensity(r.getDisplayMetrics());
+
+ // Find the mask
+ final int N = getNumberOfLayers();
+ for (int i = 0; i < N; i++) {
+ if (mLayerState.mChildren[i].mId == R.id.mask) {
+ mState.mMask = mLayerState.mChildren[i].mDrawable;
+ }
+ }
+ }
+
+ @Override
+ public boolean setDrawableByLayerId(int id, Drawable drawable) {
+ if (super.setDrawableByLayerId(id, drawable)) {
+ if (id == R.id.mask) {
+ mState.mMask = drawable;
+ }
+
+ return true;
+ }
+
+ return false;
}
/**
@@ -261,23 +353,35 @@
mActiveRipples = new Ripple[MAX_RIPPLES];
}
+ if (mActiveRipplesCount >= MAX_RIPPLES) {
+ Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+ return;
+ }
+
final Ripple ripple = mTouchedRipples.get(id);
if (ripple == null) {
- final Rect bounds = getBounds();
final Rect padding = mPaddingRect;
getPadding(padding);
+ final Rect bounds = mHotspotBounds;
if (mState.mPinned) {
x = bounds.exactCenterX();
y = bounds.exactCenterY();
}
- final Ripple newRipple = new Ripple(bounds, padding, x, y, mDensity);
+ // TODO: Clean this up in the API.
+ final boolean pulse = (id != R.attr.state_focused);
+ final Ripple newRipple = new Ripple(bounds, padding, x, y, mDensity, pulse);
newRipple.animate().enter();
mActiveRipples[mActiveRipplesCount++] = newRipple;
mTouchedRipples.put(id, newRipple);
- } else if (!mState.mPinned) {
+ } else if (mState.mPinned) {
+ final Rect bounds = mHotspotBounds;
+ x = bounds.exactCenterX();
+ y = bounds.exactCenterY();
+ ripple.move(x, y);
+ } else {
ripple.move(x, y);
}
@@ -307,6 +411,7 @@
final int n = mTouchedRipples.size();
for (int i = 0; i < n; i++) {
+ // TODO: Use a fast exit, maybe just fade out?
mTouchedRipples.valueAt(i).animate().exit();
}
@@ -317,6 +422,16 @@
}
/**
+ * @hide
+ */
+ @Override
+ public void setHotspotBounds(int left, int top, int right, int bottom) {
+ mOverrideBounds = true;
+ mHotspotBounds.set(left, top, right, bottom);
+ onHotspotBoundsChange();
+ }
+
+ /**
* Schedules the next animation, if necessary.
*/
private void scheduleAnimation() {
@@ -342,100 +457,139 @@
@Override
public void draw(Canvas canvas) {
- final boolean projected = getNumberOfLayers() == 0;
+ final int N = mLayerState.mNum;
+ final Rect bounds = getBounds();
+ final ChildDrawable[] array = mLayerState.mChildren;
+ final boolean maskOnly = mState.mMask != null && N == 1;
+
+ int restoreToCount = drawRippleLayer(canvas, bounds, maskOnly);
+
+ if (restoreToCount >= 0) {
+ // We have a ripple layer that contains ripples. If we also have an
+ // explicit mask drawable, apply it now using DST_IN blending.
+ if (mState.mMask != null) {
+ canvas.saveLayer(bounds.left, bounds.top, bounds.right,
+ bounds.bottom, getMaskingPaint(DST_IN));
+ mState.mMask.draw(canvas);
+ canvas.restoreToCount(restoreToCount);
+ restoreToCount = -1;
+ }
+
+ // If there's more content, we need an extra masking layer to merge
+ // the ripples over the content.
+ if (!maskOnly) {
+ final PorterDuffXfermode xfermode = mState.getTintXfermodeInverse();
+ final int count = canvas.saveLayer(bounds.left, bounds.top,
+ bounds.right, bounds.bottom, getMaskingPaint(xfermode));
+ if (restoreToCount < 0) {
+ restoreToCount = count;
+ }
+ }
+ }
+
+ // Draw everything except the mask.
+ for (int i = 0; i < N; i++) {
+ if (array[i].mId != R.id.mask) {
+ array[i].mDrawable.draw(canvas);
+ }
+ }
+
+ // Composite the layers if needed.
+ if (restoreToCount >= 0) {
+ canvas.restoreToCount(restoreToCount);
+ }
+ }
+
+ private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) {
final Ripple[] activeRipples = mActiveRipples;
final int ripplesCount = mActiveRipplesCount;
- final Rect bounds = getBounds();
+
+ Paint ripplePaint = null;
+ boolean drewRipples = false;
+ int restoreToCount = -1;
+ int activeRipplesCount = 0;
// Draw ripples.
- boolean drewRipples = false;
- int rippleRestoreCount = -1;
- int activeRipplesCount = 0;
for (int i = 0; i < ripplesCount; i++) {
final Ripple ripple = activeRipples[i];
final RippleAnimator animator = ripple.animate();
animator.update();
+
+ // Mark and skip inactive ripples.
if (!animator.isRunning()) {
activeRipples[i] = null;
- } else {
- // If we're masking the ripple layer, make sure we have a layer
- // first. This will merge SRC_OVER (directly) onto the canvas.
- if (!projected && rippleRestoreCount < 0) {
- rippleRestoreCount = canvas.saveLayer(bounds.left, bounds.top,
- bounds.right, bounds.bottom, null, 0);
- canvas.clipRect(bounds);
+ continue;
+ }
+
+ // 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();
+ } else {
+ xfermode = SRC_OVER;
}
- drewRipples |= ripple.draw(canvas, getRipplePaint());
-
- activeRipples[activeRipplesCount] = activeRipples[i];
- activeRipplesCount++;
+ 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);
+
+ activeRipples[activeRipplesCount] = activeRipples[i];
+ activeRipplesCount++;
}
+
mActiveRipplesCount = activeRipplesCount;
- // TODO: Use the masking layer first, if there is one.
-
- // If we have ripples and content, we need a masking layer. This will
- // merge DST_ATOP onto (effectively under) the ripple layer.
- if (drewRipples && !projected && rippleRestoreCount >= 0) {
- final PorterDuffXfermode xfermode = mState.getTintXfermode();
- canvas.saveLayer(bounds.left, bounds.top,
- bounds.right, bounds.bottom, getMaskingPaint(xfermode), 0);
+ // If we created a layer with no content, merge it immediately.
+ if (restoreToCount >= 0 && !drewRipples) {
+ canvas.restoreToCount(restoreToCount);
+ restoreToCount = -1;
}
- Drawable mask = null;
- final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
- for (int i = 0; i < N; i++) {
- if (array[i].mId != R.id.mask) {
- array[i].mDrawable.draw(canvas);
- } else {
- mask = array[i].mDrawable;
- }
- }
-
- // If we have ripples, mask them.
- if (mask != null && drewRipples) {
- // TODO: This will also mask the lower layer, which is bad.
- canvas.saveLayer(bounds.left, bounds.top, bounds.right,
- bounds.bottom, getMaskingPaint(DST_IN), 0);
- mask.draw(canvas);
- }
-
- // Composite the layers if needed.
- if (rippleRestoreCount >= 0) {
- canvas.restoreToCount(rippleRestoreCount);
- }
+ return restoreToCount;
}
- private Paint getRipplePaint() {
- if (mRipplePaint == null) {
- mRipplePaint = new Paint();
- mRipplePaint.setAntiAlias(true);
-
- if (mState.mTint != null) {
- final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
- mRipplePaint.setColor(color);
- }
- }
- return mRipplePaint;
- }
-
- private Paint getMaskingPaint(PorterDuffXfermode mode) {
+ private Paint getMaskingPaint(PorterDuffXfermode xfermode) {
if (mMaskingPaint == null) {
mMaskingPaint = new Paint();
}
- mMaskingPaint.setXfermode(mode);
+ mMaskingPaint.setXfermode(xfermode);
return mMaskingPaint;
}
@Override
public Rect getDirtyBounds() {
- final Rect dirtyBounds = mDirtyBounds;
final Rect drawingBounds = mDrawingBounds;
+ final Rect dirtyBounds = mDirtyBounds;
dirtyBounds.set(drawingBounds);
drawingBounds.setEmpty();
+
final Rect rippleBounds = mTempRect;
final Ripple[] activeRipples = mActiveRipples;
final int N = mActiveRipplesCount;
@@ -458,6 +612,8 @@
int[] mTouchThemeAttrs;
ColorStateList mTint;
PorterDuffXfermode mTintXfermode;
+ PorterDuffXfermode mTintXfermodeInverse;
+ Drawable mMask;
boolean mPinned;
public TouchFeedbackState(
@@ -468,19 +624,26 @@
mTouchThemeAttrs = orig.mTouchThemeAttrs;
mTint = orig.mTint;
mTintXfermode = orig.mTintXfermode;
+ mTintXfermodeInverse = orig.mTintXfermodeInverse;
mPinned = orig.mPinned;
+ mMask = orig.mMask;
}
}
-
+
public void setTintMode(Mode mode) {
final Mode invertedMode = TouchFeedbackState.invertPorterDuffMode(mode);
- mTintXfermode = new PorterDuffXfermode(invertedMode);
+ mTintXfermodeInverse = new PorterDuffXfermode(invertedMode);
+ mTintXfermode = new PorterDuffXfermode(mode);
}
-
+
public PorterDuffXfermode getTintXfermode() {
return mTintXfermode;
}
+ public PorterDuffXfermode getTintXfermodeInverse() {
+ return mTintXfermodeInverse;
+ }
+
@Override
public boolean canApplyTheme() {
return mTouchThemeAttrs != null || super.canApplyTheme();
diff --git a/graphics/java/android/graphics/drawable/shapes/OvalShape.java b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
index c914999..198dcc1 100644
--- a/graphics/java/android/graphics/drawable/shapes/OvalShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/OvalShape.java
@@ -17,7 +17,9 @@
package android.graphics.drawable.shapes;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Paint;
+import android.graphics.RectF;
/**
* Defines an oval shape.
@@ -36,5 +38,13 @@
public void draw(Canvas canvas, Paint paint) {
canvas.drawOval(rect(), paint);
}
+
+ @Override
+ public boolean getOutline(Outline outline) {
+ final RectF rect = rect();
+ outline.setOval((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
+ (int) Math.floor(rect.right), (int) Math.floor(rect.bottom));
+ return true;
+ }
}
diff --git a/graphics/java/android/graphics/drawable/shapes/RectShape.java b/graphics/java/android/graphics/drawable/shapes/RectShape.java
index a3d2654..2a0256c 100644
--- a/graphics/java/android/graphics/drawable/shapes/RectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RectShape.java
@@ -17,6 +17,7 @@
package android.graphics.drawable.shapes;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.RectF;
@@ -40,10 +41,18 @@
}
@Override
+ public boolean getOutline(Outline outline) {
+ final RectF rect = rect();
+ outline.setRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
+ (int) Math.floor(rect.right), (int) Math.floor(rect.bottom));
+ return true;
+ }
+
+ @Override
protected void onResize(float width, float height) {
mRect.set(0, 0, width, height);
}
-
+
/**
* Returns the RectF that defines this rectangle's bounds.
*/
diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
index b469d2a..a6bb1bb 100644
--- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
@@ -17,6 +17,7 @@
package android.graphics.drawable.shapes;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
@@ -77,11 +78,34 @@
public void draw(Canvas canvas, Paint paint) {
canvas.drawPath(mPath, paint);
}
-
+
+ @Override
+ public boolean getOutline(Outline outline) {
+ if (mInnerRect != null) return false; // have a hole, can't produce valid outline
+
+ float radius = 0;
+ if (mOuterRadii != null) {
+ radius = mOuterRadii[0];
+ for (int i = 1; i < 8; i++) {
+ if (mOuterRadii[i] != radius) {
+ // can't call simple constructors, use path
+ outline.setConvexPath(mPath);
+ return true;
+ }
+ }
+ }
+
+ final RectF rect = rect();
+ outline.setRoundRect((int) Math.ceil(rect.left), (int) Math.ceil(rect.top),
+ (int) Math.floor(rect.right), (int) Math.floor(rect.bottom),
+ radius);
+ return true;
+ }
+
@Override
protected void onResize(float w, float h) {
super.onResize(w, h);
-
+
RectF r = rect();
mPath.reset();
diff --git a/graphics/java/android/graphics/drawable/shapes/Shape.java b/graphics/java/android/graphics/drawable/shapes/Shape.java
index 4e192f95..1a20e8b 100644
--- a/graphics/java/android/graphics/drawable/shapes/Shape.java
+++ b/graphics/java/android/graphics/drawable/shapes/Shape.java
@@ -17,6 +17,7 @@
package android.graphics.drawable.shapes;
import android.graphics.Canvas;
+import android.graphics.Outline;
import android.graphics.Paint;
/**
@@ -43,7 +44,6 @@
return mHeight;
}
-
/**
* Draw this shape into the provided Canvas, with the provided Paint.
* Before calling this, you must call {@link #resize(float,float)}.
@@ -52,7 +52,6 @@
* @param paint the Paint object that defines this shape's characteristics
*/
public abstract void draw(Canvas canvas, Paint paint);
-
/**
* Resizes the dimensions of this shape.
@@ -93,8 +92,20 @@
*/
protected void onResize(float width, float height) {}
+ /**
+ * Compute the Outline of the shape.
+ *
+ * The default implementation does not supply an outline.
+ *
+ * @return True if a valid outline has been computed, false otherwise.
+ */
+ public boolean getOutline(Outline outline) {
+ return false;
+ }
+
@Override
public Shape clone() throws CloneNotSupportedException {
return (Shape) super.clone();
}
+
}
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index c0b5402..904ec8c 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -62,7 +62,7 @@
dir.setCapacity(rays);
float rayDist[rays];
float rayHeight[rays];
- calculateRayDirections(rays, dir.editArray());
+ calculateRayDirections(rays, vertices, vertexCount, centroid3d, dir.editArray());
// Calculate the length and height of the points along the edge.
//
@@ -149,14 +149,91 @@
* Generate an array of rays' direction vectors.
*
* @param rays The number of rays shooting out from the centroid.
+ * @param vertices Vertices of the polygon.
+ * @param vertexCount The number of vertices.
+ * @param centroid3d The centroid of the polygon.
* @param dir Return the array of ray vectors.
*/
-void AmbientShadow::calculateRayDirections(int rays, Vector2* dir) {
- float deltaAngle = 2 * M_PI / rays;
+void AmbientShadow::calculateRayDirections(const int rays, const Vector3* vertices,
+ const int vertexCount, const Vector3& centroid3d, Vector2* dir) {
+ // If we don't have enough rays, then fall back to the uniform distribution.
+ if (vertexCount * 2 > rays) {
+ float deltaAngle = 2 * M_PI / rays;
+ for (int i = 0; i < rays; i++) {
+ dir[i].x = sinf(deltaAngle * i);
+ dir[i].y = cosf(deltaAngle * i);
+ }
+ return;
+ }
+
+ // If we have enough rays, then we assign each vertices a ray, and distribute
+ // the rest uniformly.
+ float rayThetas[rays];
+
+ const int uniformRayCount = rays - vertexCount;
+ const float deltaAngle = 2 * M_PI / uniformRayCount;
+
+ // We have to generate all the vertices' theta anyway and we also need to
+ // find the minimal, so let's precompute it first.
+ // Since the incoming polygon is clockwise, we can find the dip to identify
+ // the minimal theta.
+ float polyThetas[vertexCount];
+ int minimalPolyThetaIndex = 0;
+ for (int i = 0; i < vertexCount; i++) {
+ polyThetas[i] = atan2(vertices[i].y - centroid3d.y,
+ vertices[i].x - centroid3d.x);
+ if (i > 0 && polyThetas[i] < polyThetas[i - 1]) {
+ minimalPolyThetaIndex = i;
+ }
+ }
+
+ int polyThetaIndex = minimalPolyThetaIndex;
+ float polyTheta = polyThetas[minimalPolyThetaIndex];
+ int uniformThetaIndex = 0;
+ float uniformTheta = - M_PI;
+ for (int i = 0; i < rays; i++) {
+ // Compare both thetas and pick the smaller one and move on.
+ bool hasThetaCollision = abs(polyTheta - uniformTheta) < MINIMAL_DELTA_THETA;
+ if (polyTheta < uniformTheta || hasThetaCollision) {
+ if (hasThetaCollision) {
+ // Shift the uniformTheta to middle way between current polyTheta
+ // and next uniform theta. The next uniform theta can wrap around
+ // to exactly PI safely here.
+ // Note that neither polyTheta nor uniformTheta can be FLT_MAX
+ // due to the hasThetaCollision is true.
+ uniformTheta = (polyTheta + deltaAngle * (uniformThetaIndex + 1) - M_PI) / 2;
+#if DEBUG_SHADOW
+ ALOGD("Shifted uniformTheta to %f", uniformTheta);
+#endif
+ }
+ rayThetas[i] = polyTheta;
+ polyThetaIndex = (polyThetaIndex + 1) % vertexCount;
+ if (polyThetaIndex != minimalPolyThetaIndex) {
+ polyTheta = polyThetas[polyThetaIndex];
+ } else {
+ // out of poly points.
+ polyTheta = FLT_MAX;
+ }
+ } else {
+ rayThetas[i] = uniformTheta;
+ uniformThetaIndex++;
+ if (uniformThetaIndex < uniformRayCount) {
+ uniformTheta = deltaAngle * uniformThetaIndex - M_PI;
+ } else {
+ // out of uniform points.
+ uniformTheta = FLT_MAX;
+ }
+ }
+ }
for (int i = 0; i < rays; i++) {
- dir[i].x = sinf(deltaAngle * i);
- dir[i].y = cosf(deltaAngle * i);
+#if DEBUG_SHADOW
+ ALOGD("No. %d : %f", i, rayThetas[i] * 180 / M_PI);
+#endif
+ // TODO: Fix the intersection precision problem and remvoe the delta added
+ // here.
+ dir[i].x = sinf(rayThetas[i] + MINIMAL_DELTA_THETA);
+ dir[i].y = cosf(rayThetas[i] + MINIMAL_DELTA_THETA);
}
}
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 45b8bef..451bfbe 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -40,7 +40,8 @@
float geomFactor, VertexBuffer& shadowVertexBuffer);
private:
- static void calculateRayDirections(int rays, Vector2* dir);
+ static void calculateRayDirections(const int rays, const Vector3* vertices,
+ const int vertexCount, const Vector3& centroid3d, Vector2* dir);
static void calculateIntersection(const Vector3* poly, int nbVertices,
const Vector3& start, const Vector2& dir, int& outEdgeIndex,
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index a5d8dcb..dac86cb 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -29,7 +29,10 @@
namespace android {
namespace uirenderer {
-DisplayListData::DisplayListData() : projectionReceiveIndex(-1), functorCount(0), hasDrawOps(false) {
+DisplayListData::DisplayListData()
+ : projectionReceiveIndex(-1)
+ , functorCount(0)
+ , hasDrawOps(false) {
}
DisplayListData::~DisplayListData() {
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index f19da9d..6dfb918 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -318,12 +318,19 @@
class SaveLayerOp : public StateOp {
public:
SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags)
- : mArea(left, top, right, bottom), mPaint(&mCachedPaint), mFlags(flags) {
+ : mArea(left, top, right, bottom)
+ , mPaint(&mCachedPaint)
+ , mFlags(flags)
+ , mConvexMask(NULL) {
mCachedPaint.setAlpha(alpha);
}
SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags)
- : mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
+ : mArea(left, top, right, bottom)
+ , mPaint(paint)
+ , mFlags(flags)
+ , mConvexMask(NULL)
+ {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
bool useQuickReject) {
@@ -338,7 +345,8 @@
}
virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mPaint, mFlags);
+ renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom,
+ mPaint, mFlags, mConvexMask);
}
virtual void output(int level, uint32_t logFlags) const {
@@ -350,6 +358,11 @@
int getFlags() { return mFlags; }
+ // Called to make SaveLayerOp clip to the provided mask when drawing back/restored
+ void setMask(const SkPath* convexMask) {
+ mConvexMask = convexMask;
+ }
+
private:
bool isSaveLayerAlpha() const {
SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
@@ -361,6 +374,10 @@
const SkPaint* mPaint;
SkPaint mCachedPaint;
int mFlags;
+
+ // Convex path, points at data in RenderNode, valid for the duration of the frame only
+ // Only used for masking the SaveLayer which wraps projected RenderNodes
+ const SkPath* mConvexMask;
};
class TranslateOp : public StateOp {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 6c73d68..e36d975 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -184,20 +184,15 @@
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
- // TODO: To be safe, the display list should be ref-counted in the
- // resources cache, but we rely on the caller (UI toolkit) to
- // do the right thing for now
+ if (displayList->stagingProperties().isProjectionReceiver()) {
+ // use staging property, since recording on UI thread
+ mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size();
+ }
DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList,
flags, *currentTransform());
addDrawOp(op);
mDisplayListData->addChild(op);
-
- if (displayList->stagingProperties().isProjectionReceiver()) {
- // use staging property, since recording on UI thread
- mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
- }
-
return DrawGlInfo::kStatusDone;
}
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index bfe4eda..9606e58 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -48,6 +48,7 @@
hasDrawnSinceUpdate = false;
forceFilter = false;
deferredList = NULL;
+ convexMask = NULL;
caches.resourceCache.incrementRefcount(this);
}
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 5375b45..49610d5 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -227,6 +227,14 @@
ANDROID_API void setColorFilter(SkColorFilter* filter);
+ inline void setConvexMask(const SkPath* convexMask) {
+ this->convexMask = convexMask;
+ }
+
+ inline const SkPath* getConvexMask() {
+ return convexMask;
+ }
+
void bindStencilRenderBuffer() const;
void bindTexture() const;
@@ -378,6 +386,13 @@
*/
DeferredDisplayList* deferredList;
+ /**
+ * This convex path should be used to mask the layer's draw to the screen.
+ *
+ * Data not owned/managed by layer object.
+ */
+ const SkPath* convexMask;
+
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f37487f..1f5389c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -704,11 +704,11 @@
///////////////////////////////////////////////////////////////////////////////
int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags) {
+ const SkPaint* paint, int flags, const SkPath* convexMask) {
const int count = saveSnapshot(flags);
if (!currentSnapshot()->isIgnored()) {
- createLayer(left, top, right, bottom, paint, flags);
+ createLayer(left, top, right, bottom, paint, flags, convexMask);
}
return count;
@@ -782,7 +782,6 @@
return count;
}
-
/**
* Layers are viewed by Skia are slightly different than layers in image editing
* programs (for instance.) When a layer is created, previously created layers
@@ -835,7 +834,7 @@
* something actually gets drawn are the layers regions cleared.
*/
bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags) {
+ const SkPaint* paint, int flags, const SkPath* convexMask) {
LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
@@ -865,6 +864,7 @@
layer->setBlend(true);
layer->setDirty(false);
+ layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
// Save the layer in the snapshot
mSnapshot->flags |= Snapshot::kFlagIsLayer;
@@ -1013,6 +1013,7 @@
dirtyClip();
// Failing to add the layer to the cache should happen only if the layer is too large
+ layer->setConvexMask(NULL);
if (!mCaches.layerCache.put(layer)) {
LAYER_LOGD("Deleting layer");
Caches::getInstance().resourceCache.decrementRefcount(layer);
@@ -1122,6 +1123,38 @@
#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
+ if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
+
+ if (layer->getConvexMask()) {
+ save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+
+ // clip to the area of the layer the mask can be larger
+ clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
+
+ SkiaShader* oldShader = mDrawModifiers.mShader;
+
+ // create LayerShader to map SaveLayer content into subsequent draw
+ SkMatrix shaderMatrix;
+ shaderMatrix.setTranslate(rect.left, rect.bottom);
+ shaderMatrix.preScale(1, -1);
+ SkiaLayerShader layerShader(layer, &shaderMatrix);
+ mDrawModifiers.mShader = &layerShader;
+
+ // Since the drawing primitive is defined in local drawing space,
+ // we don't need to modify the draw matrix
+ const SkPath* maskPath = layer->getConvexMask();
+ DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
+
+ mDrawModifiers.mShader = oldShader;
+ restore();
+
+ return;
+ }
+
if (layer->region.isRect()) {
layer->setRegionAsRect();
@@ -1131,88 +1164,87 @@
return;
}
- if (CC_LIKELY(!layer->region.isEmpty())) {
- size_t count;
- const android::Rect* rects;
- Region safeRegion;
- if (CC_LIKELY(hasRectToRectTransform())) {
- rects = layer->region.getArray(&count);
- } else {
- safeRegion = Region::createTJunctionFreeRegion(layer->region);
- rects = safeRegion.getArray(&count);
- }
+ // standard Region based draw
+ size_t count;
+ const android::Rect* rects;
+ Region safeRegion;
+ if (CC_LIKELY(hasRectToRectTransform())) {
+ rects = layer->region.getArray(&count);
+ } else {
+ safeRegion = Region::createTJunctionFreeRegion(layer->region);
+ rects = safeRegion.getArray(&count);
+ }
- const float alpha = getLayerAlpha(layer);
- const float texX = 1.0f / float(layer->getWidth());
- const float texY = 1.0f / float(layer->getHeight());
- const float height = rect.getHeight();
+ const float alpha = getLayerAlpha(layer);
+ const float texX = 1.0f / float(layer->getWidth());
+ const float texY = 1.0f / float(layer->getHeight());
+ const float height = rect.getHeight();
- setupDraw();
+ setupDraw();
- // We must get (and therefore bind) the region mesh buffer
- // after we setup drawing in case we need to mess with the
- // stencil buffer in setupDraw()
- TextureVertex* mesh = mCaches.getRegionMesh();
- uint32_t numQuads = 0;
+ // We must get (and therefore bind) the region mesh buffer
+ // after we setup drawing in case we need to mess with the
+ // stencil buffer in setupDraw()
+ TextureVertex* mesh = mCaches.getRegionMesh();
+ uint32_t numQuads = 0;
- setupDrawWithTexture();
- setupDrawColor(alpha, alpha, alpha, alpha);
- setupDrawColorFilter(layer->getColorFilter());
- setupDrawBlending(layer);
- setupDrawProgram();
- setupDrawDirtyRegionsDisabled();
- setupDrawPureColorUniforms();
- setupDrawColorFilterUniforms(layer->getColorFilter());
- setupDrawTexture(layer->getTexture());
- if (currentTransform()->isPureTranslate()) {
- const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
- const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
+ setupDrawWithTexture();
+ setupDrawColor(alpha, alpha, alpha, alpha);
+ setupDrawColorFilter(layer->getColorFilter());
+ setupDrawBlending(layer);
+ setupDrawProgram();
+ setupDrawDirtyRegionsDisabled();
+ setupDrawPureColorUniforms();
+ setupDrawColorFilterUniforms(layer->getColorFilter());
+ setupDrawTexture(layer->getTexture());
+ if (currentTransform()->isPureTranslate()) {
+ const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
+ const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
- layer->setFilter(GL_NEAREST);
- setupDrawModelView(kModelViewMode_Translate, false,
- x, y, x + rect.getWidth(), y + rect.getHeight(), true);
- } else {
- layer->setFilter(GL_LINEAR);
- setupDrawModelView(kModelViewMode_Translate, false,
- rect.left, rect.top, rect.right, rect.bottom);
- }
- setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
+ layer->setFilter(GL_NEAREST);
+ setupDrawModelView(kModelViewMode_Translate, false,
+ x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+ } else {
+ layer->setFilter(GL_LINEAR);
+ setupDrawModelView(kModelViewMode_Translate, false,
+ rect.left, rect.top, rect.right, rect.bottom);
+ }
+ setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
- for (size_t i = 0; i < count; i++) {
- const android::Rect* r = &rects[i];
+ for (size_t i = 0; i < count; i++) {
+ const android::Rect* r = &rects[i];
- const float u1 = r->left * texX;
- const float v1 = (height - r->top) * texY;
- const float u2 = r->right * texX;
- const float v2 = (height - r->bottom) * texY;
+ const float u1 = r->left * texX;
+ const float v1 = (height - r->top) * texY;
+ const float u2 = r->right * texX;
+ const float v2 = (height - r->bottom) * texY;
- // TODO: Reject quads outside of the clip
- TextureVertex::set(mesh++, r->left, r->top, u1, v1);
- TextureVertex::set(mesh++, r->right, r->top, u2, v1);
- TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
- TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+ // TODO: Reject quads outside of the clip
+ TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+ TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+ TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+ TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
- numQuads++;
+ numQuads++;
- if (numQuads >= gMaxNumberOfQuads) {
- DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
- GL_UNSIGNED_SHORT, NULL));
- numQuads = 0;
- mesh = mCaches.getRegionMesh();
- }
- }
-
- if (numQuads > 0) {
+ if (numQuads >= gMaxNumberOfQuads) {
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
GL_UNSIGNED_SHORT, NULL));
+ numQuads = 0;
+ mesh = mCaches.getRegionMesh();
}
+ }
+
+ if (numQuads > 0) {
+ DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
+ GL_UNSIGNED_SHORT, NULL));
+ }
#if DEBUG_LAYERS_AS_REGIONS
- drawRegionRectsDebug(layer->region);
+ drawRegionRectsDebug(layer->region);
#endif
- layer->region.clear();
- }
+ layer->region.clear();
}
#if DEBUG_LAYERS_AS_REGIONS
@@ -2926,7 +2958,7 @@
if (layer->isTextureLayer()) {
transform = &layer->getTransform();
if (!transform->isIdentity()) {
- save(0);
+ save(SkCanvas::kMatrix_SaveFlag);
concatMatrix(*transform);
}
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 2debd2e..b49d1e1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -161,7 +161,14 @@
ANDROID_API void flushLayerUpdates();
ANDROID_API virtual int saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags);
+ const SkPaint* paint, int flags) {
+ return saveLayer(left, top, right, bottom, paint, flags, NULL);
+ }
+
+ // Specialized saveLayer implementation, which will pass the convexMask to an FBO layer, if
+ // created, which will in turn clip to that mask when drawn back/restored.
+ int saveLayer(float left, float top, float right, float bottom,
+ const SkPaint* paint, int flags, const SkPath* convexMask);
int saveLayerDeferred(float left, float top, float right, float bottom,
const SkPaint* paint, int flags);
@@ -523,11 +530,12 @@
* @param alpha The translucency of the layer
* @param mode The blending mode of the layer
* @param flags The layer save flags
+ * @param mask A mask to use when drawing the layer back, may be empty
*
* @return True if the layer was successfully created, false otherwise
*/
bool createLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags);
+ const SkPaint* paint, int flags, const SkPath* convexMask);
/**
* Creates a new layer stored in the specified snapshot as an FBO.
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 0083b77..92964a8 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -30,6 +30,8 @@
#define RECT_STRING "%7.2f %7.2f %7.2f %7.2f"
#define RECT_ARGS(r) \
(r).left, (r).top, (r).right, (r).bottom
+#define SK_RECT_ARGS(r) \
+ (r).left(), (r).top(), (r).right(), (r).bottom()
///////////////////////////////////////////////////////////////////////////////
// Structs
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index cf21834..2008f02 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -26,6 +26,7 @@
#include "Debug.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
+#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
@@ -76,7 +77,7 @@
*/
void RenderNode::output(uint32_t level) {
ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
- mName.string(), isRenderable());
+ getName(), isRenderable());
ALOGD("%*s%s %d", level * 2, "", "Save",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -86,7 +87,7 @@
mDisplayListData->displayListOps[i]->output(level, flags);
}
- ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
+ ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
}
void RenderNode::prepareTree(TreeInfo& info) {
@@ -217,7 +218,9 @@
mat4 anim(*properties().getAnimationMatrix());
matrix.multiply(anim);
}
- if (properties().hasTransformMatrix()) {
+
+ bool applyTranslationZ = true3dTransform && !MathUtils::isZero(properties().getTranslationZ());
+ if (properties().hasTransformMatrix() || applyTranslationZ) {
if (properties().isTransformTranslateOnly()) {
matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
true3dTransform ? properties().getTranslationZ() : 0.0f);
@@ -260,12 +263,13 @@
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children()[i];
childOp->mDisplayList->computeOrderingImpl(childOp,
- &mProjectedNodes, &mat4::identity());
+ properties().getOutline().getPath(), &mProjectedNodes, &mat4::identity());
}
}
void RenderNode::computeOrderingImpl(
DrawDisplayListOp* opState,
+ const SkPath* outlineOfProjectionSurface,
Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface) {
mProjectedNodes.clear();
@@ -293,6 +297,7 @@
DrawDisplayListOp* childOp = mDisplayListData->children()[i];
RenderNode* child = childOp->mDisplayList;
+ const SkPath* projectionOutline = NULL;
Vector<DrawDisplayListOp*>* projectionChildren = NULL;
const mat4* projectionTransform = NULL;
if (isProjectionReceiver && !child->properties().getProjectBackwards()) {
@@ -301,6 +306,7 @@
// Note that if a direct descendent is projecting backwards, we pass it's
// grandparent projection collection, since it shouldn't project onto it's
// parent, where it will already be drawing.
+ projectionOutline = properties().getOutline().getPath();
projectionChildren = &mProjectedNodes;
projectionTransform = &mat4::identity();
} else {
@@ -308,10 +314,12 @@
applyViewPropertyTransforms(localTransformFromProjectionSurface);
haveAppliedPropertiesToProjection = true;
}
+ projectionOutline = outlineOfProjectionSurface;
projectionChildren = compositedChildrenOfProjectionSurface;
projectionTransform = &localTransformFromProjectionSurface;
}
- child->computeOrderingImpl(childOp, projectionChildren, projectionTransform);
+ child->computeOrderingImpl(childOp,
+ projectionOutline, projectionChildren, projectionTransform);
}
}
}
@@ -351,7 +359,7 @@
: mReplayStruct(replayStruct), mLevel(level) {}
inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
- properties().getReplayStruct().mRenderer.eventMark(operation->name());
+ mReplayStruct.mRenderer.eventMark(operation->name());
#endif
operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
}
@@ -361,8 +369,6 @@
}
inline void endMark() {
mReplayStruct.mRenderer.endMark();
- DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
- mReplayStruct.mDrawGlStatus);
}
inline int level() { return mLevel; }
inline int replayFlags() { return mReplayStruct.mReplayFlags; }
@@ -391,7 +397,7 @@
RenderNode* child = childOp->mDisplayList;
float childZ = child->properties().getTranslationZ();
- if (childZ != 0.0f) {
+ if (!MathUtils::isZero(childZ)) {
zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp));
childOp->mSkipInOrderDraw = true;
} else if (!child->properties().getProjectBackwards()) {
@@ -467,6 +473,10 @@
endIndex = size;
shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
}
+
+ DISPLAY_LIST_LOGD("%*s%d %s 3d children:", (handler.level() + 1) * 2, "",
+ endIndex - drawIndex, mode == kNegativeZChildren ? "negative" : "positive");
+
float lastCasterZ = 0.0f;
while (shadowIndex < endIndex || drawIndex < endIndex) {
if (shadowIndex < endIndex) {
@@ -503,6 +513,42 @@
template <class T>
void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) {
+ DISPLAY_LIST_LOGD("%*s%d projected children:", (handler.level() + 1) * 2, "", mProjectedNodes.size());
+ const SkPath* projectionReceiverOutline = properties().getOutline().getPath();
+ bool maskProjecteesWithPath = projectionReceiverOutline != NULL
+ && !projectionReceiverOutline->isRect(NULL);
+ int restoreTo = renderer.getSaveCount();
+
+ // If the projection reciever has an outline, we mask each of the projected rendernodes to it
+ // Either with clipRect, or special saveLayer masking
+ LinearAllocator& alloc = handler.allocator();
+ if (projectionReceiverOutline != NULL) {
+ const SkRect& outlineBounds = projectionReceiverOutline->getBounds();
+ if (projectionReceiverOutline->isRect(NULL)) {
+ // mask to the rect outline simply with clipRect
+ handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+ PROPERTY_SAVECOUNT, properties().getClipToBounds());
+ ClipRectOp* clipOp = new (alloc) ClipRectOp(
+ outlineBounds.left(), outlineBounds.top(),
+ outlineBounds.right(), outlineBounds.bottom(), SkRegion::kIntersect_Op);
+ handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+ } else {
+ // wrap the projected RenderNodes with a SaveLayer that will mask to the outline
+ SaveLayerOp* op = new (alloc) SaveLayerOp(
+ outlineBounds.left(), outlineBounds.top(),
+ outlineBounds.right(), outlineBounds.bottom(),
+ 255, SkCanvas::kARGB_ClipLayer_SaveFlag);
+ op->setMask(projectionReceiverOutline);
+ handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+
+ /* TODO: add optimizations here to take advantage of placement/size of projected
+ * children (which may shrink saveLayer area significantly). This is dependent on
+ * passing actual drawing/dirtying bounds of projected content down to native.
+ */
+ }
+ }
+
+ // draw projected nodes
for (size_t i = 0; i < mProjectedNodes.size(); i++) {
DrawDisplayListOp* childOp = mProjectedNodes[i];
@@ -514,6 +560,11 @@
childOp->mSkipInOrderDraw = true;
renderer.restoreToCount(restoreTo);
}
+
+ if (projectionReceiverOutline != NULL) {
+ handler(new (alloc) RestoreToCountOp(restoreTo),
+ PROPERTY_SAVECOUNT, properties().getClipToBounds());
+ }
}
/**
@@ -529,17 +580,17 @@
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
const int level = handler.level();
if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
- DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
+ DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
return;
}
- handler.startMark(mName.string());
+ handler.startMark(getName());
#if DEBUG_DISPLAY_LIST
- Rect* clipRect = renderer.getClipRect();
- DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
- level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
- clipRect->right, clipRect->bottom);
+ const Rect& clipRect = renderer.getLocalClipBounds();
+ DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f",
+ level * 2, "", this, getName(),
+ clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
#endif
LinearAllocator& alloc = handler.allocator();
@@ -587,6 +638,7 @@
PROPERTY_SAVECOUNT, properties().getClipToBounds());
renderer.setOverrideLayerAlpha(1.0f);
+ DISPLAY_LIST_LOGD("%*sDone (%p, %s)", level * 2, "", this, getName());
handler.endMark();
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 6688952..b9edbe5 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -172,6 +172,7 @@
void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false);
void computeOrderingImpl(DrawDisplayListOp* opState,
+ const SkPath* outlineOfProjectionSurface,
Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface);
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 08829ef..a922db8 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -26,16 +26,7 @@
#include <SkPathOps.h>
#include "Matrix.h"
-
-/**
- * Convenience value to check for float values that are close enough to zero to be considered
- * zero.
- */
-#define NONZERO_EPSILON .001f
-
-static inline bool is_zero(float value) {
- return (value >= -NONZERO_EPSILON) || (value <= NONZERO_EPSILON);
-}
+#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
@@ -151,7 +142,7 @@
}
SkMatrix* transform = mComputedFields.mTransformMatrix;
transform->reset();
- if (is_zero(getRotationX()) && is_zero(getRotationY())) {
+ if (MathUtils::isZero(getRotationX()) && MathUtils::isZero(getRotationY())) {
transform->setTranslate(getTranslationX(), getTranslationY());
transform->preRotate(getRotation(), getPivotX(), getPivotY());
transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index efcea5f..3209a53 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -167,7 +167,7 @@
virtual void concatMatrix(const SkMatrix* matrix) = 0;
// clip
- virtual const Rect& getClipBounds() const = 0;
+ virtual const Rect& getLocalClipBounds() const = 0;
virtual bool quickRejectConservative(float left, float top,
float right, float bottom) const = 0;
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index ff3de74..05370dd 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -62,6 +62,8 @@
#define SHADOW_MIN_CASTER_Z 0.001f
+#define MINIMAL_DELTA_THETA (M_PI / 180 / 1000)
+
class ShadowTessellator {
public:
static VertexBufferMode tessellateAmbientShadow(bool isCasterOpaque,
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 4f2a432..6a4a0c8 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -73,7 +73,7 @@
}
SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
- SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
+ SkShader::TileMode tileY, const SkMatrix* matrix, bool blend):
mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend),
mCaches(NULL) {
setMatrix(matrix);
@@ -101,6 +101,49 @@
}
///////////////////////////////////////////////////////////////////////////////
+// Layer shader
+///////////////////////////////////////////////////////////////////////////////
+
+SkiaLayerShader::SkiaLayerShader(Layer* layer, const SkMatrix* matrix):
+ SkiaShader(kBitmap, NULL, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
+ matrix, layer->isBlend()), mLayer(layer) {
+ updateLocalMatrix(matrix);
+}
+
+SkiaShader* SkiaLayerShader::copy() {
+ SkiaLayerShader* copy = new SkiaLayerShader();
+ copy->copyFrom(*this);
+ copy->mLayer = mLayer;
+ return copy;
+}
+
+void SkiaLayerShader::describe(ProgramDescription& description, const Extensions& extensions) {
+ description.hasBitmap = true;
+}
+
+void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView,
+ const Snapshot& snapshot, GLuint* textureUnit) {
+ GLuint textureSlot = (*textureUnit)++;
+ Caches::getInstance().activeTexture(textureSlot);
+
+ const float width = mLayer->getWidth();
+ const float height = mLayer->getHeight();
+
+ mat4 textureTransform;
+ computeScreenSpaceMatrix(textureTransform, modelView);
+
+ // Uniforms
+ mLayer->bindTexture();
+ mLayer->setWrap(GL_CLAMP_TO_EDGE);
+ mLayer->setFilter(GL_LINEAR);
+
+ glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
+ glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+ GL_FALSE, &textureTransform.data[0]);
+ glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Bitmap shader
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 6015761..9f30257 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -58,7 +58,7 @@
};
ANDROID_API SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
- SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
+ SkShader::TileMode tileY, const SkMatrix* matrix, bool blend);
virtual ~SkiaShader();
virtual SkiaShader* copy() = 0;
@@ -88,7 +88,7 @@
return mGenerationId;
}
- void setMatrix(SkMatrix* matrix) {
+ void setMatrix(const SkMatrix* matrix) {
updateLocalMatrix(matrix);
mGenerationId++;
}
@@ -134,6 +134,24 @@
///////////////////////////////////////////////////////////////////////////////
/**
+ * A shader that draws a layer.
+ */
+struct SkiaLayerShader: public SkiaShader {
+ SkiaLayerShader(Layer* layer, const SkMatrix* matrix);
+ SkiaShader* copy();
+
+ void describe(ProgramDescription& description, const Extensions& extensions);
+ void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
+ GLuint* textureUnit);
+
+private:
+ SkiaLayerShader() {
+ }
+
+ Layer* mLayer;
+}; // struct SkiaLayerShader
+
+/**
* A shader that draws a bitmap.
*/
struct SkiaBitmapShader: public SkiaShader {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 5bdb18a..038aea8 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -108,7 +108,12 @@
* Returns the current clip in local coordinates. The clip rect is
* transformed by the inverse transform matrix.
*/
- ANDROID_API const Rect& getLocalClip();
+ const Rect& getLocalClip();
+
+ /**
+ * Returns the current clip in render target coordinates.
+ */
+ const Rect& getRenderTargetClip() { return *clipRect; }
/**
* Resets the clip to the specified rect.
@@ -238,7 +243,7 @@
mat4 mTransformRoot;
Rect mClipRectRoot;
- Rect mLocalClip;
+ Rect mLocalClip; // don't use directly, call getLocalClip() which initializes this
SkRegion mClipRegionRoot;
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index bf34bec..64354ac 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -75,7 +75,8 @@
void concatMatrix(const Matrix4& matrix); // internal only convenience method
// Clip
- const Rect& getClipBounds() const { return mSnapshot->getLocalClip(); }
+ virtual const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
+
virtual bool quickRejectConservative(float left, float top, float right, float bottom) const;
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
@@ -83,6 +84,8 @@
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
protected:
+ const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
+
int getWidth() { return mWidth; }
int getHeight() { return mHeight; }
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 5187f8f..d22cb8a 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -42,6 +42,7 @@
Font::Font(FontRenderer* state, const Font::FontDescription& desc) :
mState(state), mDescription(desc) {
+ mDeviceProperties = SkDeviceProperties::Make(SkDeviceProperties::Geometry::MakeDefault(), 1.0f);
}
Font::FontDescription::FontDescription(const SkPaint* paint, const mat4& matrix) {
@@ -272,7 +273,7 @@
if (cachedGlyph) {
// Is the glyph still in texture cache?
if (!cachedGlyph->mIsValid) {
- SkAutoGlyphCache autoCache(*paint, NULL, &mDescription.mLookupTransform);
+ SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), textUnit);
updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), cachedGlyph, precaching);
}
@@ -464,7 +465,7 @@
CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
mCachedGlyphs.add(glyph, newGlyph);
- SkAutoGlyphCache autoCache(*paint, NULL, &mDescription.mLookupTransform);
+ SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), glyph);
newGlyph->mIsValid = false;
newGlyph->mGlyphIndex = skiaGlyph.fID;
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 02197bc..6ddd4f2 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -19,6 +19,8 @@
#include <utils/KeyedVector.h>
+#include <SkScalar.h>
+#include <SkDeviceProperties.h>
#include <SkGlyphCache.h>
#include <SkScalerContext.h>
#include <SkPaint.h>
@@ -146,6 +148,7 @@
DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
bool mIdentityTransform;
+ SkDeviceProperties mDeviceProperties;
};
inline int strictly_order_type(const Font::FontDescription& lhs,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4ed73c3..5ce7ba6 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -91,7 +91,8 @@
void destroy();
bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
- void makeCurrent(EGLSurface surface);
+ // Returns true if the current surface changed, false if it was already current
+ bool makeCurrent(EGLSurface surface);
void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
void swapBuffers(EGLSurface surface);
@@ -250,8 +251,8 @@
mCurrentSurface = EGL_NO_SURFACE;
}
-void GlobalContext::makeCurrent(EGLSurface surface) {
- if (isCurrent(surface)) return;
+bool GlobalContext::makeCurrent(EGLSurface surface) {
+ if (isCurrent(surface)) return false;
if (surface == EGL_NO_SURFACE) {
// If we are setting EGL_NO_SURFACE we don't care about any of the potential
@@ -263,6 +264,7 @@
(void*)surface, egl_error_str());
}
mCurrentSurface = surface;
+ return true;
}
void GlobalContext::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {
@@ -281,7 +283,6 @@
void GlobalContext::swapBuffers(EGLSurface surface) {
eglSwapBuffers(mEglDisplay, surface);
EGLint err = eglGetError();
- // TODO: Check whether we need to special case EGL_CONTEXT_LOST
LOG_ALWAYS_FATAL_IF(err != EGL_SUCCESS,
"Encountered EGL error %d %s during rendering", err, egl_error_str(err));
}
@@ -344,8 +345,8 @@
if (mEglSurface != EGL_NO_SURFACE) {
mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
- mGlobalContext->makeCurrent(mEglSurface);
mHaveNewSurface = true;
+ makeCurrent();
}
}
@@ -357,7 +358,7 @@
void CanvasContext::requireSurface() {
LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
"requireSurface() called but no surface set!");
- mGlobalContext->makeCurrent(mEglSurface);
+ makeCurrent();
}
bool CanvasContext::initialize(EGLNativeWindowType window) {
@@ -383,7 +384,9 @@
}
void CanvasContext::makeCurrent() {
- mGlobalContext->makeCurrent(mEglSurface);
+ // TODO: Figure out why this workaround is needed, see b/13913604
+ // In the meantime this matches the behavior of GLRenderer, so it is not a regression
+ mHaveNewSurface |= mGlobalContext->makeCurrent(mEglSurface);
}
void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters,
@@ -475,7 +478,7 @@
void CanvasContext::requireGlContext() {
if (mEglSurface != EGL_NO_SURFACE) {
- mGlobalContext->makeCurrent(mEglSurface);
+ makeCurrent();
} else {
mGlobalContext->usePBufferSurface();
}
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
new file mode 100644
index 0000000..57ba8fa
--- /dev/null
+++ b/libs/hwui/utils/MathUtils.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+#ifndef MATHUTILS_H
+#define MATHUTILS_H
+
+namespace android {
+namespace uirenderer {
+
+class MathUtils {
+private:
+ static const float gNonZeroEpsilon = 0.001f;
+public:
+ /**
+ * Check for floats that are close enough to zero.
+ */
+ inline static bool isZero(float value) {
+ return (value >= -gNonZeroEpsilon) && (value <= gNonZeroEpsilon);
+ }
+}; // class MathUtils
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* RENDERNODE_H */
diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java
index 623d707..5600aeb 100644
--- a/location/java/android/location/FusedBatchOptions.java
+++ b/location/java/android/location/FusedBatchOptions.java
@@ -95,8 +95,9 @@
}
public static final class BatchFlags {
- public static int WAKEUP_ON_FIFO_FULL = 1<<0;
- public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+ // follow the definitions to the letter in fused_location.h
+ public static int WAKEUP_ON_FIFO_FULL = 0x0000001;
+ public static int CALLBACK_ON_LOCATION_FIX =0x0000002;
}
/*
diff --git a/media/java/android/media/DngCreator.java b/media/java/android/media/DngCreator.java
new file mode 100644
index 0000000..b2a38ab
--- /dev/null
+++ b/media/java/android/media/DngCreator.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 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.media;
+
+import android.graphics.Bitmap;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureResult;
+import android.location.Location;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * The {@link DngCreator} class provides functions to write raw pixel data as a DNG file.
+ *
+ * <p>
+ * This class is designed to be used with the {@link android.graphics.ImageFormat#RAW_SENSOR}
+ * buffers available from {@link android.hardware.camera2.CameraDevice}, or with Bayer-type raw
+ * pixel data that is otherwise generated by an application. The DNG metadata tags will be
+ * generated from a {@link android.hardware.camera2.CaptureResult} object or set directly.
+ * </p>
+ *
+ * <p>
+ * The DNG file format is a cross-platform file format that is used to store pixel data from
+ * camera sensors with minimal pre-processing applied. DNG files allow for pixel data to be
+ * defined in a user-defined colorspace, and have associated metadata that allow for this
+ * pixel data to be converted to the standard CIE XYZ colorspace during post-processing.
+ * </p>
+ *
+ * <p>
+ * For more information on the DNG file format and associated metadata, please refer to the
+ * <a href=
+ * "https://wwwimages2.adobe.com/content/dam/Adobe/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf">
+ * Adobe DNG 1.4.0.0 specification</a>.
+ * </p>
+ */
+public final class DngCreator {
+
+ /**
+ * Create a new DNG object.
+ *
+ * <p>
+ * It is not necessary to call any set methods to write a well-formatted DNG file.
+ * </p>
+ * <p>
+ * DNG metadata tags will be generated from the corresponding parameters in the
+ * {@link android.hardware.camera2.CaptureResult} object. This removes or overrides
+ * all previous tags set.
+ * </p>
+ *
+ * @param characteristics an object containing the static
+ * {@link android.hardware.camera2.CameraCharacteristics}.
+ * @param metadata a metadata object to generate tags from.
+ */
+ public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {/*TODO*/}
+
+ /**
+ * Set the orientation value to write.
+ *
+ * <p>
+ * This will be written as the TIFF "Orientation" tag {@code (0x0112)}.
+ * Calling this will override any prior settings for this tag.
+ * </p>
+ *
+ * @param orientation the orientation value to set, one of:
+ * <ul>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_NORMAL}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_FLIP_HORIZONTAL}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_180}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_FLIP_VERTICAL}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_TRANSPOSE}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_90}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_TRANSVERSE}</li>
+ * <li>{@link android.media.ExifInterface#ORIENTATION_ROTATE_270}</li>
+ * </ul>
+ * @return this {@link #DngCreator} object.
+ */
+ public DngCreator setOrientation(int orientation) {
+ return this;
+ }
+
+ /**
+ * Set the thumbnail image.
+ *
+ * <p>
+ * Pixel data will be converted to a Baseline TIFF RGB image, with 8 bits per color channel.
+ * The alpha channel will be discarded.
+ * </p>
+ *
+ * <p>
+ * The given bitmap should not be altered while this object is in use.
+ * </p>
+ *
+ * @param pixels a {@link android.graphics.Bitmap} of pixel data.
+ * @return this {@link #DngCreator} object.
+ */
+ public DngCreator setThumbnail(Bitmap pixels) {
+ return this;
+ }
+
+ /**
+ * Set the thumbnail image.
+ *
+ * <p>
+ * Pixel data is interpreted as a {@link android.graphics.ImageFormat#YUV_420_888} image.
+ * </p>
+ *
+ * <p>
+ * The given image should not be altered while this object is in use.
+ * </p>
+ *
+ * @param pixels an {@link android.media.Image} object with the format
+ * {@link android.graphics.ImageFormat#YUV_420_888}.
+ * @return this {@link #DngCreator} object.
+ */
+ public DngCreator setThumbnail(Image pixels) {
+ return this;
+ }
+
+
+ /**
+ * Set image location metadata.
+ *
+ * <p>
+ * The given location object must contain at least a valid time, latitude, and longitude
+ * (equivalent to the values returned by {@link android.location.Location#getTime()},
+ * {@link android.location.Location#getLatitude()}, and
+ * {@link android.location.Location#getLongitude()} methods).
+ * </p>
+ *
+ * @param location an {@link android.location.Location} object to set.
+ * @return this {@link #DngCreator} object.
+ *
+ * @throws java.lang.IllegalArgumentException if the given location object doesn't
+ * contain enough information to set location metadata.
+ */
+ public DngCreator setLocation(Location location) { return this; }
+
+ /**
+ * Set the user description string to write.
+ *
+ * <p>
+ * This is equivalent to setting the TIFF "ImageDescription" tag {@code (0x010E)}.
+ * </p>
+ *
+ * @param description the user description string.
+ * @return this {@link #DngCreator} object.
+ */
+ public DngCreator setDescription(String description) {
+ return this;
+ }
+
+ /**
+ * Write the {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data to a DNG file with
+ * the currently configured metadata.
+ *
+ * <p>
+ * Raw pixel data must have 16 bits per pixel, and the input must contain at least
+ * {@code offset + 2 * (stride * (height - 1) + width * height)} bytes. The width and height of
+ * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
+ * and will typically be equal to the width and height of
+ * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+ * If insufficient metadata is set to write a well-formatted DNG file, and
+ * {@link java.lang.IllegalStateException} will be thrown.
+ * </p>
+ *
+ * <p>
+ * When reading from the pixel input, {@code stride} pixels will be skipped
+ * after each row (excluding the last).
+ * </p>
+ *
+ * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+ * @param pixels an {@link java.io.InputStream} of pixel data to write.
+ * @param stride the stride of the raw image in pixels.
+ * @param offset the offset of the raw image in bytes. This indicates how many bytes will
+ * be skipped in the input before any pixel data is read.
+ *
+ * @throws IOException if an error was encountered in the input or output stream.
+ * @throws java.lang.IllegalStateException if not enough metadata information has been
+ * set to write a well-formatted DNG file.
+ */
+ public void writeInputStream(OutputStream dngOutput, InputStream pixels, int stride,
+ long offset) throws IOException {
+ /*TODO*/
+ }
+
+ /**
+ * Write the {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data to a DNG file with
+ * the currently configured metadata.
+ *
+ * <p>
+ * Raw pixel data must have 16 bits per pixel, and the input must contain at least
+ * {@code offset + 2 * (stride * (height - 1) + width * height)} bytes. The width and height of
+ * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
+ * and will typically be equal to the width and height of
+ * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+ * If insufficient metadata is set to write a well-formatted DNG file, and
+ * {@link java.lang.IllegalStateException} will be thrown.
+ * </p>
+ *
+ * <p>
+ * When reading from the pixel input, {@code stride} pixels will be skipped
+ * after each row (excluding the last).
+ * </p>
+ *
+ * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+ * @param pixels an {@link java.nio.ByteBuffer} of pixel data to write.
+ * @param stride the stride of the raw image in pixels.
+ * @param offset the offset of the raw image in bytes. This indicates how many bytes will
+ * be skipped in the input before any pixel data is read.
+ *
+ * @throws IOException if an error was encountered in the input or output stream.
+ * @throws java.lang.IllegalStateException if not enough metadata information has been
+ * set to write a well-formatted DNG file.
+ */
+ public void writeByteBuffer(OutputStream dngOutput, ByteBuffer pixels, int stride,
+ long offset) throws IOException {/*TODO*/}
+
+ /**
+ * Write the pixel data to a DNG file with the currently configured metadata.
+ *
+ * <p>
+ * For this method to succeed, the {@link android.media.Image} input must contain
+ * {@link android.graphics.ImageFormat#RAW_SENSOR} pixel data, otherwise an
+ * {@link java.lang.IllegalArgumentException} will be thrown.
+ * </p>
+ *
+ * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+ * @param pixels an {@link android.media.Image} to write.
+ *
+ * @throws java.io.IOException if an error was encountered in the output stream.
+ * @throws java.lang.IllegalArgumentException if an image with an unsupported format was used.
+ * @throws java.lang.IllegalStateException if not enough metadata information has been
+ * set to write a well-formatted DNG file.
+ */
+ public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {/*TODO*/}
+
+}
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 214306c..2dea509 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -327,13 +327,12 @@
private static final int MSG_REEVALUATE_REMOTE = 3;
private static final int MSG_RCC_NEW_PLAYBACK_INFO = 4;
private static final int MSG_RCC_NEW_VOLUME_OBS = 5;
- private static final int MSG_PROMOTE_RCC = 6;
- private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7;
- private static final int MSG_RCC_SEEK_REQUEST = 8;
- private static final int MSG_RCC_UPDATE_METADATA = 9;
- private static final int MSG_RCDISPLAY_INIT_INFO = 10;
- private static final int MSG_REEVALUATE_RCD = 11;
- private static final int MSG_UNREGISTER_MEDIABUTTONINTENT = 12;
+ private static final int MSG_RCC_NEW_PLAYBACK_STATE = 6;
+ private static final int MSG_RCC_SEEK_REQUEST = 7;
+ private static final int MSG_RCC_UPDATE_METADATA = 8;
+ private static final int MSG_RCDISPLAY_INIT_INFO = 9;
+ private static final int MSG_REEVALUATE_RCD = 10;
+ private static final int MSG_UNREGISTER_MEDIABUTTONINTENT = 11;
// sendMsg() flags
/** If the msg is already queued, replace it with this one. */
@@ -406,10 +405,6 @@
(Rating) msg.obj /* value */);
break;
- case MSG_PROMOTE_RCC:
- onPromoteRcc(msg.arg1);
- break;
-
case MSG_RCDISPLAY_INIT_INFO:
// msg.obj is guaranteed to be non null
onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
@@ -1212,56 +1207,91 @@
mediaButtonIntent.setComponent(eventReceiver);
PendingIntent pi = PendingIntent.getBroadcast(mContext,
0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
- registerMediaButtonIntent(pi, eventReceiver, null);
+ registerMediaButtonIntent(pi, eventReceiver, null /*token*/);
}
}
/**
* Helper function:
- * Set the new remote control receiver at the top of the RC focus stack.
+ * Push the new media button receiver "near" the top of the PlayerRecord stack.
+ * "Near the top" is defined as:
+ * - at the top if the current PlayerRecord at the top is not playing
+ * - below the entries at the top of the stack that correspond to the playing PlayerRecord
+ * otherwise
* Called synchronized on mPRStack
* precondition: mediaIntent != null
- * @return true if mPRStack was changed, false otherwise
+ * @return true if the top of mPRStack was changed, false otherwise
*/
private boolean pushMediaButtonReceiver_syncPrs(PendingIntent mediaIntent,
ComponentName target, IBinder token) {
- // already at top of stack?
- if (!mPRStack.empty() && mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) {
+ if (mPRStack.empty()) {
+ mPRStack.push(new PlayerRecord(mediaIntent, target, token));
+ return true;
+ } else if (mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) {
+ // already at top of stack
return false;
}
if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
return false;
}
+ PlayerRecord oldTopPrse = mPRStack.lastElement(); // top of the stack before any changes
+ boolean topChanged = false;
PlayerRecord prse = null;
- boolean wasInsideStack = false;
+ int lastPlayingIndex = mPRStack.size();
+ int inStackIndex = -1;
try {
+ // go through the stack from the top to figure out who's playing, and the position
+ // of this media button receiver (note that it may not be in the stack)
for (int index = mPRStack.size()-1; index >= 0; index--) {
prse = mPRStack.elementAt(index);
- if(prse.hasMatchingMediaButtonIntent(mediaIntent)) {
- // ok to remove element while traversing the stack since we're leaving the loop
- mPRStack.removeElementAt(index);
- wasInsideStack = true;
+ if (prse.isPlaybackActive()) {
+ lastPlayingIndex = index;
+ }
+ if (prse.hasMatchingMediaButtonIntent(mediaIntent)) {
+ inStackIndex = index;
+ // found it, ok to stop here
break;
}
}
+
+ if (inStackIndex == -1) {
+ // is not in stack
+ prse = new PlayerRecord(mediaIntent, target, token);
+ // it's new so it's not playing (no RemoteControlClient to give a playstate),
+ // therefore it goes after the ones with active playback
+ mPRStack.add(lastPlayingIndex, prse);
+ } else {
+ // is in the stack
+ if (mPRStack.size() > 1) { // no need to remove and add if stack contains only 1
+ prse = mPRStack.elementAt(inStackIndex);
+ // remove it from its old location in the stack
+ mPRStack.removeElementAt(inStackIndex);
+ if (prse.isPlaybackActive()) {
+ // and put it at the top
+ mPRStack.push(prse);
+ } else {
+ // and put it after the ones with active playback
+ mPRStack.add(lastPlayingIndex, prse);
+ }
+ }
+ }
+
+ topChanged = (oldTopPrse != mPRStack.lastElement());
+ // post message to persist the default media button receiver
+ if (topChanged && (target != null)) {
+ mEventHandler.sendMessage( mEventHandler.obtainMessage(
+ MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
+ }
+
} catch (ArrayIndexOutOfBoundsException e) {
- // not expected to happen, indicates improper concurrent modification
- Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
- }
- if (!wasInsideStack) {
- prse = new PlayerRecord(mediaIntent, target, token);
- }
- mPRStack.push(prse); // prse is never null
-
- // post message to persist the default media button receiver
- if (target != null) {
- mEventHandler.sendMessage( mEventHandler.obtainMessage(
- MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
+ // not expected to happen, indicates improper concurrent modification or bad index
+ Log.e(TAG, "Wrong index (inStack=" + inStackIndex + " lastPlaying=" + lastPlayingIndex
+ + " size=" + mPRStack.size()
+ + " accessing media button stack", e);
}
- // RC stack was modified
- return true;
+ return (topChanged);
}
/**
@@ -1515,48 +1545,6 @@
}
/**
- * Helper function:
- * Post a message to asynchronously move the media button event receiver associated with the
- * given remote control client ID to the top of the remote control stack
- * @param rccId
- */
- private void postPromoteRcc(int rccId) {
- sendMsg(mEventHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE,
- rccId /*arg1*/, 0, null, 0/*delay*/);
- }
-
- private void onPromoteRcc(int rccId) {
- if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); }
- synchronized(mPRStack) {
- // ignore if given RCC ID is already at top of remote control stack
- if (!mPRStack.isEmpty() && (mPRStack.peek().getRccId() == rccId)) {
- return;
- }
- int indexToPromote = -1;
- try {
- for (int index = mPRStack.size()-1; index >= 0; index--) {
- final PlayerRecord prse = mPRStack.elementAt(index);
- if (prse.getRccId() == rccId) {
- indexToPromote = index;
- break;
- }
- }
- if (indexToPromote >= 0) {
- if (DEBUG_RC) { Log.d(TAG, " moving RCC from index " + indexToPromote
- + " to " + (mPRStack.size()-1)); }
- final PlayerRecord prse = mPRStack.remove(indexToPromote);
- mPRStack.push(prse);
- // the RC stack changed, reevaluate the display
- checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- // not expected to happen, indicates improper concurrent modification
- Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
- }
- }//synchronized(mPRStack)
- }
-
- /**
* see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
* precondition: mediaIntent != null
*/
@@ -2151,30 +2139,66 @@
if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
+ ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
synchronized(mPRStack) {
- // iterating from top of stack as playback information changes are more likely
- // on entries at the top of the remote control stack
+ if (mPRStack.empty()) {
+ return;
+ }
+ PlayerRecord oldTopPrse = mPRStack.lastElement(); // top of the stack before any changes
+ PlayerRecord prse = null;
+ int lastPlayingIndex = mPRStack.size();
+ int inStackIndex = -1;
try {
+ // go through the stack from the top to figure out who's playing, and the position
+ // of this RemoteControlClient (note that it may not be in the stack)
for (int index = mPRStack.size()-1; index >= 0; index--) {
- final PlayerRecord prse = mPRStack.elementAt(index);
+ prse = mPRStack.elementAt(index);
+ if (prse.isPlaybackActive()) {
+ lastPlayingIndex = index;
+ }
if (prse.getRccId() == rccId) {
+ inStackIndex = index;
prse.mPlaybackState = newState;
- synchronized (mMainRemote) {
- if (rccId == mMainRemote.mRccId) {
- mMainRemoteIsActive = isPlaystateActive(state);
- postReevaluateRemote();
- }
- }
- // an RCC moving to a "playing" state should become the media button
- // event receiver so it can be controlled, without requiring the
- // app to re-register its receiver
- if (isPlaystateActive(state)) {
- postPromoteRcc(rccId);
+ }
+ }
+
+ if (inStackIndex != -1) {
+ // is in the stack
+ prse = mPRStack.elementAt(inStackIndex);
+ synchronized (mMainRemote) {
+ if (rccId == mMainRemote.mRccId) {
+ mMainRemoteIsActive = isPlaystateActive(state);
+ postReevaluateRemote();
}
}
- }//for
+ if (mPRStack.size() > 1) { // no need to remove and add if stack contains only 1
+ // remove it from its old location in the stack
+ mPRStack.removeElementAt(inStackIndex);
+ if (prse.isPlaybackActive()) {
+ // and put it at the top
+ mPRStack.push(prse);
+ } else {
+ // and put it after the ones with active playback
+ mPRStack.add(lastPlayingIndex, prse);
+ }
+ }
+
+ if (oldTopPrse != mPRStack.lastElement()) {
+ // the top of the stack changed:
+ final ComponentName target =
+ mPRStack.lastElement().getMediaButtonReceiver();
+ if (target != null) {
+ // post message to persist the default media button receiver
+ mEventHandler.sendMessage( mEventHandler.obtainMessage(
+ MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
+ }
+ // reevaluate the display
+ checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+ }
+ }
} catch (ArrayIndexOutOfBoundsException e) {
- // not expected to happen, indicates improper concurrent modification
- Log.e(TAG, "Wrong index on mPRStack in onNewPlaybackStateForRcc, lock error? ", e);
+ // not expected to happen, indicates improper concurrent modification or bad index
+ Log.e(TAG, "Wrong index (inStack=" + inStackIndex + " lastPlaying=" + lastPlayingIndex
+ + " size=" + mPRStack.size()
+ + "accessing PlayerRecord stack in onNewPlaybackStateForRcc", e);
}
}
}
@@ -2249,7 +2273,7 @@
* @param playState the playback state to evaluate
* @return true if active, false otherwise (inactive or unknown)
*/
- private static boolean isPlaystateActive(int playState) {
+ protected static boolean isPlaystateActive(int playState) {
switch (playState) {
case RemoteControlClient.PLAYSTATE_PLAYING:
case RemoteControlClient.PLAYSTATE_BUFFERING:
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 72f3e1a..6424a98 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1281,6 +1281,14 @@
mMediaProvider = null;
}
+ private void releaseResources() {
+ // release the DrmManagerClient resources
+ if (mDrmManagerClient != null) {
+ mDrmManagerClient.release();
+ mDrmManagerClient = null;
+ }
+ }
+
private void initialize(String volumeName) {
mMediaProvider = mContext.getContentResolver().acquireProvider("media");
@@ -1341,6 +1349,8 @@
Log.e(TAG, "UnsupportedOperationException in MediaScanner.scan()", e);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scan()", e);
+ } finally {
+ releaseResources();
}
}
@@ -1364,6 +1374,8 @@
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
return null;
+ } finally {
+ releaseResources();
}
}
@@ -1511,6 +1523,7 @@
if (fileList != null) {
fileList.close();
}
+ releaseResources();
}
}
diff --git a/media/java/android/media/PlayerRecord.java b/media/java/android/media/PlayerRecord.java
index a79b0ed..f9708c3 100644
--- a/media/java/android/media/PlayerRecord.java
+++ b/media/java/android/media/PlayerRecord.java
@@ -58,6 +58,9 @@
private int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
+ /**
+ * A non-null token implies this record tracks a "live" player whose death is being monitored.
+ */
private IBinder mToken;
private String mCallingPackageName;
private int mCallingUid;
@@ -254,20 +257,20 @@
return mMediaIntent;
}
- // FIXME this is only used when comparing with the audio focus owner calling package name,
- // accessor to be removed once audio focus and media button owner are dissociated
- protected String getCallingPackageName() {
- return mCallingPackageName;
- }
-
- // FIXME this is only used when comparing with the audio focus owner calling package name,
- // accessor to be removed once audio focus and media button owner are dissociated
- protected int getCallingUid() {
- return mCallingUid;
- }
-
protected boolean hasMatchingMediaButtonIntent(PendingIntent pi) {
- return mMediaIntent.equals(pi);
+ if (mToken != null) {
+ return mMediaIntent.equals(pi);
+ } else {
+ if (mReceiverComponent != null) {
+ return mReceiverComponent.equals(pi.getIntent().getComponent());
+ } else {
+ return false;
+ }
+ }
+ }
+
+ protected boolean isPlaybackActive() {
+ return MediaFocusControl.isPlaystateActive(mPlaybackState.mState);
}
//---------------------------------------------
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 1283e9b..2616b6c 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -217,7 +217,7 @@
if (mAudioManager.getStreamVolume(mStreamType) != 0) {
mLocalPlayer.start();
}
- } else if (mAllowRemote) {
+ } else if (mAllowRemote && (mRemotePlayer != null)) {
final Uri canonicalUri = mUri.getCanonicalUri();
try {
mRemotePlayer.play(mRemoteToken, canonicalUri, mStreamType);
@@ -239,7 +239,7 @@
public void stop() {
if (mLocalPlayer != null) {
destroyLocalPlayer();
- } else if (mAllowRemote) {
+ } else if (mAllowRemote && (mRemotePlayer != null)) {
try {
mRemotePlayer.stop(mRemoteToken);
} catch (RemoteException e) {
@@ -264,7 +264,7 @@
public boolean isPlaying() {
if (mLocalPlayer != null) {
return mLocalPlayer.isPlaying();
- } else if (mAllowRemote) {
+ } else if (mAllowRemote && (mRemotePlayer != null)) {
try {
return mRemotePlayer.isPlaying(mRemoteToken);
} catch (RemoteException e) {
diff --git a/media/java/android/media/session/IMediaSessionManager.aidl b/media/java/android/media/routeprovider/IRouteConnection.aidl
similarity index 65%
copy from media/java/android/media/session/IMediaSessionManager.aidl
copy to media/java/android/media/routeprovider/IRouteConnection.aidl
index 0b4328e..15c8039 100644
--- a/media/java/android/media/session/IMediaSessionManager.aidl
+++ b/media/java/android/media/routeprovider/IRouteConnection.aidl
@@ -13,16 +13,16 @@
* limitations under the License.
*/
-package android.media.session;
+package android.media.routeprovider;
-import android.media.session.IMediaSession;
-import android.media.session.IMediaSessionCallback;
-import android.os.Bundle;
+import android.media.session.RouteCommand;
+import android.os.ResultReceiver;
/**
- * Interface to the MediaSessionManagerService
+ * Interface for a specific connected route.
* @hide
*/
-interface IMediaSessionManager {
- IMediaSession createSession(String packageName, in IMediaSessionCallback cb, String tag);
+oneway interface IRouteConnection {
+ void onCommand(in RouteCommand command, in ResultReceiver cb);
+ void disconnect();
}
\ No newline at end of file
diff --git a/media/java/android/media/routeprovider/IRouteProvider.aidl b/media/java/android/media/routeprovider/IRouteProvider.aidl
new file mode 100644
index 0000000..c36f6a7
--- /dev/null
+++ b/media/java/android/media/routeprovider/IRouteProvider.aidl
@@ -0,0 +1,36 @@
+/* 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.media.routeprovider;
+
+import android.media.routeprovider.IRouteConnection;
+import android.media.routeprovider.IRouteProviderCallback;
+import android.media.routeprovider.RouteRequest;
+import android.media.session.RouteInfo;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+
+/**
+ * Interface to an app's RouteProviderService.
+ * @hide
+ */
+oneway interface IRouteProvider {
+ void registerCallback(in IRouteProviderCallback cb);
+ void unregisterCallback(in IRouteProviderCallback cb);
+ void updateDiscoveryRequests(in List<RouteRequest> requests);
+
+ void getAvailableRoutes(in List<RouteRequest> requests, in ResultReceiver cb);
+ void connect(in RouteInfo route, in RouteRequest request, in ResultReceiver cb);
+}
\ No newline at end of file
diff --git a/media/java/android/media/routeprovider/IRouteProviderCallback.aidl b/media/java/android/media/routeprovider/IRouteProviderCallback.aidl
new file mode 100644
index 0000000..9185347
--- /dev/null
+++ b/media/java/android/media/routeprovider/IRouteProviderCallback.aidl
@@ -0,0 +1,32 @@
+/* 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.media.routeprovider;
+
+import android.media.routeprovider.IRouteConnection;
+import android.media.session.RouteEvent;
+import android.os.Bundle;
+import android.os.ResultReceiver;
+
+/**
+ * System's provider callback interface.
+ * @hide
+ */
+oneway interface IRouteProviderCallback {
+ void onRoutesChanged();
+ void onConnectionStateChanged(in IRouteConnection connection, int state);
+ void onConnectionTerminated(in IRouteConnection connection);
+ void onRouteEvent(in RouteEvent event);
+}
\ No newline at end of file
diff --git a/media/java/android/media/routeprovider/RouteConnection.java b/media/java/android/media/routeprovider/RouteConnection.java
new file mode 100644
index 0000000..9214ff8
--- /dev/null
+++ b/media/java/android/media/routeprovider/RouteConnection.java
@@ -0,0 +1,164 @@
+/*
+ * 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.media.routeprovider;
+
+import android.media.routeprovider.IRouteConnection;
+import android.media.session.RouteCommand;
+import android.media.session.RouteEvent;
+import android.media.session.RouteInfo;
+import android.media.session.RouteInterface;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents an ongoing connection between an application and a media route
+ * offered by a media route provider.
+ * <p>
+ * The media route provider should add interfaces to the connection before
+ * returning it to the system in order to receive commands from clients on those
+ * interfaces. Use {@link #addRouteInterface(String)} to add an interface and
+ * {@link #getRouteInterface(String)} to retrieve the interface's handle anytime
+ * after it has been added.
+ */
+public final class RouteConnection {
+ private static final String TAG = "RouteConnection";
+ private final ConnectionStub mBinder;
+ private final ArrayList<String> mIfaceNames = new ArrayList<String>();
+ private final ArrayMap<String, RouteInterfaceHandler> mIfaces
+ = new ArrayMap<String, RouteInterfaceHandler>();
+ private final RouteProviderService mProvider;
+ private final RouteInfo mRoute;
+
+ private boolean mPublished;
+
+ /**
+ * Create a new connection for the given Provider and Route.
+ *
+ * @param provider The provider this route is associated with.
+ * @param route The route this is a connection to.
+ */
+ public RouteConnection(RouteProviderService provider, RouteInfo route) {
+ if (provider == null) {
+ throw new IllegalArgumentException("provider may not be null.");
+ }
+ if (route == null) {
+ throw new IllegalArgumentException("route may not be null.");
+ }
+ mBinder = new ConnectionStub(this);
+ mProvider = provider;
+ mRoute = route;
+ }
+
+ /**
+ * Add an interface to this route connection. All interfaces must be added
+ * to the connection before the connection is returned to the system.
+ *
+ * @param ifaceName The name of the interface to add
+ * @return The route interface that was registered
+ */
+ public RouteInterfaceHandler addRouteInterface(String ifaceName) {
+ if (TextUtils.isEmpty(ifaceName)) {
+ throw new IllegalArgumentException("The interface's name may not be empty");
+ }
+ if (mPublished) {
+ throw new IllegalStateException(
+ "Connection has already been published to the system.");
+ }
+ RouteInterfaceHandler iface = mIfaces.get(ifaceName);
+ if (iface == null) {
+ iface = new RouteInterfaceHandler(this, ifaceName);
+ mIfaceNames.add(ifaceName);
+ mIfaces.put(ifaceName, iface);
+ } else {
+ Log.w(TAG, "Attempted to add an interface that already exists");
+ }
+ return iface;
+ }
+
+ /**
+ * Get the interface instance for the specified interface name. If the
+ * interface was not added to this connection null will be returned.
+ *
+ * @param ifaceName The name of the interface to get.
+ * @return The route interface with that name or null.
+ */
+ public RouteInterfaceHandler getRouteInterface(String ifaceName) {
+ return mIfaces.get(ifaceName);
+ }
+
+ /**
+ * Close the connection and inform the system that it may no longer be used.
+ */
+ public void shutDown() {
+ mProvider.disconnect(this);
+ }
+
+ /**
+ * @hide
+ */
+ public void sendEvent(String iface, String event, Bundle extras) {
+ RouteEvent e = new RouteEvent(mBinder, iface, event, extras);
+ mProvider.sendRouteEvent(e);
+ }
+
+ /**
+ * @hide
+ */
+ IRouteConnection.Stub getBinder() {
+ return mBinder;
+ }
+
+ /**
+ * @hide
+ */
+ void publish() {
+ mPublished = true;
+ }
+
+ private static class ConnectionStub extends IRouteConnection.Stub {
+ private final WeakReference<RouteConnection> mConnection;
+
+ public ConnectionStub(RouteConnection connection) {
+ mConnection = new WeakReference<RouteConnection>(connection);
+ }
+
+ @Override
+ public void onCommand(RouteCommand command, ResultReceiver cb) {
+ RouteConnection connection = mConnection.get();
+ if (connection != null) {
+ RouteInterfaceHandler iface = connection.mIfaces.get(command.getIface());
+ if (iface != null) {
+ iface.onCommand(command.getEvent(), command.getExtras(), cb);
+ } else if (cb != null) {
+ cb.send(RouteInterface.RESULT_INTERFACE_NOT_SUPPORTED, null);
+ }
+ }
+ }
+
+ @Override
+ public void disconnect() {
+ // TODO
+ }
+ }
+}
diff --git a/media/java/android/media/routeprovider/RouteInterfaceHandler.java b/media/java/android/media/routeprovider/RouteInterfaceHandler.java
new file mode 100644
index 0000000..9693dc6
--- /dev/null
+++ b/media/java/android/media/routeprovider/RouteInterfaceHandler.java
@@ -0,0 +1,245 @@
+/*
+ * 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.media.routeprovider;
+
+import android.media.session.Route;
+import android.media.session.Session;
+import android.media.session.RouteInterface;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ResultReceiver;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Represents an interface that an application may use to send requests to a
+ * connected media route.
+ * <p>
+ * A {@link RouteProviderService} may expose multiple interfaces on a
+ * {@link RouteConnection} for a {@link Session} to interact with. A
+ * provider creates an interface with
+ * {@link RouteConnection#addRouteInterface(String)} to allow messages to be
+ * routed appropriately. Events are then sent through a specific interface and
+ * all commands being sent on the interface will be sent to any registered
+ * {@link CommandListener}s.
+ * <p>
+ * An interface instance can only be registered on one {@link RouteConnection}.
+ * To use the same interface on multiple connections a new instance must be
+ * created for each connection.
+ * <p>
+ * It is recommended you wrap this interface with a standard implementation to
+ * avoid errors, but for simple interfaces this class may be used directly. TODO
+ * add link to sample code.
+ */
+public final class RouteInterfaceHandler {
+ private static final String TAG = "RouteInterfaceHandler";
+
+ private final Object mLock = new Object();
+ private final RouteConnection mConnection;
+ private final String mName;
+
+ private ArrayList<MessageHandler> mListeners = new ArrayList<MessageHandler>();
+
+ /**
+ * Create a new RouteInterface for a given connection. This can be used to
+ * send events on the given interface and register listeners for commands
+ * from the connected session.
+ *
+ * @param connection The connection this interface sends events on
+ * @param ifaceName The name of this interface
+ * @hide
+ */
+ public RouteInterfaceHandler(RouteConnection connection, String ifaceName) {
+ if (connection == null) {
+ throw new IllegalArgumentException("connection may not be null");
+ }
+ if (TextUtils.isEmpty(ifaceName)) {
+ throw new IllegalArgumentException("ifaceName can not be empty");
+ }
+ mConnection = connection;
+ mName = ifaceName;
+ }
+
+ /**
+ * Send an event on this interface to the connected session.
+ *
+ * @param event The event to send
+ * @param extras Any extras for the event
+ */
+ public void sendEvent(String event, Bundle extras) {
+ mConnection.sendEvent(mName, event, extras);
+ }
+
+ /**
+ * Send a result from a command to the specified callback. The result codes
+ * in {@link RouteInterface} must be used. More information
+ * about the result, whether successful or an error, should be included in
+ * the extras.
+ *
+ * @param cb The callback to send the result to
+ * @param resultCode The result code for the call
+ * @param extras Any extras to include
+ */
+ public static void sendResult(ResultReceiver cb, int resultCode, Bundle extras) {
+ if (cb != null) {
+ cb.send(resultCode, extras);
+ }
+ }
+
+ /**
+ * Add a listener for this interface. If a handler is specified callbacks
+ * will be performed on the handler's thread, otherwise the callers thread
+ * will be used.
+ *
+ * @param listener The listener to receive calls on.
+ * @param handler The handler whose thread to post calls on or null.
+ */
+ public void addListener(CommandListener listener, Handler handler) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener may not be null");
+ }
+ Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+ synchronized (mLock) {
+ if (findIndexOfListenerLocked(listener) != -1) {
+ Log.d(TAG, "Listener is already added, ignoring");
+ return;
+ }
+ mListeners.add(new MessageHandler(looper, listener));
+ }
+ }
+
+ /**
+ * Remove a listener from this interface.
+ *
+ * @param listener The listener to stop receiving commands on.
+ */
+ public void removeListener(CommandListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener may not be null");
+ }
+ synchronized (mLock) {
+ int index = findIndexOfListenerLocked(listener);
+ if (index != -1) {
+ mListeners.remove(index);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void onCommand(String command, Bundle args, ResultReceiver cb) {
+ synchronized (mLock) {
+ Command cmd = new Command(command, args, cb);
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).post(MessageHandler.MSG_COMMAND, cmd);
+ }
+ }
+ }
+
+ /**
+ * Get the interface name.
+ *
+ * @return The name of this interface
+ */
+ public String getName() {
+ return mName;
+ }
+
+ private int findIndexOfListenerLocked(CommandListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Callback cannot be null");
+ }
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ MessageHandler handler = mListeners.get(i);
+ if (listener == handler.mListener) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Handles commands sent to the interface.
+ * <p>
+ * Register an InterfaceListener using {@link #addListener}.
+ */
+ public abstract static class CommandListener {
+ /**
+ * This is called when a command is received that matches this
+ * interface. Commands are sent by a {@link Session} that is
+ * connected to the route this interface is registered with.
+ *
+ * @param iface The interface the command was received on.
+ * @param command The command or method to invoke.
+ * @param args Any args that were included with the command. May be
+ * null.
+ * @param cb The callback provided to send a response on. May be null.
+ * @return true if the command was handled, false otherwise. If the
+ * command was not handled an error will be sent automatically.
+ * true may be returned if the command will be handled
+ * asynchronously.
+ * @see Route
+ * @see Session
+ */
+ public abstract boolean onCommand(RouteInterfaceHandler iface, String command, Bundle args,
+ ResultReceiver cb);
+ }
+
+ private class MessageHandler extends Handler {
+ private static final int MSG_COMMAND = 1;
+
+ private final CommandListener mListener;
+
+ public MessageHandler(Looper looper, CommandListener listener) {
+ super(looper, null, true /* async */);
+ mListener = listener;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_COMMAND:
+ Command cmd = (Command) msg.obj;
+ if (!mListener.onCommand(RouteInterfaceHandler.this, cmd.command, cmd.args, cmd.cb)) {
+ sendResult(cmd.cb, RouteInterface.RESULT_COMMAND_NOT_SUPPORTED,
+ null);
+ }
+ break;
+ }
+ }
+
+ public void post(int what, Object obj) {
+ obtainMessage(what, obj).sendToTarget();
+ }
+ }
+
+ private final static class Command {
+ public final String command;
+ public final Bundle args;
+ public final ResultReceiver cb;
+
+ public Command(String command, Bundle args, ResultReceiver cb) {
+ this.command = command;
+ this.args = args;
+ this.cb = cb;
+ }
+ }
+}
diff --git a/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java b/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java
new file mode 100644
index 0000000..dcef79a
--- /dev/null
+++ b/media/java/android/media/routeprovider/RoutePlaybackControlsHandler.java
@@ -0,0 +1,221 @@
+/*
+ * 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.media.routeprovider;
+
+import android.media.session.RoutePlaybackControls;
+import android.media.session.RouteInterface;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Standard wrapper for using playback controls over a {@link RouteInterfaceHandler}.
+ * This is the provider half of the interface. Sessions should use
+ * {@link RoutePlaybackControls} to interact with this interface.
+ */
+public final class RoutePlaybackControlsHandler {
+ private static final String TAG = "RoutePlaybackControls";
+
+ private final RouteInterfaceHandler mIface;
+
+ private RoutePlaybackControlsHandler(RouteInterfaceHandler iface) {
+ mIface = iface;
+ }
+
+ /**
+ * Add this interface to the specified route and return a handle for
+ * communicating on the interface.
+ *
+ * @param connection The connection to register this interface on.
+ * @return A handle for communicating on this interface.
+ */
+ public static RoutePlaybackControlsHandler addTo(RouteConnection connection) {
+ if (connection == null) {
+ throw new IllegalArgumentException("connection may not be null");
+ }
+ RouteInterfaceHandler iface = connection
+ .addRouteInterface(RoutePlaybackControls.NAME);
+
+ return new RoutePlaybackControlsHandler(iface);
+ }
+
+ /**
+ * Add a {@link Listener} to this interface. The listener will receive
+ * commands on the caller's thread.
+ *
+ * @param listener The listener to send commands to.
+ */
+ public void addListener(Listener listener) {
+ addListener(listener, null);
+ }
+
+ /**
+ * Add a {@link Listener} to this interface. The listener will receive
+ * updates on the handler's thread. If no handler is specified the caller's
+ * thread will be used instead.
+ *
+ * @param listener The listener to send commands to.
+ * @param handler The handler whose thread calls should be posted on. May be
+ * null.
+ */
+ public void addListener(Listener listener, Handler handler) {
+ mIface.addListener(listener, handler);
+ }
+
+ /**
+ * Remove a {@link Listener} from this interface.
+ *
+ * @param listener The Listener to remove.
+ */
+ public void removeListener(Listener listener) {
+ mIface.removeListener(listener);
+ }
+
+ /**
+ * Publish the current playback state to the system and any controllers.
+ * Valid values are defined in {@link PlaybackState}. TODO create
+ * RoutePlaybackState.
+ *
+ * @param state
+ */
+ public void sendPlaybackChangeEvent(int state) {
+ Bundle extras = new Bundle();
+ extras.putInt(RoutePlaybackControls.KEY_VALUE1, state);
+ mIface.sendEvent(RoutePlaybackControls.EVENT_PLAYSTATE_CHANGE, extras);
+ }
+
+ /**
+ * Command handler for the RoutePlaybackControls interface. You can add a
+ * Listener to the interface using {@link #addListener}.
+ */
+ public static abstract class Listener extends RouteInterfaceHandler.CommandListener {
+
+ @Override
+ public final boolean onCommand(RouteInterfaceHandler iface, String method, Bundle extras,
+ ResultReceiver cb) {
+ if (RoutePlaybackControls.CMD_FAST_FORWARD.equals(method)) {
+ boolean success = fastForward();
+ // TODO specify type of error
+ RouteInterfaceHandler.sendResult(cb, success
+ ? RouteInterface.RESULT_SUCCESS
+ : RouteInterface.RESULT_ERROR, null);
+ return true;
+ } else if (RoutePlaybackControls.CMD_GET_CURRENT_POSITION.equals(method)) {
+ Bundle result = new Bundle();
+ result.putLong(RoutePlaybackControls.KEY_VALUE1, getCurrentPosition());
+ RouteInterfaceHandler.sendResult(cb, RouteInterface.RESULT_SUCCESS,
+ result);
+ return true;
+ } else if (RoutePlaybackControls.CMD_GET_CAPABILITIES.equals(method)) {
+ Bundle result = new Bundle();
+ result.putLong(RoutePlaybackControls.KEY_VALUE1, getCapabilities());
+ RouteInterfaceHandler.sendResult(cb, RouteInterface.RESULT_SUCCESS,
+ result);
+ return true;
+ } else if (RoutePlaybackControls.CMD_PLAY_NOW.equals(method)) {
+ playNow(extras.getString(RoutePlaybackControls.KEY_VALUE1, null), cb);
+ return true;
+ } else if (RoutePlaybackControls.CMD_RESUME.equals(method)) {
+ boolean success = resume();
+ RouteInterfaceHandler.sendResult(cb, success
+ ? RouteInterface.RESULT_SUCCESS
+ : RouteInterface.RESULT_ERROR, null);
+ return true;
+ } else if (RoutePlaybackControls.CMD_PAUSE.equals(method)) {
+ boolean success = pause();
+ RouteInterfaceHandler.sendResult(cb, success
+ ? RouteInterface.RESULT_SUCCESS
+ : RouteInterface.RESULT_ERROR, null);
+ return true;
+ } else {
+ // The command wasn't recognized
+ }
+ return false;
+ }
+
+ /**
+ * Override to handle fast forwarding.
+ *
+ * @return true if the request succeeded, false otherwise
+ */
+ public boolean fastForward() {
+ Log.w(TAG, "fastForward is not supported.");
+ return false;
+ }
+
+ /**
+ * Override to handle getting the current position of playback in
+ * millis.
+ *
+ * @return The current position in millis or -1
+ */
+ public long getCurrentPosition() {
+ Log.w(TAG, "getCurrentPosition is not supported");
+ return -1;
+ }
+
+ /**
+ * Override to handle getting the set of capabilities currently
+ * available.
+ *
+ * @return A bit mask of the supported capabilities
+ */
+ public long getCapabilities() {
+ Log.w(TAG, "getCapabilities is not supported");
+ return 0;
+ }
+
+ /**
+ * Override to handle play now requests.
+ *
+ * @param content The uri of the item to play.
+ * @param cb The callback to send the result to.
+ */
+ public void playNow(String content, ResultReceiver cb) {
+ Log.w(TAG, "playNow is not supported");
+ if (cb != null) {
+ // We do this directly since we don't have a reference to the
+ // iface
+ cb.send(RouteInterface.RESULT_COMMAND_NOT_SUPPORTED, null);
+ }
+ }
+
+ /**
+ * Override to handle resume requests. Return true if the call was
+ * handled, even if it was a no-op.
+ *
+ * @return true if the call was handled.
+ */
+ public boolean resume() {
+ Log.w(TAG, "resume is not supported");
+ return false;
+ }
+
+ /**
+ * Override to handle pause requests. Return true if the call was
+ * handled, even if it was a no-op.
+ *
+ * @return true if the call was handled.
+ */
+ public boolean pause() {
+ Log.w(TAG, "pause is not supported");
+ return false;
+ }
+ }
+}
diff --git a/media/java/android/media/routeprovider/RouteProviderService.java b/media/java/android/media/routeprovider/RouteProviderService.java
new file mode 100644
index 0000000..6ebfb5b
--- /dev/null
+++ b/media/java/android/media/routeprovider/RouteProviderService.java
@@ -0,0 +1,227 @@
+/*
+ * 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.media.routeprovider;
+
+import android.app.Service;
+import android.content.Intent;
+import android.media.routeprovider.IRouteProvider;
+import android.media.routeprovider.IRouteProviderCallback;
+import android.media.session.RouteEvent;
+import android.media.session.RouteInfo;
+import android.media.session.RouteOptions;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for defining a route provider service.
+ * <p>
+ * A route provider offers media routes which represent destinations to which
+ * applications may connect, control, and send content. This provides a means
+ * for Android applications to interact with a variety of media streaming
+ * devices such as speakers or television sets.
+ * <p>
+ * The system will bind to your provider when an active app is interested in
+ * routes that may be discovered through your provider. After binding, the
+ * system will send updates on which routes to discover through
+ * {@link #updateDiscoveryRequests(List)}. The system will call
+ * {@link #getMatchingRoutes(List)} with a subset of filters when a route is
+ * needed for a specific app.
+ * <p>
+ * TODO add documentation for how the sytem knows an app is interested. Maybe
+ * interface declarations in the manifest.
+ * <p>
+ * The system will only start a provider when an app may discover routes through
+ * it. If your service needs to run at other times you are responsible for
+ * managing its lifecycle.
+ * <p>
+ * Declare your route provider service in your application manifest like this:
+ * <p>
+ *
+ * <pre>
+ * <service android:name=".MyRouteProviderService"
+ * android:label="@string/my_route_provider_service">
+ * <intent-filter>
+ * <action android:name="com.android.media.session.MediaRouteProvider" />
+ * </intent-filter>
+ * </service>
+ * </pre>
+ */
+public abstract class RouteProviderService extends Service {
+ private static final String TAG = "RouteProvider";
+ /**
+ * A service that implements a RouteProvider must declare that it handles
+ * this action in its AndroidManifest.
+ */
+ public static final String SERVICE_INTERFACE =
+ "com.android.media.session.MediaRouteProvider";
+
+ /**
+ * @hide
+ */
+ public static final String KEY_ROUTES = "routes";
+ /**
+ * @hide
+ */
+ public static final String KEY_CONNECTION = "connection";
+ /**
+ * @hide
+ */
+ public static final int RESULT_FAILURE = -1;
+ /**
+ * @hide
+ */
+ public static final int RESULT_SUCCESS = 0;
+
+ // The system's callback once it has bound to the service
+ private IRouteProviderCallback mCb;
+
+ /**
+ * If your service overrides onBind it must return super.onBind() in
+ * response to the {@link #SERVICE_INTERFACE} action.
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (intent != null && RouteProviderService.SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mBinder;
+ }
+ return null;
+ }
+
+ /**
+ * Disconnect the specified RouteConnection. The system will stop sending
+ * commands to this connection.
+ *
+ * @param connection The connection to disconnect.
+ * @hide
+ */
+ public final void disconnect(RouteConnection connection) {
+ if (mCb != null) {
+ try {
+ mCb.onConnectionTerminated(connection.getBinder());
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error in disconnect.", e);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public final void sendRouteEvent(RouteEvent event) {
+ if (mCb != null) {
+ try {
+ mCb.onRouteEvent(event);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Unable to send MediaRouteEvent to system", e);
+ }
+ }
+ }
+
+ /**
+ * Override to handle updates to the routes that are of interest. Each
+ * {@link RouteRequest} will specify if it is an active or passive request.
+ * Route discovery may perform more aggressive discovery on behalf of active
+ * requests but should use low power discovery methods otherwise.
+ * <p>
+ * A single app may have more than one request. Your provider is responsible
+ * for deciding the set of features that are important for discovery given
+ * the set of requests. If your provider only has one method of discovery it
+ * may simply verify that one or more requests are valid before starting
+ * discovery.
+ *
+ * @param requests The route requests that are currently relevant.
+ */
+ public void updateDiscoveryRequests(List<RouteRequest> requests) {
+ }
+
+ /**
+ * Return a list of matching routes for the given set of requests. Returning
+ * null or an empty list indicates there are no matches. A route is
+ * considered matching if it supports one or more of the
+ * {@link RouteOptions} specified. Each returned {@link RouteInfo}
+ * should include all the requested connections that it supports.
+ *
+ * @param options The set of requests for routes
+ * @return The routes that this caller may connect to using one or more of
+ * the route options.
+ */
+ public abstract List<RouteInfo> getMatchingRoutes(List<RouteRequest> options);
+
+ /**
+ * Handle a request to connect to a specific route with a specific request.
+ * The {@link RouteConnection} must be fully defined before being returned,
+ * though the actual connection to the route may be performed in the
+ * background.
+ *
+ * @param route The route to connect to
+ * @param request The connection request parameters
+ * @return A MediaRouteConnection representing the connection to the route
+ */
+ public abstract RouteConnection connect(RouteInfo route, RouteRequest request);
+
+ private IRouteProvider.Stub mBinder = new IRouteProvider.Stub() {
+
+ @Override
+ public void registerCallback(IRouteProviderCallback cb) throws RemoteException {
+ mCb = cb;
+ }
+
+ @Override
+ public void unregisterCallback(IRouteProviderCallback cb) throws RemoteException {
+ mCb = null;
+ }
+
+ @Override
+ public void updateDiscoveryRequests(List<RouteRequest> requests)
+ throws RemoteException {
+ RouteProviderService.this.updateDiscoveryRequests(requests);
+ }
+
+ @Override
+ public void getAvailableRoutes(List<RouteRequest> requests, ResultReceiver cb)
+ throws RemoteException {
+ List<RouteInfo> routes = RouteProviderService.this.getMatchingRoutes(requests);
+ ArrayList<RouteInfo> routesArray;
+ if (routes instanceof ArrayList) {
+ routesArray = (ArrayList<RouteInfo>) routes;
+ } else {
+ routesArray = new ArrayList<RouteInfo>(routes);
+ }
+ Bundle resultData = new Bundle();
+ resultData.putParcelableArrayList(KEY_ROUTES, routesArray);
+ cb.send(routes == null ? RESULT_FAILURE : RESULT_SUCCESS, resultData);
+ }
+
+ @Override
+ public void connect(RouteInfo route, RouteRequest request, ResultReceiver cb)
+ throws RemoteException {
+ RouteConnection connection = RouteProviderService.this.connect(route, request);
+ Bundle resultData = new Bundle();
+ if (connection != null) {
+ connection.publish();
+ resultData.putBinder(KEY_CONNECTION, connection.getBinder());
+ }
+
+ cb.send(connection == null ? RESULT_FAILURE : RESULT_SUCCESS, resultData);
+ }
+ };
+}
diff --git a/media/java/android/media/session/MediaSessionToken.aidl b/media/java/android/media/routeprovider/RouteRequest.aidl
similarity index 90%
copy from media/java/android/media/session/MediaSessionToken.aidl
copy to media/java/android/media/routeprovider/RouteRequest.aidl
index 5812682..7bc5722 100644
--- a/media/java/android/media/session/MediaSessionToken.aidl
+++ b/media/java/android/media/routeprovider/RouteRequest.aidl
@@ -13,6 +13,6 @@
** limitations under the License.
*/
-package android.media.session;
+package android.media.routeprovider;
-parcelable MediaSessionToken;
+parcelable RouteRequest;
diff --git a/media/java/android/media/routeprovider/RouteRequest.java b/media/java/android/media/routeprovider/RouteRequest.java
new file mode 100644
index 0000000..9913566
--- /dev/null
+++ b/media/java/android/media/routeprovider/RouteRequest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.media.routeprovider;
+
+import android.media.session.RouteOptions;
+import android.media.session.SessionInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A request to connect or discover routes with certain capabilities.
+ * <p>
+ * Passed to a {@link RouteProviderService} when a request for discovery or to
+ * connect to a route is made. This identifies the app making the request and
+ * provides the full set of connection parameters they would like to use for a
+ * connection. An app that can connect in multiple ways will be represented by
+ * multiple requests.
+ */
+public final class RouteRequest implements Parcelable {
+ private final SessionInfo mSessionInfo;
+ private final RouteOptions mOptions;
+ private final boolean mActive;
+
+ /**
+ * @hide
+ */
+ public RouteRequest(SessionInfo info, RouteOptions connRequest,
+ boolean active) {
+ mSessionInfo = info;
+ mOptions = connRequest;
+ mActive = active;
+ }
+
+ private RouteRequest(Parcel in) {
+ mSessionInfo = SessionInfo.CREATOR.createFromParcel(in);
+ mOptions = RouteOptions.CREATOR.createFromParcel(in);
+ mActive = in.readInt() != 0;
+ }
+
+ /**
+ * Get information about the session making the request.
+ *
+ * @return Info on the session making the request
+ */
+ public SessionInfo getSessionInfo() {
+ return mSessionInfo;
+ }
+
+ /**
+ * Get the connection options, which includes the interfaces and other
+ * connection params the session wants to use with a route.
+ *
+ * @return The connection options
+ */
+ public RouteOptions getConnectionOptions() {
+ return mOptions;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ mSessionInfo.writeToParcel(dest, flags);
+ mOptions.writeToParcel(dest, flags);
+ dest.writeInt(mActive ? 1 : 0);
+ }
+
+ public static final Parcelable.Creator<RouteRequest> CREATOR
+ = new Parcelable.Creator<RouteRequest>() {
+ @Override
+ public RouteRequest createFromParcel(Parcel in) {
+ return new RouteRequest(in);
+ }
+
+ @Override
+ public RouteRequest[] newArray(int size) {
+ return new RouteRequest[size];
+ }
+ };
+}
diff --git a/media/java/android/media/session/IMediaSession.aidl b/media/java/android/media/session/ISession.aidl
similarity index 64%
rename from media/java/android/media/session/IMediaSession.aidl
rename to media/java/android/media/session/ISession.aidl
index aed7641..ca77f04 100644
--- a/media/java/android/media/session/IMediaSession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -15,25 +15,33 @@
package android.media.session;
-import android.media.session.IMediaController;
+import android.media.session.ISessionController;
import android.media.session.MediaMetadata;
+import android.media.session.RouteOptions;
+import android.media.session.RouteCommand;
+import android.media.session.RouteInfo;
import android.media.session.PlaybackState;
import android.os.Bundle;
+import android.os.ResultReceiver;
/**
* Interface to a MediaSession in the system.
* @hide
*/
-interface IMediaSession {
+interface ISession {
void sendEvent(String event, in Bundle data);
- IMediaController getMediaController();
+ ISessionController getController();
void setTransportPerformerEnabled();
- void setRouteState(in Bundle routeState);
- void setRoute(in Bundle mediaRouteDescriptor);
- List<String> getSupportedInterfaces();
void publish();
void destroy();
+ // These commands are for setting up and communicating with routes
+ // Returns true if the route was set for this session
+ boolean setRoute(in RouteInfo route);
+ void setRouteOptions(in List<RouteOptions> options);
+ void connectToRoute(in RouteInfo route, in RouteOptions options);
+ void sendRouteCommand(in RouteCommand event, in ResultReceiver cb);
+
// These commands are for the TransportPerformer
void setMetadata(in MediaMetadata metadata);
void setPlaybackState(in PlaybackState state);
diff --git a/media/java/android/media/session/IMediaSessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
similarity index 73%
rename from media/java/android/media/session/IMediaSessionCallback.aidl
rename to media/java/android/media/session/ISessionCallback.aidl
index 7c183e0..f04cbcc 100644
--- a/media/java/android/media/session/IMediaSessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -16,6 +16,9 @@
package android.media.session;
import android.media.Rating;
+import android.media.session.RouteEvent;
+import android.media.session.RouteInfo;
+import android.media.session.RouteOptions;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -23,10 +26,13 @@
/**
* @hide
*/
-oneway interface IMediaSessionCallback {
+oneway interface ISessionCallback {
void onCommand(String command, in Bundle extras, in ResultReceiver cb);
- void onMediaButton(in Intent mediaRequestIntent);
- void onRequestRouteChange(in Bundle route);
+ void onMediaButton(in Intent mediaButtonIntent);
+ void onRequestRouteChange(in RouteInfo route);
+ void onRouteConnected(in RouteInfo route, in RouteOptions options);
+ void onRouteStateChange(int state);
+ void onRouteEvent(in RouteEvent event);
// These callbacks are for the TransportPerformer
void onPlay();
diff --git a/media/java/android/media/session/IMediaController.aidl b/media/java/android/media/session/ISessionController.aidl
similarity index 85%
rename from media/java/android/media/session/IMediaController.aidl
rename to media/java/android/media/session/ISessionController.aidl
index d34e973..e2e046f 100644
--- a/media/java/android/media/session/IMediaController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -17,7 +17,7 @@
import android.content.Intent;
import android.media.Rating;
-import android.media.session.IMediaControllerCallback;
+import android.media.session.ISessionControllerCallback;
import android.media.session.MediaMetadata;
import android.media.session.PlaybackState;
import android.os.Bundle;
@@ -28,12 +28,13 @@
* Interface to a MediaSession in the system.
* @hide
*/
-interface IMediaController {
+interface ISessionController {
void sendCommand(String command, in Bundle extras, in ResultReceiver cb);
void sendMediaButton(in KeyEvent mediaButton);
- void registerCallbackListener(in IMediaControllerCallback cb);
- void unregisterCallbackListener(in IMediaControllerCallback cb);
+ void registerCallbackListener(in ISessionControllerCallback cb);
+ void unregisterCallbackListener(in ISessionControllerCallback cb);
boolean isTransportControlEnabled();
+ void showRoutePicker();
// These commands are for the TransportController
void play();
diff --git a/media/java/android/media/session/IMediaControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl
similarity index 88%
rename from media/java/android/media/session/IMediaControllerCallback.aidl
rename to media/java/android/media/session/ISessionControllerCallback.aidl
index 3651f1b..bc1ae05 100644
--- a/media/java/android/media/session/IMediaControllerCallback.aidl
+++ b/media/java/android/media/session/ISessionControllerCallback.aidl
@@ -16,15 +16,16 @@
package android.media.session;
import android.media.session.MediaMetadata;
+import android.media.session.RouteInfo;
import android.media.session.PlaybackState;
import android.os.Bundle;
/**
* @hide
*/
-oneway interface IMediaControllerCallback {
+oneway interface ISessionControllerCallback {
void onEvent(String event, in Bundle extras);
- void onRouteChanged(in Bundle route);
+ void onRouteChanged(in RouteInfo route);
// These callbacks are for the TransportController
void onPlaybackStateChanged(in PlaybackState state);
diff --git a/media/java/android/media/session/IMediaSessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
similarity index 77%
rename from media/java/android/media/session/IMediaSessionManager.aidl
rename to media/java/android/media/session/ISessionManager.aidl
index 0b4328e..84b9a0f 100644
--- a/media/java/android/media/session/IMediaSessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -15,14 +15,14 @@
package android.media.session;
-import android.media.session.IMediaSession;
-import android.media.session.IMediaSessionCallback;
+import android.media.session.ISession;
+import android.media.session.ISessionCallback;
import android.os.Bundle;
/**
* Interface to the MediaSessionManagerService
* @hide
*/
-interface IMediaSessionManager {
- IMediaSession createSession(String packageName, in IMediaSessionCallback cb, String tag);
+interface ISessionManager {
+ ISession createSession(String packageName, in ISessionCallback cb, String tag);
}
\ No newline at end of file
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index b3506b3..14d9fb1 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -15,12 +15,11 @@
*/
package android.media.session;
-import android.media.RemoteControlClient;
import android.os.Parcel;
import android.os.Parcelable;
/**
- * Playback state for a {@link MediaSession}. This includes a state like
+ * Playback state for a {@link Session}. This includes a state like
* {@link PlaybackState#PLAYSTATE_PLAYING}, the current playback position,
* and the current control capabilities.
*/
@@ -147,6 +146,14 @@
*/
public final static int PLAYSTATE_ERROR = 7;
+ /**
+ * State indicating the class doing playback is currently connecting to a
+ * route. Depending on the implementation you may return to the previous
+ * state when the connection finishes or enter {@link #PLAYSTATE_NONE}. If
+ * the connection failed {@link #PLAYSTATE_ERROR} should be used.
+ */
+ public final static int PLAYSTATE_CONNECTING = 8;
+
private int mState;
private long mPosition;
private long mBufferPosition;
diff --git a/media/java/android/media/session/Route.java b/media/java/android/media/session/Route.java
new file mode 100644
index 0000000..c9530a6
--- /dev/null
+++ b/media/java/android/media/session/Route.java
@@ -0,0 +1,99 @@
+/*
+ * 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.media.session;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Represents a destination which an application has connected to and may send
+ * media content.
+ * <p>
+ * This allows a session owner to interact with a route it has been connected
+ * to. The MediaRoute must be used to get {@link RouteInterface}
+ * instances which can be used to communicate over a specific interface on the
+ * route.
+ */
+public final class Route {
+ private static final String TAG = "Route";
+ private final RouteInfo mInfo;
+ private final Session mSession;
+ private final RouteOptions mOptions;
+
+ /**
+ * @hide
+ */
+ public Route(RouteInfo info, RouteOptions options, Session session) {
+ if (info == null || options == null) {
+ throw new IllegalStateException("Route info was not valid!");
+ }
+ mInfo = info;
+ mOptions = options;
+ mSession = session;
+ }
+
+ /**
+ * Get the {@link RouteInfo} for this route.
+ *
+ * @return The info for this route.
+ */
+ public RouteInfo getRouteInfo() {
+ return mInfo;
+ }
+
+ /**
+ * Get the {@link RouteOptions} that were used to connect this route.
+ *
+ * @return The options used to connect to this route.
+ */
+ public RouteOptions getOptions() {
+ return mOptions;
+ }
+
+ /**
+ * Gets an interface provided by this route. If the interface is not
+ * supported by the route, returns null.
+ *
+ * @see RouteInterface
+ * @param iface The name of the interface to create
+ * @return A {@link RouteInterface} or null if the interface is
+ * not supported.
+ */
+ public RouteInterface getInterface(String iface) {
+ if (TextUtils.isEmpty(iface)) {
+ throw new IllegalArgumentException("iface may not be empty.");
+ }
+ List<String> ifaces = mOptions.getInterfaceNames();
+ if (ifaces != null) {
+ for (int i = ifaces.size() - 1; i >= 0; i--) {
+ if (iface.equals(ifaces.get(i))) {
+ return new RouteInterface(this, iface, mSession);
+ }
+ }
+ }
+ Log.e(TAG, "Interface not supported by route");
+ return null;
+ }
+
+ /**
+ * @hide
+ */
+ Session getSession() {
+ return mSession;
+ }
+}
diff --git a/media/java/android/media/session/MediaSessionToken.aidl b/media/java/android/media/session/RouteCommand.aidl
similarity index 95%
copy from media/java/android/media/session/MediaSessionToken.aidl
copy to media/java/android/media/session/RouteCommand.aidl
index 5812682..725b308 100644
--- a/media/java/android/media/session/MediaSessionToken.aidl
+++ b/media/java/android/media/session/RouteCommand.aidl
@@ -15,4 +15,4 @@
package android.media.session;
-parcelable MediaSessionToken;
+parcelable RouteCommand;
diff --git a/media/java/android/media/session/RouteCommand.java b/media/java/android/media/session/RouteCommand.java
new file mode 100644
index 0000000..358bc0a
--- /dev/null
+++ b/media/java/android/media/session/RouteCommand.java
@@ -0,0 +1,117 @@
+/*
+ * 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.media.session;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a command that an application may send to a route.
+ * <p>
+ * Commands are associated with a specific route and interface supported by that
+ * route and sent through the session. This class isn't used directly by apps.
+ *
+ * @hide
+ */
+public final class RouteCommand implements Parcelable {
+ private final String mRoute;
+ private final String mIface;
+ private final String mEvent;
+ private final Bundle mExtras;
+
+ /**
+ * @param route The id of the route this event is being sent on
+ * @param iface The interface the sender used
+ * @param event The event or command
+ * @param extras Any extras included with the event
+ */
+ public RouteCommand(String route, String iface, String event, Bundle extras) {
+ mRoute = route;
+ mIface = iface;
+ mEvent = event;
+ mExtras = extras;
+ }
+
+ private RouteCommand(Parcel in) {
+ mRoute = in.readString();
+ mIface = in.readString();
+ mEvent = in.readString();
+ mExtras = in.readBundle();
+ }
+
+ /**
+ * Get the id for the route this event was sent on.
+ *
+ * @return The route id this event is using
+ */
+ public String getRouteInfo() {
+ return mRoute;
+ }
+
+ /**
+ * Get the interface this event was sent from
+ *
+ * @return The interface for this event
+ */
+ public String getIface() {
+ return mIface;
+ }
+
+ /**
+ * Get the action/name of the event.
+ *
+ * @return The name of event/command.
+ */
+ public String getEvent() {
+ return mEvent;
+ }
+
+ /**
+ * Get any extras included with the event.
+ *
+ * @return The bundle included with the event or null
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mRoute);
+ dest.writeString(mIface);
+ dest.writeString(mEvent);
+ dest.writeBundle(mExtras);
+ }
+
+ public static final Parcelable.Creator<RouteCommand> CREATOR
+ = new Parcelable.Creator<RouteCommand>() {
+ @Override
+ public RouteCommand createFromParcel(Parcel in) {
+ return new RouteCommand(in);
+ }
+
+ @Override
+ public RouteCommand[] newArray(int size) {
+ return new RouteCommand[size];
+ }
+ };
+}
diff --git a/media/java/android/media/session/MediaSessionToken.aidl b/media/java/android/media/session/RouteEvent.aidl
similarity index 95%
rename from media/java/android/media/session/MediaSessionToken.aidl
rename to media/java/android/media/session/RouteEvent.aidl
index 5812682..6966207 100644
--- a/media/java/android/media/session/MediaSessionToken.aidl
+++ b/media/java/android/media/session/RouteEvent.aidl
@@ -15,4 +15,4 @@
package android.media.session;
-parcelable MediaSessionToken;
+parcelable RouteEvent;
diff --git a/media/java/android/media/session/RouteEvent.java b/media/java/android/media/session/RouteEvent.java
new file mode 100644
index 0000000..918e410
--- /dev/null
+++ b/media/java/android/media/session/RouteEvent.java
@@ -0,0 +1,120 @@
+/*
+ * 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.media.session;
+
+import android.media.routeprovider.RouteConnection;
+import android.media.routeprovider.RouteProviderService;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents an event that a route provider is sending to a particular
+ * {@link RouteConnection}. Events are associated with a specific interface
+ * supported by the connection and sent through the {@link RouteProviderService}.
+ * This class isn't used directly by apps.
+ *
+ * @hide
+ */
+public class RouteEvent implements Parcelable {
+ private final IBinder mConnection;
+ private final String mIface;
+ private final String mEvent;
+ private final Bundle mExtras;
+
+ /**
+ * @param connection The connection that this event is for
+ * @param iface The interface the sender used
+ * @param event The event or command
+ * @param extras Any extras included with the event
+ */
+ public RouteEvent(IBinder connection, String iface, String event, Bundle extras) {
+ mConnection = connection;
+ mIface = iface;
+ mEvent = event;
+ mExtras = extras;
+ }
+
+ private RouteEvent(Parcel in) {
+ mConnection = in.readStrongBinder();
+ mIface = in.readString();
+ mEvent = in.readString();
+ mExtras = in.readBundle();
+ }
+
+ /**
+ * Get the connection this event was sent on.
+ *
+ * @return The connection this event is using
+ */
+ public IBinder getConnection() {
+ return mConnection;
+ }
+
+ /**
+ * Get the interface this event was sent from
+ *
+ * @return The interface for this event
+ */
+ public String getIface() {
+ return mIface;
+ }
+
+ /**
+ * Get the action/name of the event.
+ *
+ * @return The name of event/command.
+ */
+ public String getEvent() {
+ return mEvent;
+ }
+
+ /**
+ * Get any extras included with the event.
+ *
+ * @return The bundle included with the event or null
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mConnection);
+ dest.writeString(mIface);
+ dest.writeString(mEvent);
+ dest.writeBundle(mExtras);
+ }
+
+ public static final Parcelable.Creator<RouteEvent> CREATOR
+ = new Parcelable.Creator<RouteEvent>() {
+ @Override
+ public RouteEvent createFromParcel(Parcel in) {
+ return new RouteEvent(in);
+ }
+
+ @Override
+ public RouteEvent[] newArray(int size) {
+ return new RouteEvent[size];
+ }
+ };
+}
diff --git a/media/java/android/media/session/MediaSessionToken.aidl b/media/java/android/media/session/RouteInfo.aidl
similarity index 95%
copy from media/java/android/media/session/MediaSessionToken.aidl
copy to media/java/android/media/session/RouteInfo.aidl
index 5812682..c5f50c8 100644
--- a/media/java/android/media/session/MediaSessionToken.aidl
+++ b/media/java/android/media/session/RouteInfo.aidl
@@ -15,4 +15,4 @@
package android.media.session;
-parcelable MediaSessionToken;
+parcelable RouteInfo;
diff --git a/media/java/android/media/session/RouteInfo.java b/media/java/android/media/session/RouteInfo.java
new file mode 100644
index 0000000..17df969
--- /dev/null
+++ b/media/java/android/media/session/RouteInfo.java
@@ -0,0 +1,233 @@
+/*
+ * 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.media.session;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Information about a route, including its display name, a way to identify it,
+ * and the ways it can be connected to.
+ */
+public final class RouteInfo implements Parcelable {
+ private final String mName;
+ private final String mId;
+ private final String mProviderId;
+ private final List<RouteOptions> mOptions;
+
+ private RouteInfo(String id, String name, String providerId,
+ List<RouteOptions> connRequests) {
+ mId = id;
+ mName = name;
+ mProviderId = providerId;
+ mOptions = connRequests;
+ }
+
+ private RouteInfo(Parcel in) {
+ mId = in.readString();
+ mName = in.readString();
+ mProviderId = in.readString();
+ mOptions = new ArrayList<RouteOptions>();
+ in.readTypedList(mOptions, RouteOptions.CREATOR);
+ }
+
+ /**
+ * Get the displayable name of this route.
+ *
+ * @return A short, user readable name for this route
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Get the unique id for this route.
+ *
+ * @return A unique route id.
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Get the package name of this route's provider.
+ *
+ * @return The package name of this route's provider.
+ */
+ public String getProvider() {
+ return mProviderId;
+ }
+
+ /**
+ * Get the set of connections that may be used with this route.
+ *
+ * @return An array of connection requests that may be used to connect
+ */
+ public List<RouteOptions> getConnectionMethods() {
+ return mOptions;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ dest.writeString(mName);
+ dest.writeString(mProviderId);
+ dest.writeTypedList(mOptions);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder bob = new StringBuilder();
+ bob.append("RouteInfo: id=").append(mId).append(", name=").append(mName)
+ .append(", provider=").append(mProviderId).append(", options={");
+ for (int i = 0; i < mOptions.size(); i++) {
+ if (i != 0) {
+ bob.append(", ");
+ }
+ bob.append(mOptions.get(i).toString());
+ }
+ bob.append("}");
+ return bob.toString();
+ }
+
+ public static final Parcelable.Creator<RouteInfo> CREATOR
+ = new Parcelable.Creator<RouteInfo>() {
+ @Override
+ public RouteInfo createFromParcel(Parcel in) {
+ return new RouteInfo(in);
+ }
+
+ @Override
+ public RouteInfo[] newArray(int size) {
+ return new RouteInfo[size];
+ }
+ };
+
+ /**
+ * Helper for creating MediaRouteInfos. A route must have a name and an id.
+ * While options are not strictly required the route cannot be connected to
+ * without at least one set of options.
+ */
+ public static final class Builder {
+ private String mName;
+ private String mId;
+ private String mProviderPackage;
+ private ArrayList<RouteOptions> mOptions;
+
+ /**
+ * Copies an existing route info object. TODO Remove once we have
+ * helpers for creating route infos.
+ *
+ * @param from The existing info to copy.
+ */
+ public Builder(RouteInfo from) {
+ mOptions = new ArrayList<RouteOptions>(from.getConnectionMethods());
+ mName = from.mName;
+ mId = from.mId;
+ mProviderPackage = from.mProviderId;
+ }
+
+ public Builder() {
+ mOptions = new ArrayList<RouteOptions>();
+ }
+
+ /**
+ * Set the user visible name for this route.
+ *
+ * @param name The name of the route
+ * @return The builder for easy chaining.
+ */
+ public Builder setName(String name) {
+ mName = name;
+ return this;
+ }
+
+ /**
+ * Set the id of the route. This should be unique to the provider.
+ *
+ * @param id The unique id of the route.
+ * @return The builder for easy chaining.
+ */
+ public Builder setId(String id) {
+ mId = id;
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public Builder setProviderId(String packageName) {
+ mProviderPackage = packageName;
+ return this;
+ }
+
+ /**
+ * Add a set of {@link RouteOptions} to the route. Multiple options
+ * may be added to the same route.
+ *
+ * @param options The options to add to this route.
+ * @return The builder for easy chaining.
+ */
+ public Builder addRouteOptions(RouteOptions options) {
+ mOptions.add(options);
+ return this;
+ }
+
+ /**
+ * Clear the set of {@link RouteOptions} on the route.
+ *
+ * @return The builder for easy chaining
+ */
+ public Builder clearRouteOptions() {
+ mOptions.clear();
+ return this;
+ }
+
+ /**
+ * Build a new MediaRouteInfo.
+ *
+ * @return A new MediaRouteInfo with the values that were set.
+ */
+ public RouteInfo build() {
+ if (TextUtils.isEmpty(mName)) {
+ throw new IllegalArgumentException("Must set a name before building");
+ }
+ if (TextUtils.isEmpty(mId)) {
+ throw new IllegalArgumentException("Must set an id before building");
+ }
+ return new RouteInfo(mId, mName, mProviderPackage, mOptions);
+ }
+
+ /**
+ * Get the current number of options that have been added to this
+ * builder.
+ *
+ * @return The number of options that have been added.
+ */
+ public int getOptionsSize() {
+ return mOptions.size();
+ }
+ }
+}
diff --git a/media/java/android/media/session/RouteInterface.java b/media/java/android/media/session/RouteInterface.java
index 2391f27..e9c9fd3 100644
--- a/media/java/android/media/session/RouteInterface.java
+++ b/media/java/android/media/session/RouteInterface.java
@@ -17,136 +17,161 @@
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.Parcelable;
import android.os.ResultReceiver;
+import android.util.Log;
+
+import java.util.ArrayList;
/**
- * Routes can support multiple interfaces for MediaSessions to interact with. To
- * add a standard interface you should implement that interface's RouteInterface
- * Stub and register it with the session. The set of supported commands is
- * dependent on the specific interface's implementation.
- * <p>
- * A MediaInterface can be registered by calling TODO. Once added an interface
- * will be used by Sessions to decide how they communicate with a session and
- * cannot be removed, so all interfaces that you plan to support should be added
- * when the route is created.
+ * A route can support multiple interfaces for a {@link Session} to
+ * interact with. To use a specific interface with a route a
+ * MediaSessionRouteInterface needs to be retrieved from the route. An
+ * implementation of the specific interface, like
+ * {@link RoutePlaybackControls}, should be used to simplify communication
+ * and reduce errors on that interface.
*
- * @see RouteTransportControls
+ * @see RoutePlaybackControls for an example
*/
public final class RouteInterface {
- private static final String TAG = "MediaInterface";
+ private static final String TAG = "RouteInterface";
- private static final String KEY_RESULT = "result";
+ /**
+ * Error indicating the route is currently not connected.
+ */
+ public static final int RESULT_NOT_CONNECTED = -5;
+ /**
+ * Error indicating the session is no longer using the route this command
+ * was sent to.
+ */
+ public static final int RESULT_ROUTE_IS_STALE = -4;
+ /**
+ * Error indicating that the interface does not support the command.
+ */
+ public static final int RESULT_COMMAND_NOT_SUPPORTED = -3;
+ /**
+ * Error indicating that the route does not support the interface.
+ */
+ public static final int RESULT_INTERFACE_NOT_SUPPORTED = -2;
+ /**
+ * Generic error. Extra information about the error may be included in the
+ * result bundle.
+ */
+ public static final int RESULT_ERROR = -1;
+ /**
+ * The command was successful. Extra information may be included in the
+ * result bundle.
+ */
+ public static final int RESULT_SUCCESS = 1;
- private final MediaController mController;
+ private final Route mRoute;
private final String mIface;
+ private final Session mSession;
+
+ private final Object mLock = new Object();
+ private final ArrayList<EventHandler> mListeners = new ArrayList<EventHandler>();
/**
* @hide
*/
- RouteInterface(MediaController controller, String iface) {
- mController = controller;
+ RouteInterface(Route route, String iface, Session session) {
+ mRoute = route;
mIface = iface;
+ mSession = session;
+ mSession.addInterfaceListener(iface, mEventListener);
}
- public void sendCommand(String command, Bundle params, ResultReceiver cb) {
- // TODO
+ /**
+ * Send a command using this interface.
+ *
+ * @param command The command to send.
+ * @param extras Any extras to include with the command.
+ * @param cb The callback to receive the result on.
+ * @return true if the command was sent, false otherwise.
+ */
+ public boolean sendCommand(String command, Bundle extras, ResultReceiver cb) {
+ RouteCommand cmd = new RouteCommand(mRoute.getRouteInfo().getId(), mIface,
+ command, extras);
+ return mSession.sendRouteCommand(cmd, cb);
}
+ /**
+ * Add a listener to this interface. Events will be sent on the caller's
+ * thread.
+ *
+ * @param listener The listener to receive events on.
+ */
public void addListener(EventListener listener) {
addListener(listener, null);
}
+ /**
+ * Add a listener for this interface. If a handler is specified events will
+ * be performed on the handler's thread, otherwise the caller's thread will
+ * be used.
+ *
+ * @param listener The listener to receive events on
+ * @param handler The handler whose thread to post calls on
+ */
public void addListener(EventListener listener, Handler handler) {
- // TODO See MediaController for add/remove pattern
+ if (listener == null) {
+ throw new IllegalArgumentException("listener may not be null");
+ }
+ if (handler == null) {
+ handler = new Handler();
+ }
+ synchronized (mLock) {
+ if (findIndexOfListenerLocked(listener) != -1) {
+ Log.d(TAG, "Listener is already added, ignoring");
+ return;
+ }
+ mListeners.add(new EventHandler(handler.getLooper(), listener));
+ }
}
+ /**
+ * Remove a listener from this interface.
+ *
+ * @param listener The listener to stop receiving events on.
+ */
public void removeListener(EventListener listener) {
- // TODO
- }
-
- // TODO decide on list of supported types
- private static Bundle writeResultToBundle(Object v) {
- Bundle b = new Bundle();
- if (v == null) {
- // Don't send anything if null
- } else if (v instanceof String) {
- b.putString(KEY_RESULT, (String) v);
- } else if (v instanceof Integer) {
- b.putInt(KEY_RESULT, (Integer) v);
- } else if (v instanceof Bundle) {
- // Must be before Parcelable
- b.putBundle(KEY_RESULT, (Bundle) v);
- } else if (v instanceof Parcelable) {
- b.putParcelable(KEY_RESULT, (Parcelable) v);
- } else if (v instanceof Short) {
- b.putShort(KEY_RESULT, (Short) v);
- } else if (v instanceof Long) {
- b.putLong(KEY_RESULT, (Long) v);
- } else if (v instanceof Float) {
- b.putFloat(KEY_RESULT, (Float) v);
- } else if (v instanceof Double) {
- b.putDouble(KEY_RESULT, (Double) v);
- } else if (v instanceof Boolean) {
- b.putBoolean(KEY_RESULT, (Boolean) v);
- } else if (v instanceof CharSequence) {
- // Must be after String
- b.putCharSequence(KEY_RESULT, (CharSequence) v);
- } else if (v instanceof boolean[]) {
- b.putBooleanArray(KEY_RESULT, (boolean[]) v);
- } else if (v instanceof byte[]) {
- b.putByteArray(KEY_RESULT, (byte[]) v);
- } else if (v instanceof String[]) {
- b.putStringArray(KEY_RESULT, (String[]) v);
- } else if (v instanceof CharSequence[]) {
- // Must be after String[] and before Object[]
- b.putCharSequenceArray(KEY_RESULT, (CharSequence[]) v);
- } else if (v instanceof IBinder) {
- b.putBinder(KEY_RESULT, (IBinder) v);
- } else if (v instanceof Parcelable[]) {
- b.putParcelableArray(KEY_RESULT, (Parcelable[]) v);
- } else if (v instanceof int[]) {
- b.putIntArray(KEY_RESULT, (int[]) v);
- } else if (v instanceof long[]) {
- b.putLongArray(KEY_RESULT, (long[]) v);
- } else if (v instanceof Byte) {
- b.putByte(KEY_RESULT, (Byte) v);
+ if (listener == null) {
+ throw new IllegalArgumentException("listener may not be null");
}
- return b;
- }
-
- public abstract static class Stub {
-
- /**
- * The name of an interface should be a fully qualified name to prevent
- * namespace collisions. Example: "com.myproject.MyPlaybackInterface"
- *
- * @return The name of this interface
- */
- public abstract String getName();
-
- /**
- * This is called when a command is received that matches the interface
- * you registered. Commands can come from any app with a MediaController
- * reference to the session.
- *
- * @see MediaController
- * @see MediaSession
- * @param command The command or method to invoke.
- * @param args Any args that were included with the command. May be
- * null.
- * @param cb The callback provided to send a response on. May be null.
- */
- public abstract void onCommand(String command, Bundle args, ResultReceiver cb);
-
- public final void sendEvent(MediaSession session, String event, Bundle extras) {
- // TODO
+ synchronized (mLock) {
+ int index = findIndexOfListenerLocked(listener);
+ if (index != -1) {
+ mListeners.remove(index);
+ }
}
}
+ private int findIndexOfListenerLocked(EventListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Callback cannot be null");
+ }
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ EventHandler handler = mListeners.get(i);
+ if (listener == handler.mListener) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private EventListener mEventListener = new EventListener() {
+ @Override
+ public void onEvent(String event, Bundle args) {
+ synchronized (mLock) {
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).postEvent(event, args);
+ }
+ }
+ }
+
+ };
+
/**
* An EventListener can be registered by an app with TODO to handle events
* sent by the session on a specific interface.
@@ -166,9 +191,9 @@
private static final class EventHandler extends Handler {
- private final RouteInterface.EventListener mListener;
+ private final EventListener mListener;
- public EventHandler(Looper looper, RouteInterface.EventListener cb) {
+ public EventHandler(Looper looper, EventListener cb) {
super(looper, null, true);
mListener = cb;
}
diff --git a/media/java/android/media/session/MediaSessionToken.aidl b/media/java/android/media/session/RouteOptions.aidl
similarity index 95%
copy from media/java/android/media/session/MediaSessionToken.aidl
copy to media/java/android/media/session/RouteOptions.aidl
index 5812682..feaf517 100644
--- a/media/java/android/media/session/MediaSessionToken.aidl
+++ b/media/java/android/media/session/RouteOptions.aidl
@@ -15,4 +15,4 @@
package android.media.session;
-parcelable MediaSessionToken;
+parcelable RouteOptions;
diff --git a/media/java/android/media/session/RouteOptions.java b/media/java/android/media/session/RouteOptions.java
new file mode 100644
index 0000000..5105867
--- /dev/null
+++ b/media/java/android/media/session/RouteOptions.java
@@ -0,0 +1,163 @@
+/*
+ * 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.media.session;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Specifies options that an application might use when connecting to a route.
+ * This includes things like interfaces, connection parameters, and required
+ * features.
+ * <p>
+ * An application may create several different route options that describe
+ * alternative sets of capabilities that it can use and choose the most
+ * appropriate route options when it is ready to connect to the route. Each
+ * route options instance must specify a complete set of capabilities to request
+ * when the connection is established.
+ */
+public final class RouteOptions implements Parcelable {
+ private static final String TAG = "RouteOptions";
+
+ private final ArrayList<String> mIfaces;
+ private final Bundle mConnectionParams;
+
+ private RouteOptions(List<String> ifaces, Bundle params) {
+ mIfaces = new ArrayList<String>(ifaces);
+ mConnectionParams = params;
+ }
+
+ private RouteOptions(Parcel in) {
+ mIfaces = new ArrayList<String>();
+ in.readStringList(mIfaces);
+ mConnectionParams = in.readBundle();
+ }
+
+ /**
+ * Get the interfaces this connection wants to use.
+ *
+ * @return The interfaces for this connection
+ */
+ public List<String> getInterfaceNames() {
+ return mIfaces;
+ }
+
+ /**
+ * Get the parameters that will be used for connecting.
+ *
+ * @return The set of connection parameters this connections uses
+ */
+ public Bundle getConnectionParams() {
+ return mConnectionParams;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStringList(mIfaces);
+ dest.writeBundle(mConnectionParams);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder bob = new StringBuilder();
+ bob.append("Options: interfaces={");
+ for (int i = 0; i < mIfaces.size(); i++) {
+ if (i != 0) {
+ bob.append(", ");
+ }
+ bob.append(mIfaces.get(i));
+ }
+ bob.append("}");
+ bob.append(", parameters=");
+ bob.append(mConnectionParams == null ? "null" : mConnectionParams.toString());
+ return bob.toString();
+ }
+
+ public static final Parcelable.Creator<RouteOptions> CREATOR
+ = new Parcelable.Creator<RouteOptions>() {
+ @Override
+ public RouteOptions createFromParcel(Parcel in) {
+ return new RouteOptions(in);
+ }
+
+ @Override
+ public RouteOptions[] newArray(int size) {
+ return new RouteOptions[size];
+ }
+ };
+
+ /**
+ * Builder for creating {@link RouteOptions}.
+ */
+ public final static class Builder {
+ private ArrayList<String> mIfaces = new ArrayList<String>();
+ private Bundle mConnectionParams;
+
+ public Builder() {
+ }
+
+ /**
+ * Add a required interface to the options.
+ *
+ * @param interfaceName The name of the interface to add.
+ * @return The builder to allow chaining commands.
+ */
+ public Builder addInterface(String interfaceName) {
+ if (TextUtils.isEmpty(interfaceName)) {
+ throw new IllegalArgumentException("interfaceName cannot be empty");
+ }
+ if (!mIfaces.contains(interfaceName)) {
+ mIfaces.add(interfaceName);
+ } else {
+ Log.w(TAG, "Attempted to add interface that is already added");
+ }
+ return this;
+ }
+
+ /**
+ * Set the connection parameters to use with the options. TODO replace
+ * with more specific calls once we decide on the standard way to
+ * express parameters.
+ *
+ * @param parameters The parameters to use.
+ * @return The builder to allow chaining commands.
+ */
+ public Builder setParameters(Bundle parameters) {
+ mConnectionParams = parameters;
+ return this;
+ }
+
+ /**
+ * Generate a set of options.
+ *
+ * @return The options with the specified components.
+ */
+ public RouteOptions build() {
+ return new RouteOptions(mIfaces, mConnectionParams);
+ }
+ }
+}
diff --git a/media/java/android/media/session/RoutePlaybackControls.java b/media/java/android/media/session/RoutePlaybackControls.java
new file mode 100644
index 0000000..a3ffb58
--- /dev/null
+++ b/media/java/android/media/session/RoutePlaybackControls.java
@@ -0,0 +1,161 @@
+/*
+ * 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.media.session;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+
+/**
+ * A standard media control interface for Routes that support queueing and
+ * transport controls. Routes may support multiple interfaces for MediaSessions
+ * to interact with.
+ */
+public final class RoutePlaybackControls {
+ private static final String TAG = "RoutePlaybackControls";
+ public static final String NAME = "android.media.session.RoutePlaybackControls";
+
+ /** @hide */
+ public static final String KEY_VALUE1 = "value1";
+
+ /** @hide */
+ public static final String CMD_FAST_FORWARD = "fastForward";
+ /** @hide */
+ public static final String CMD_GET_CURRENT_POSITION = "getCurrentPosition";
+ /** @hide */
+ public static final String CMD_GET_CAPABILITIES = "getCapabilities";
+ /** @hide */
+ public static final String CMD_PLAY_NOW = "playNow";
+ /** @hide */
+ public static final String CMD_RESUME = "resume";
+ /** @hide */
+ public static final String CMD_PAUSE = "pause";
+
+ /** @hide */
+ public static final String EVENT_PLAYSTATE_CHANGE = "playstateChange";
+ /** @hide */
+ public static final String EVENT_METADATA_CHANGE = "metadataChange";
+
+ private final RouteInterface mIface;
+
+ private RoutePlaybackControls(RouteInterface iface) {
+ mIface = iface;
+ }
+
+ /**
+ * Get a new MediaRoutePlaybackControls instance for sending commands using
+ * this interface. If the provided route doesn't support this interface null
+ * will be returned.
+ *
+ * @param route The route to send commands to.
+ * @return A MediaRoutePlaybackControls instance or null if not supported.
+ */
+ public static RoutePlaybackControls from(Route route) {
+ RouteInterface iface = route.getInterface(NAME);
+ if (iface != null) {
+ return new RoutePlaybackControls(iface);
+ }
+ return null;
+ }
+
+ /**
+ * Send a resume command to the route.
+ */
+ public void resume() {
+ mIface.sendCommand(CMD_RESUME, null, null);
+ }
+
+ /**
+ * Send a pause command to the route.
+ */
+ public void pause() {
+ mIface.sendCommand(CMD_PAUSE, null, null);
+ }
+
+ /**
+ * Send a fast forward command.
+ */
+ public void fastForward() {
+ Bundle b = new Bundle();
+ mIface.sendCommand(CMD_FAST_FORWARD, b, null);
+ }
+
+ /**
+ * Retrieves the current playback position.
+ *
+ * @param cb The callback to receive the result on.
+ */
+ public void getCurrentPosition(ResultReceiver cb) {
+ mIface.sendCommand(CMD_GET_CURRENT_POSITION, null, cb);
+ }
+
+ public void getCapabilities(ResultReceiver cb) {
+ mIface.sendCommand(CMD_GET_CAPABILITIES, null, cb);
+ }
+
+ public void addListener(Listener listener) {
+ mIface.addListener(listener);
+ }
+
+ public void addListener(Listener listener, Handler handler) {
+ mIface.addListener(listener, handler);
+ }
+
+ public void removeListener(Listener listener) {
+ mIface.removeListener(listener);
+ }
+
+ public void playNow(String content) {
+ Bundle bundle = new Bundle();
+ bundle.putString(KEY_VALUE1, content);
+ mIface.sendCommand(CMD_PLAY_NOW, bundle, null);
+ }
+
+ /**
+ * Register this event listener using {@link #addListener} to receive
+ * RoutePlaybackControl events from a session.
+ */
+ public static abstract class Listener extends RouteInterface.EventListener {
+ @Override
+ public final void onEvent(String event, Bundle args) {
+ if (EVENT_PLAYSTATE_CHANGE.equals(event)) {
+ onPlaybackStateChange(args.getInt(KEY_VALUE1, 0));
+ } else if (EVENT_METADATA_CHANGE.equals(event)) {
+ onMetadataUpdate((MediaMetadata) args.getParcelable(KEY_VALUE1));
+ }
+ }
+
+ /**
+ * Override to handle updates to the playback state. Valid values are in
+ * {@link TransportPerformer}. TODO put playstate values somewhere more
+ * generic.
+ *
+ * @param state
+ */
+ public void onPlaybackStateChange(int state) {
+ }
+
+ /**
+ * Override to handle metadata changes for this session's media. The
+ * default supported fields are those in {@link MediaMetadata}.
+ *
+ * @param metadata
+ */
+ public void onMetadataUpdate(MediaMetadata metadata) {
+ }
+ }
+
+}
diff --git a/media/java/android/media/session/RouteTransportControls.java b/media/java/android/media/session/RouteTransportControls.java
deleted file mode 100644
index 665fd10..0000000
--- a/media/java/android/media/session/RouteTransportControls.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * 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.media.session;
-
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-
-/**
- * A standard media control interface for Routes. Routes can support multiple
- * interfaces for MediaSessions to interact with. TODO rewrite for routes
- */
-public final class RouteTransportControls {
- private static final String TAG = "RouteTransportControls";
- public static final String NAME = "android.media.session.RouteTransportControls";
-
- private static final String KEY_VALUE1 = "value1";
-
- private static final String METHOD_FAST_FORWARD = "fastForward";
- private static final String METHOD_GET_CURRENT_POSITION = "getCurrentPosition";
- private static final String METHOD_GET_CAPABILITIES = "getCapabilities";
-
- private static final String EVENT_PLAYSTATE_CHANGE = "playstateChange";
- private static final String EVENT_METADATA_CHANGE = "metadataChange";
-
- private final MediaController mController;
- private final RouteInterface mIface;
-
- private RouteTransportControls(RouteInterface iface, MediaController controller) {
- mIface = iface;
- mController = controller;
- }
-
- public static RouteTransportControls from(MediaController controller) {
-// MediaInterface iface = controller.getInterface(NAME);
-// if (iface != null) {
-// return new RouteTransportControls(iface, controller);
-// }
- return null;
- }
-
- /**
- * Send a play command to the route. TODO rename resume() and use messaging
- * protocol, not KeyEvent
- */
- public void play() {
- // TODO
- }
-
- /**
- * Send a pause command to the session.
- */
- public void pause() {
- // TODO
- }
-
- /**
- * Set the rate at which to fastforward. Valid values are in the range [0,1]
- * with actual rates depending on the implementation.
- *
- * @param rate
- */
- public void fastForward(float rate) {
- if (rate < 0 || rate > 1) {
- throw new IllegalArgumentException("Rate must be between 0 and 1 inclusive");
- }
- Bundle b = new Bundle();
- b.putFloat(KEY_VALUE1, rate);
- mIface.sendCommand(METHOD_FAST_FORWARD, b, null);
- }
-
- public void getCurrentPosition(ResultReceiver cb) {
- mIface.sendCommand(METHOD_GET_CURRENT_POSITION, null, cb);
- }
-
- public void getCapabilities(ResultReceiver cb) {
- mIface.sendCommand(METHOD_GET_CAPABILITIES, null, cb);
- }
-
- public void addListener(Listener listener) {
- mIface.addListener(listener.mListener);
- }
-
- public void addListener(Listener listener, Handler handler) {
- mIface.addListener(listener.mListener, handler);
- }
-
- public void removeListener(Listener listener) {
- mIface.removeListener(listener.mListener);
- }
-
- public static abstract class Stub extends RouteInterface.Stub {
- private final MediaSession mSession;
-
- public Stub(MediaSession session) {
- mSession = session;
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public void onCommand(String method, Bundle extras, ResultReceiver cb) {
- if (TextUtils.isEmpty(method)) {
- return;
- }
- Bundle result;
- if (METHOD_FAST_FORWARD.equals(method)) {
- fastForward(extras.getFloat(KEY_VALUE1, -1));
- } else if (METHOD_GET_CURRENT_POSITION.equals(method)) {
- if (cb != null) {
- result = new Bundle();
- result.putLong(KEY_VALUE1, getCurrentPosition());
- cb.send(0, result);
- }
- } else if (METHOD_GET_CAPABILITIES.equals(method)) {
- if (cb != null) {
- result = new Bundle();
- result.putLong(KEY_VALUE1, getCapabilities());
- cb.send(0, result);
- }
- }
- }
-
- /**
- * Override to handle fast forwarding. Valid values are [0,1] inclusive.
- * The interpretation of the rate is up to the implementation. If no
- * rate was included with the command a rate of -1 will be used by
- * default.
- *
- * @param rate The rate at which to fast forward as a multiplier
- */
- public void fastForward(float rate) {
- Log.w(TAG, "fastForward is not supported.");
- }
-
- /**
- * Override to handle getting the current position of playback in
- * millis.
- *
- * @return The current position in millis or -1
- */
- public long getCurrentPosition() {
- Log.w(TAG, "getCurrentPosition is not supported");
- return -1;
- }
-
- /**
- * Override to handle getting the set of capabilities currently
- * available.
- *
- * @return A bit mask of the supported capabilities
- */
- public long getCapabilities() {
- Log.w(TAG, "getCapabilities is not supported");
- return 0;
- }
-
- /**
- * Publish the current playback state to the system and any controllers.
- * Valid values are defined in {@link RemoteControlClient}. TODO move
- * play states somewhere else.
- *
- * @param state
- */
- public final void updatePlaybackState(int state) {
- Bundle extras = new Bundle();
- extras.putInt(KEY_VALUE1, state);
- sendEvent(mSession, EVENT_PLAYSTATE_CHANGE, extras);
- }
- }
-
- /**
- * Register this event listener using TODO to receive
- * TransportControlInterface events from a session.
- *
- * @see RouteInterface.EventListener
- */
- public static abstract class Listener {
-
- private RouteInterface.EventListener mListener = new RouteInterface.EventListener() {
- @Override
- public final void onEvent(String event, Bundle args) {
- if (EVENT_PLAYSTATE_CHANGE.equals(event)) {
- onPlaybackStateChange(args.getInt(KEY_VALUE1));
- } else if (EVENT_METADATA_CHANGE.equals(event)) {
- onMetadataUpdate(args);
- }
- }
- };
-
- /**
- * Override to handle updates to the playback state. Valid values are in
- * {@link TransportPerformer}. TODO put playstate values somewhere more
- * generic.
- *
- * @param state
- */
- public void onPlaybackStateChange(int state) {
- }
-
- /**
- * Override to handle metadata changes for this session's media. The
- * default supported fields are those in {@link MediaMetadata}.
- *
- * @param metadata
- */
- public void onMetadataUpdate(Bundle metadata) {
- }
- }
-
-}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/Session.java
similarity index 66%
rename from media/java/android/media/session/MediaSession.java
rename to media/java/android/media/session/Session.java
index 23c3035..8ccd788 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/Session.java
@@ -18,9 +18,9 @@
import android.content.Intent;
import android.media.Rating;
-import android.media.session.IMediaController;
-import android.media.session.IMediaSession;
-import android.media.session.IMediaSessionCallback;
+import android.media.session.ISessionController;
+import android.media.session.ISession;
+import android.media.session.ISessionCallback;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -33,6 +33,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.List;
/**
* Allows interaction with media controllers, media routes, volume keys, media
@@ -44,11 +45,11 @@
* media to multiple routes or to provide finer grain controls of media.
* <p>
* A MediaSession is created by calling
- * {@link MediaSessionManager#createSession(String)}. Once a session is created
+ * {@link SessionManager#createSession(String)}. Once a session is created
* apps that have the MEDIA_CONTENT_CONTROL permission can interact with the
- * session through {@link MediaSessionManager#getActiveSessions()}. The owner of
+ * session through {@link SessionManager#getActiveSessions()}. The owner of
* the session may also use {@link #getSessionToken()} to allow apps without
- * this permission to create a {@link MediaController} to interact with this
+ * this permission to create a {@link SessionController} to interact with this
* session.
* <p>
* To receive commands, media keys, and other events a Callback must be set with
@@ -59,12 +60,13 @@
* <p>
* MediaSession objects are thread safe
*/
-public final class MediaSession {
- private static final String TAG = "MediaSession";
+public final class Session {
+ private static final String TAG = "Session";
private static final int MSG_MEDIA_BUTTON = 1;
private static final int MSG_COMMAND = 2;
private static final int MSG_ROUTE_CHANGE = 3;
+ private static final int MSG_ROUTE_CONNECTED = 4;
private static final String KEY_COMMAND = "command";
private static final String KEY_EXTRAS = "extras";
@@ -72,32 +74,33 @@
private final Object mLock = new Object();
- private final MediaSessionToken mSessionToken;
- private final IMediaSession mBinder;
+ private final SessionToken mSessionToken;
+ private final ISession mBinder;
private final CallbackStub mCbStub;
private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
// TODO route interfaces
- private final ArrayMap<String, RouteInterface.Stub> mInterfaces
- = new ArrayMap<String, RouteInterface.Stub>();
+ private final ArrayMap<String, RouteInterface.EventListener> mInterfaceListeners
+ = new ArrayMap<String, RouteInterface.EventListener>();
private TransportPerformer mPerformer;
+ private Route mRoute;
private boolean mPublished = false;;
/**
* @hide
*/
- public MediaSession(IMediaSession binder, CallbackStub cbStub) {
+ public Session(ISession binder, CallbackStub cbStub) {
mBinder = binder;
mCbStub = cbStub;
- IMediaController controllerBinder = null;
+ ISessionController controllerBinder = null;
try {
- controllerBinder = mBinder.getMediaController();
+ controllerBinder = mBinder.getController();
} catch (RemoteException e) {
throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
}
- mSessionToken = new MediaSessionToken(controllerBinder);
+ mSessionToken = new SessionToken(controllerBinder);
}
/**
@@ -109,6 +112,13 @@
addCallback(callback, null);
}
+ /**
+ * Add a callback to receive updates for the MediaSession. This includes
+ * events like route updates, media buttons, and focus changes.
+ *
+ * @param callback The callback to receive updates on.
+ * @param handler The handler that events should be posted on.
+ */
public void addCallback(Callback callback, Handler handler) {
if (callback == null) {
throw new IllegalArgumentException("Callback cannot be null");
@@ -126,6 +136,11 @@
}
}
+ /**
+ * Remove a callback. It will no longer receive updates.
+ *
+ * @param callback The callback to remove.
+ */
public void removeCallback(Callback callback) {
synchronized (mLock) {
removeCallbackLocked(callback);
@@ -186,30 +201,6 @@
}
/**
- * Add an interface that can be used by MediaSessions. TODO make this a
- * route provider api
- *
- * @see RouteInterface
- * @param iface The interface to add
- * @hide
- */
- public void addInterface(RouteInterface.Stub iface) {
- if (iface == null) {
- throw new IllegalArgumentException("Stub cannot be null");
- }
- String name = iface.getName();
- if (TextUtils.isEmpty(name)) {
- throw new IllegalArgumentException("Stub must return a valid name");
- }
- if (mInterfaces.containsKey(iface)) {
- throw new IllegalArgumentException("Interface is already added");
- }
- synchronized (mLock) {
- mInterfaces.put(iface.getName(), iface);
- }
- }
-
- /**
* Send a proprietary event to all MediaControllers listening to this
* Session. It's up to the Controller/Session owner to determine the meaning
* of any events.
@@ -243,16 +234,92 @@
/**
* Retrieve a token object that can be used by apps to create a
- * {@link MediaController} for interacting with this session. The owner of
+ * {@link SessionController} for interacting with this session. The owner of
* the session is responsible for deciding how to distribute these tokens.
*
* @return A token that can be used to create a MediaController for this
* session
*/
- public MediaSessionToken getSessionToken() {
+ public SessionToken getSessionToken() {
return mSessionToken;
}
+ /**
+ * Connect to the current route using the specified request.
+ * <p>
+ * Connection updates will be sent to the callback's
+ * {@link Callback#onRouteConnected(Route)} and
+ * {@link Callback#onRouteDisconnected(Route, int)} methods. If the
+ * connection fails {@link Callback#onRouteDisconnected(Route, int)}
+ * will be called.
+ * <p>
+ * If you already have a connection to this route it will be disconnected
+ * before the new connection is established. TODO add an easy way to compare
+ * MediaRouteOptions.
+ *
+ * @param route The route the app is trying to connect to.
+ * @param request The connection request to use.
+ */
+ public void connect(RouteInfo route, RouteOptions request) {
+ if (route == null) {
+ throw new IllegalArgumentException("Must specify the route");
+ }
+ if (request == null) {
+ throw new IllegalArgumentException("Must specify the connection request");
+ }
+ try {
+ mBinder.connectToRoute(route, request);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error starting connection to route", e);
+ }
+ }
+
+ /**
+ * Disconnect from the current route. After calling you will be switched
+ * back to the default route.
+ *
+ * @param route The route to disconnect from.
+ */
+ public void disconnect(RouteInfo route) {
+ // TODO
+ }
+
+ /**
+ * Set the list of route options your app is interested in connecting to. It
+ * will be used for picking valid routes.
+ *
+ * @param options The set of route options your app may use to connect.
+ */
+ public void setRouteOptions(List<RouteOptions> options) {
+ try {
+ mBinder.setRouteOptions(options);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error setting route options.", e);
+ }
+ }
+
+ /**
+ * @hide
+ * TODO allow multiple listeners for the same interface, allow removal
+ */
+ public void addInterfaceListener(String iface,
+ RouteInterface.EventListener listener) {
+ mInterfaceListeners.put(iface, listener);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean sendRouteCommand(RouteCommand command, ResultReceiver cb) {
+ try {
+ mBinder.sendRouteCommand(command, cb);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error sending command to route.", e);
+ return false;
+ }
+ return true;
+ }
+
private MessageHandler getHandlerForCallbackLocked(Callback cb) {
if (cb == null) {
throw new IllegalArgumentException("Callback cannot be null");
@@ -297,10 +364,19 @@
}
}
- private void postRequestRouteChange(Bundle mediaRouteDescriptor) {
+ private void postRequestRouteChange(RouteInfo route) {
synchronized (mLock) {
for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- mCallbacks.get(i).post(MSG_ROUTE_CHANGE, mediaRouteDescriptor);
+ mCallbacks.get(i).post(MSG_ROUTE_CHANGE, route);
+ }
+ }
+ }
+
+ private void postRouteConnected(RouteInfo route, RouteOptions options) {
+ synchronized (mLock) {
+ mRoute = new Route(route, options, this);
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ mCallbacks.get(i).post(MSG_ROUTE_CONNECTED, mRoute);
}
}
}
@@ -346,26 +422,49 @@
* The app is responsible for connecting to the new route and migrating
* ongoing playback if necessary.
*
- * @param descriptor
+ * @param route
*/
- public void onRequestRouteChange(Bundle descriptor) {
+ public void onRequestRouteChange(RouteInfo route) {
+ }
+
+ /**
+ * Called when a route has successfully connected. Calls to the route
+ * are now valid.
+ *
+ * @param route The route that was connected
+ */
+ public void onRouteConnected(Route route) {
+ }
+
+ /**
+ * Called when a route was disconnected. Further calls to the route will
+ * fail. If available a reason for being disconnected will be provided.
+ * <p>
+ * Valid reasons are:
+ * <ul>
+ * </ul>
+ *
+ * @param route The route that disconnected
+ * @param reason The reason for the disconnect
+ */
+ public void onRouteDisconnected(Route route, int reason) {
}
}
/**
* @hide
*/
- public static class CallbackStub extends IMediaSessionCallback.Stub {
- private WeakReference<MediaSession> mMediaSession;
+ public static class CallbackStub extends ISessionCallback.Stub {
+ private WeakReference<Session> mMediaSession;
- public void setMediaSession(MediaSession session) {
- mMediaSession = new WeakReference<MediaSession>(session);
+ public void setMediaSession(Session session) {
+ mMediaSession = new WeakReference<Session>(session);
}
@Override
public void onCommand(String command, Bundle extras, ResultReceiver cb)
throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
session.postCommand(command, extras, cb);
}
@@ -373,23 +472,31 @@
@Override
public void onMediaButton(Intent mediaButtonIntent) throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
session.postMediaButton(mediaButtonIntent);
}
}
@Override
- public void onRequestRouteChange(Bundle mediaRouteDescriptor) throws RemoteException {
- MediaSession session = mMediaSession.get();
+ public void onRequestRouteChange(RouteInfo route) throws RemoteException {
+ Session session = mMediaSession.get();
if (session != null) {
- session.postRequestRouteChange(mediaRouteDescriptor);
+ session.postRequestRouteChange(route);
+ }
+ }
+
+ @Override
+ public void onRouteConnected(RouteInfo route, RouteOptions options) {
+ Session session = mMediaSession.get();
+ if (session != null) {
+ session.postRouteConnected(route, options);
}
}
@Override
public void onPlay() throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -400,7 +507,7 @@
@Override
public void onPause() throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -411,7 +518,7 @@
@Override
public void onStop() throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -422,7 +529,7 @@
@Override
public void onNext() throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -433,7 +540,7 @@
@Override
public void onPrevious() throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -444,7 +551,7 @@
@Override
public void onFastForward() throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -455,7 +562,7 @@
@Override
public void onRewind() throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -466,7 +573,7 @@
@Override
public void onSeekTo(long pos) throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -477,7 +584,7 @@
@Override
public void onRate(Rating rating) throws RemoteException {
- MediaSession session = mMediaSession.get();
+ Session session = mMediaSession.get();
if (session != null) {
TransportPerformer tp = session.getTransportPerformer();
if (tp != null) {
@@ -486,12 +593,32 @@
}
}
+ @Override
+ public void onRouteEvent(RouteEvent event) throws RemoteException {
+ Session session = mMediaSession.get();
+ if (session != null) {
+ RouteInterface.EventListener iface
+ = session.mInterfaceListeners.get(event.getIface());
+ Log.d(TAG, "Received route event on iface " + event.getIface() + ". Listener is "
+ + iface);
+ if (iface != null) {
+ iface.onEvent(event.getEvent(), event.getExtras());
+ }
+ }
+ }
+
+ @Override
+ public void onRouteStateChange(int state) throws RemoteException {
+ // TODO
+
+ }
+
}
private class MessageHandler extends Handler {
- private MediaSession.Callback mCallback;
+ private Session.Callback mCallback;
- public MessageHandler(Looper looper, MediaSession.Callback callback) {
+ public MessageHandler(Looper looper, Session.Callback callback) {
super(looper, null, true);
mCallback = callback;
}
@@ -511,11 +638,13 @@
mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
break;
case MSG_ROUTE_CHANGE:
- mCallback.onRequestRouteChange((Bundle) msg.obj);
+ mCallback.onRequestRouteChange((RouteInfo) msg.obj);
+ break;
+ case MSG_ROUTE_CONNECTED:
+ mCallback.onRouteConnected((Route) msg.obj);
break;
}
}
- msg.recycle();
}
public void post(int what, Object obj) {
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/SessionController.java
similarity index 83%
rename from media/java/android/media/session/MediaController.java
rename to media/java/android/media/session/SessionController.java
index afd8b11..dc4f7d9 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/SessionController.java
@@ -34,21 +34,21 @@
* other commands can be sent to the session. A callback may be registered to
* receive updates from the session, such as metadata and play state changes.
* <p>
- * A MediaController can be created through {@link MediaSessionManager} if you
+ * A MediaController can be created through {@link SessionManager} if you
* hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if
- * you have a {@link MediaSessionToken} from the session owner.
+ * you have a {@link SessionToken} from the session owner.
* <p>
* MediaController objects are thread-safe.
*/
-public final class MediaController {
- private static final String TAG = "MediaController";
+public final class SessionController {
+ private static final String TAG = "SessionController";
private static final int MSG_EVENT = 1;
private static final int MESSAGE_PLAYBACK_STATE = 2;
private static final int MESSAGE_METADATA = 3;
private static final int MSG_ROUTE = 4;
- private final IMediaController mSessionBinder;
+ private final ISessionController mSessionBinder;
private final CallbackStub mCbStub = new CallbackStub(this);
private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
@@ -58,15 +58,15 @@
private TransportController mTransportController;
- private MediaController(IMediaController sessionBinder) {
+ private SessionController(ISessionController sessionBinder) {
mSessionBinder = sessionBinder;
}
/**
* @hide
*/
- public static MediaController fromBinder(IMediaController sessionBinder) {
- MediaController controller = new MediaController(sessionBinder);
+ public static SessionController fromBinder(ISessionController sessionBinder) {
+ SessionController controller = new SessionController(sessionBinder);
try {
controller.mSessionBinder.registerCallbackListener(controller.mCbStub);
if (controller.mSessionBinder.isTransportControlEnabled()) {
@@ -87,7 +87,7 @@
* @param token The session token to use
* @return A controller for the session or null
*/
- public static MediaController fromToken(MediaSessionToken token) {
+ public static SessionController fromToken(SessionToken token) {
return fromBinder(token.getBinder());
}
@@ -181,10 +181,22 @@
}
}
+ /**
+ * Request that the route picker be shown for this session. This should
+ * generally be called in response to a user action.
+ */
+ public void showRoutePicker() {
+ try {
+ mSessionBinder.showRoutePicker();
+ } catch (RemoteException e) {
+ Log.d(TAG, "Dead object in showRoutePicker", e);
+ }
+ }
+
/*
* @hide
*/
- IMediaController getSessionBinder() {
+ ISessionController getSessionBinder() {
return mSessionBinder;
}
@@ -247,10 +259,10 @@
}
}
- private void postRouteChanged(Bundle routeDescriptor) {
+ private void postRouteChanged(RouteInfo route) {
synchronized (mLock) {
for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- mCallbacks.get(i).post(MSG_ROUTE, null, routeDescriptor);
+ mCallbacks.get(i).post(MSG_ROUTE, route, null);
}
}
}
@@ -275,36 +287,36 @@
*
* @param route
*/
- public void onRouteChanged(Bundle route) {
+ public void onRouteChanged(RouteInfo route) {
}
}
- private final static class CallbackStub extends IMediaControllerCallback.Stub {
- private final WeakReference<MediaController> mController;
+ private final static class CallbackStub extends ISessionControllerCallback.Stub {
+ private final WeakReference<SessionController> mController;
- public CallbackStub(MediaController controller) {
- mController = new WeakReference<MediaController>(controller);
+ public CallbackStub(SessionController controller) {
+ mController = new WeakReference<SessionController>(controller);
}
@Override
public void onEvent(String event, Bundle extras) {
- MediaController controller = mController.get();
+ SessionController controller = mController.get();
if (controller != null) {
controller.postEvent(event, extras);
}
}
@Override
- public void onRouteChanged(Bundle mediaRouteDescriptor) {
- MediaController controller = mController.get();
+ public void onRouteChanged(RouteInfo route) {
+ SessionController controller = mController.get();
if (controller != null) {
- controller.postRouteChanged(mediaRouteDescriptor);
+ controller.postRouteChanged(route);
}
}
@Override
public void onPlaybackStateChanged(PlaybackState state) {
- MediaController controller = mController.get();
+ SessionController controller = mController.get();
if (controller != null) {
TransportController tc = controller.getTransportController();
if (tc != null) {
@@ -315,7 +327,7 @@
@Override
public void onMetadataChanged(MediaMetadata metadata) {
- MediaController controller = mController.get();
+ SessionController controller = mController.get();
if (controller != null) {
TransportController tc = controller.getTransportController();
if (tc != null) {
@@ -327,9 +339,9 @@
}
private final static class MessageHandler extends Handler {
- private final MediaController.Callback mCallback;
+ private final SessionController.Callback mCallback;
- public MessageHandler(Looper looper, MediaController.Callback cb) {
+ public MessageHandler(Looper looper, SessionController.Callback cb) {
super(looper, null, true);
mCallback = cb;
}
@@ -341,7 +353,7 @@
mCallback.onEvent((String) msg.obj, msg.getData());
break;
case MSG_ROUTE:
- mCallback.onRouteChanged(msg.getData());
+ mCallback.onRouteChanged((RouteInfo) msg.obj);
}
}
diff --git a/media/java/android/media/session/SessionInfo.java b/media/java/android/media/session/SessionInfo.java
new file mode 100644
index 0000000..22d8ab1
--- /dev/null
+++ b/media/java/android/media/session/SessionInfo.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.media.session;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about a media session, including the owner's package name.
+ */
+public final class SessionInfo implements Parcelable {
+ private final String mId;
+ private final String mPackageName;
+
+ /**
+ * @hide
+ */
+ public SessionInfo(String id, String packageName) {
+ mId = id;
+ mPackageName = packageName;
+ }
+
+ private SessionInfo(Parcel in) {
+ mId = in.readString();
+ mPackageName = in.readString();
+ }
+
+ /**
+ * Get the package name of the owner of this session.
+ *
+ * @return The owner's package name
+ */
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Get the unique id for this session.
+ *
+ * @return The id for the session.
+ */
+ public String getId() {
+ return mId;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ dest.writeString(mPackageName);
+ }
+
+ public static final Parcelable.Creator<SessionInfo> CREATOR
+ = new Parcelable.Creator<SessionInfo>() {
+ @Override
+ public SessionInfo createFromParcel(Parcel in) {
+ return new SessionInfo(in);
+ }
+
+ @Override
+ public SessionInfo[] newArray(int size) {
+ return new SessionInfo[size];
+ }
+ };
+}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/SessionManager.java
similarity index 75%
rename from media/java/android/media/session/MediaSessionManager.java
rename to media/java/android/media/session/SessionManager.java
index e3f2d9c..15bf0e3 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/SessionManager.java
@@ -17,7 +17,7 @@
package android.media.session;
import android.content.Context;
-import android.media.session.IMediaSessionManager;
+import android.media.session.ISessionManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -35,37 +35,37 @@
* get an instance of this class.
* <p>
*
- * @see MediaSession
- * @see MediaController
+ * @see Session
+ * @see SessionController
*/
-public final class MediaSessionManager {
- private static final String TAG = "MediaSessionManager";
+public final class SessionManager {
+ private static final String TAG = "SessionManager";
- private final IMediaSessionManager mService;
+ private final ISessionManager mService;
private Context mContext;
/**
* @hide
*/
- public MediaSessionManager(Context context) {
+ public SessionManager(Context context) {
// Consider rewriting like DisplayManagerGlobal
// Decide if we need context
mContext = context;
IBinder b = ServiceManager.getService(Context.MEDIA_SESSION_SERVICE);
- mService = IMediaSessionManager.Stub.asInterface(b);
+ mService = ISessionManager.Stub.asInterface(b);
}
/**
* Creates a new session.
*
* @param tag A short name for debugging purposes
- * @return a {@link MediaSession} for the new session
+ * @return a {@link Session} for the new session
*/
- public MediaSession createSession(String tag) {
+ public Session createSession(String tag) {
try {
- MediaSession.CallbackStub cbStub = new MediaSession.CallbackStub();
- MediaSession session = new MediaSession(mService
+ Session.CallbackStub cbStub = new Session.CallbackStub();
+ Session session = new Session(mService
.createSession(mContext.getPackageName(), cbStub, tag), cbStub);
cbStub.setMediaSession(session);
@@ -83,8 +83,8 @@
*
* @return a list of controllers for ongoing sessions
*/
- public List<MediaController> getActiveSessions() {
+ public List<SessionController> getActiveSessions() {
// TODO
- return new ArrayList<MediaController>();
+ return new ArrayList<SessionController>();
}
}
diff --git a/media/java/android/media/session/MediaSessionToken.aidl b/media/java/android/media/session/SessionToken.aidl
similarity index 95%
copy from media/java/android/media/session/MediaSessionToken.aidl
copy to media/java/android/media/session/SessionToken.aidl
index 5812682..db35f85 100644
--- a/media/java/android/media/session/MediaSessionToken.aidl
+++ b/media/java/android/media/session/SessionToken.aidl
@@ -15,4 +15,4 @@
package android.media.session;
-parcelable MediaSessionToken;
+parcelable SessionToken;
diff --git a/media/java/android/media/session/MediaSessionToken.java b/media/java/android/media/session/SessionToken.java
similarity index 62%
rename from media/java/android/media/session/MediaSessionToken.java
rename to media/java/android/media/session/SessionToken.java
index dbb4964..59486f6 100644
--- a/media/java/android/media/session/MediaSessionToken.java
+++ b/media/java/android/media/session/SessionToken.java
@@ -16,28 +16,28 @@
package android.media.session;
-import android.media.session.IMediaController;
+import android.media.session.ISessionController;
import android.os.Parcel;
import android.os.Parcelable;
-public class MediaSessionToken implements Parcelable {
- private IMediaController mBinder;
+public class SessionToken implements Parcelable {
+ private ISessionController mBinder;
/**
* @hide
*/
- MediaSessionToken(IMediaController binder) {
+ SessionToken(ISessionController binder) {
mBinder = binder;
}
- private MediaSessionToken(Parcel in) {
- mBinder = IMediaController.Stub.asInterface(in.readStrongBinder());
+ private SessionToken(Parcel in) {
+ mBinder = ISessionController.Stub.asInterface(in.readStrongBinder());
}
/**
* @hide
*/
- IMediaController getBinder() {
+ ISessionController getBinder() {
return mBinder;
}
@@ -51,16 +51,16 @@
dest.writeStrongBinder(mBinder.asBinder());
}
- public static final Parcelable.Creator<MediaSessionToken> CREATOR
- = new Parcelable.Creator<MediaSessionToken>() {
+ public static final Parcelable.Creator<SessionToken> CREATOR
+ = new Parcelable.Creator<SessionToken>() {
@Override
- public MediaSessionToken createFromParcel(Parcel in) {
- return new MediaSessionToken(in);
+ public SessionToken createFromParcel(Parcel in) {
+ return new SessionToken(in);
}
@Override
- public MediaSessionToken[] newArray(int size) {
- return new MediaSessionToken[size];
+ public SessionToken[] newArray(int size) {
+ return new SessionToken[size];
}
};
}
diff --git a/media/java/android/media/session/TransportController.java b/media/java/android/media/session/TransportController.java
index 15b11f3..9574df6 100644
--- a/media/java/android/media/session/TransportController.java
+++ b/media/java/android/media/session/TransportController.java
@@ -34,12 +34,12 @@
private final Object mLock = new Object();
private final ArrayList<MessageHandler> mListeners = new ArrayList<MessageHandler>();
- private final IMediaController mBinder;
+ private final ISessionController mBinder;
/**
* @hide
*/
- public TransportController(IMediaController binder) {
+ public TransportController(ISessionController binder) {
mBinder = binder;
}
diff --git a/media/java/android/media/session/TransportPerformer.java b/media/java/android/media/session/TransportPerformer.java
index b96db20..eddffd1 100644
--- a/media/java/android/media/session/TransportPerformer.java
+++ b/media/java/android/media/session/TransportPerformer.java
@@ -34,12 +34,12 @@
private final Object mLock = new Object();
private final ArrayList<MessageHandler> mListeners = new ArrayList<MessageHandler>();
- private IMediaSession mBinder;
+ private ISession mBinder;
/**
* @hide
*/
- public TransportPerformer(IMediaSession binder) {
+ public TransportPerformer(ISession binder) {
mBinder = binder;
}
diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java
deleted file mode 100644
index c5cc2ca..0000000
--- a/media/java/android/media/videoeditor/AudioTrack.java
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.ref.SoftReference;
-
-import android.media.videoeditor.MediaArtistNativeHelper.Properties;
-
-/**
- * This class allows to handle an audio track. This audio file is mixed with the
- * audio samples of the media items.
- * {@hide}
- */
-public class AudioTrack {
-
- /**
- * Instance variables
- * Private object for calling native methods via MediaArtistNativeHelper
- */
- private final MediaArtistNativeHelper mMANativeHelper;
- private final String mUniqueId;
- private final String mFilename;
- private long mStartTimeMs;
- private long mTimelineDurationMs;
- private int mVolumePercent;
- private long mBeginBoundaryTimeMs;
- private long mEndBoundaryTimeMs;
- private boolean mLoop;
- private boolean mMuted;
- private final long mDurationMs;
- private final int mAudioChannels;
- private final int mAudioType;
- private final int mAudioBitrate;
- private final int mAudioSamplingFrequency;
- /**
- * Ducking variables
- */
- private int mDuckingThreshold;
- private int mDuckedTrackVolume;
- private boolean mIsDuckingEnabled;
-
- /**
- * The audio waveform filename
- */
- private String mAudioWaveformFilename;
-
- /**
- * The audio waveform data
- */
- private SoftReference<WaveformData> mWaveformData;
-
- /**
- * An object of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private AudioTrack() throws IOException {
- this(null, null, null);
- }
-
- /**
- * Constructor
- *
- * @param editor The video editor reference
- * @param audioTrackId The audio track id
- * @param filename The absolute file name
- *
- * @throws IOException if file is not found
- * @throws IllegalArgumentException if file format is not supported or if
- * the codec is not supported or if editor is not of type
- * VideoEditorImpl.
- */
- public AudioTrack(VideoEditor editor, String audioTrackId, String filename) throws IOException {
- this(editor, audioTrackId, filename, 0, 0, MediaItem.END_OF_FILE, false, 100, false, false,
- 0, 0, null);
- }
-
- /**
- * Constructor
- *
- * @param editor The video editor reference
- * @param audioTrackId The audio track id
- * @param filename The audio filename. In case file contains Audio and Video,
- * only the Audio stream will be used as Audio Track.
- * @param startTimeMs the start time in milliseconds (relative to the
- * timeline)
- * @param beginMs start time in the audio track in milliseconds (relative to
- * the beginning of the audio track)
- * @param endMs end time in the audio track in milliseconds (relative to the
- * beginning of the audio track)
- * @param loop true to loop the audio track
- * @param volume The volume in percentage
- * @param muted true if the audio track is muted
- * @param threshold Ducking will be activated when the relative energy in
- * the media items audio signal goes above this value. The valid
- * range of values is 0 to 90.
- * @param duckedTrackVolume The relative volume of the audio track when
- * ducking is active. The valid range of values is 0 to 100.
- * @param audioWaveformFilename The name of the waveform file
- *
- * @throws IOException if file is not found
- * @throws IllegalArgumentException if file format is not supported or if
- * the codec is not supported or if editor is not of type
- * VideoEditorImpl.
- */
- AudioTrack(VideoEditor editor, String audioTrackId, String filename,
- long startTimeMs,long beginMs, long endMs, boolean loop,
- int volume, boolean muted,boolean duckingEnabled,
- int duckThreshold, int duckedTrackVolume,
- String audioWaveformFilename) throws IOException {
- Properties properties = null;
-
- File file = new File(filename);
- if (!file.exists()) {
- throw new IOException(filename + " not found ! ");
- }
-
- /*Compare file_size with 2GB*/
- if (VideoEditor.MAX_SUPPORTED_FILE_SIZE <= file.length()) {
- throw new IllegalArgumentException("File size is more than 2GB");
- }
-
- if (editor instanceof VideoEditorImpl) {
- mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
- } else {
- throw new IllegalArgumentException("editor is not of type VideoEditorImpl");
- }
- try {
- properties = mMANativeHelper.getMediaProperties(filename);
- } catch (Exception e) {
- throw new IllegalArgumentException(e.getMessage() + " : " + filename);
- }
- int fileType = mMANativeHelper.getFileType(properties.fileType);
- switch (fileType) {
- case MediaProperties.FILE_3GP:
- case MediaProperties.FILE_MP4:
- case MediaProperties.FILE_MP3:
- case MediaProperties.FILE_AMR:
- break;
-
- default: {
- throw new IllegalArgumentException("Unsupported input file type: " + fileType);
- }
- }
- switch (mMANativeHelper.getAudioCodecType(properties.audioFormat)) {
- case MediaProperties.ACODEC_AMRNB:
- case MediaProperties.ACODEC_AMRWB:
- case MediaProperties.ACODEC_AAC_LC:
- case MediaProperties.ACODEC_MP3:
- break;
- default:
- throw new IllegalArgumentException("Unsupported Audio Codec Format in Input File");
- }
-
- if (endMs == MediaItem.END_OF_FILE) {
- endMs = properties.audioDuration;
- }
-
- mUniqueId = audioTrackId;
- mFilename = filename;
- mStartTimeMs = startTimeMs;
- mDurationMs = properties.audioDuration;
- mAudioChannels = properties.audioChannels;
- mAudioBitrate = properties.audioBitrate;
- mAudioSamplingFrequency = properties.audioSamplingFrequency;
- mAudioType = properties.audioFormat;
- mTimelineDurationMs = endMs - beginMs;
- mVolumePercent = volume;
-
- mBeginBoundaryTimeMs = beginMs;
- mEndBoundaryTimeMs = endMs;
-
- mLoop = loop;
- mMuted = muted;
- mIsDuckingEnabled = duckingEnabled;
- mDuckingThreshold = duckThreshold;
- mDuckedTrackVolume = duckedTrackVolume;
-
- mAudioWaveformFilename = audioWaveformFilename;
- if (audioWaveformFilename != null) {
- mWaveformData =
- new SoftReference<WaveformData>(new WaveformData(audioWaveformFilename));
- } else {
- mWaveformData = null;
- }
- }
-
- /**
- * Get the id of the audio track
- *
- * @return The id of the audio track
- */
- public String getId() {
- return mUniqueId;
- }
-
- /**
- * Get the filename for this audio track source.
- *
- * @return The filename as an absolute file name
- */
- public String getFilename() {
- return mFilename;
- }
-
- /**
- * Get the number of audio channels in the source of this audio track
- *
- * @return The number of audio channels in the source of this audio track
- */
- public int getAudioChannels() {
- return mAudioChannels;
- }
-
- /**
- * Get the audio codec of the source of this audio track
- *
- * @return The audio codec of the source of this audio track
- * {@link android.media.videoeditor.MediaProperties}
- */
- public int getAudioType() {
- return mAudioType;
- }
-
- /**
- * Get the audio sample frequency of the audio track
- *
- * @return The audio sample frequency of the audio track
- */
- public int getAudioSamplingFrequency() {
- return mAudioSamplingFrequency;
- }
-
- /**
- * Get the audio bitrate of the audio track
- *
- * @return The audio bitrate of the audio track
- */
- public int getAudioBitrate() {
- return mAudioBitrate;
- }
-
- /**
- * Set the volume of this audio track as percentage of the volume in the
- * original audio source file.
- *
- * @param volumePercent Percentage of the volume to apply. If it is set to
- * 0, then volume becomes mute. It it is set to 100, then volume
- * is same as original volume. It it is set to 200, then volume
- * is doubled (provided that volume amplification is supported)
- *
- * @throws UnsupportedOperationException if volume amplification is
- * requested and is not supported.
- */
- public void setVolume(int volumePercent) {
- if (volumePercent > MediaProperties.AUDIO_MAX_VOLUME_PERCENT) {
- throw new IllegalArgumentException("Volume set exceeds maximum allowed value");
- }
-
- if (volumePercent < 0) {
- throw new IllegalArgumentException("Invalid Volume ");
- }
-
- /**
- * Force update of preview settings
- */
- mMANativeHelper.setGeneratePreview(true);
-
- mVolumePercent = volumePercent;
- }
-
- /**
- * Get the volume of the audio track as percentage of the volume in the
- * original audio source file.
- *
- * @return The volume in percentage
- */
- public int getVolume() {
- return mVolumePercent;
- }
-
- /**
- * Mute/Unmute the audio track
- *
- * @param muted true to mute the audio track. SetMute(true) will make
- * the volume of this Audio Track to 0.
- */
- public void setMute(boolean muted) {
- /**
- * Force update of preview settings
- */
- mMANativeHelper.setGeneratePreview(true);
- mMuted = muted;
- }
-
- /**
- * Check if the audio track is muted
- *
- * @return true if the audio track is muted
- */
- public boolean isMuted() {
- return mMuted;
- }
-
- /**
- * Get the start time of this audio track relative to the storyboard
- * timeline.
- *
- * @return The start time in milliseconds
- */
-
- public long getStartTime() {
- return mStartTimeMs;
- }
-
- /**
- * Get the audio track duration
- *
- * @return The duration in milliseconds. This value represents actual audio
- * track duration. This value is not effected by 'enableLoop' or
- * 'setExtractBoundaries'.
- */
- public long getDuration() {
- return mDurationMs;
- }
-
- /**
- * Get the audio track timeline duration
- *
- * @return The timeline duration as defined by the begin and end boundaries
- */
- public long getTimelineDuration() {
- return mTimelineDurationMs;
- }
-
- /**
- * Sets the start and end marks for trimming an audio track
- *
- * @param beginMs start time in the audio track in milliseconds (relative to
- * the beginning of the audio track)
- * @param endMs end time in the audio track in milliseconds (relative to the
- * beginning of the audio track)
- */
- public void setExtractBoundaries(long beginMs, long endMs) {
- if (beginMs > mDurationMs) {
- throw new IllegalArgumentException("Invalid start time");
- }
- if (endMs > mDurationMs) {
- throw new IllegalArgumentException("Invalid end time");
- }
- if (beginMs < 0) {
- throw new IllegalArgumentException("Invalid start time; is < 0");
- }
- if (endMs < 0) {
- throw new IllegalArgumentException("Invalid end time; is < 0");
- }
-
- /**
- * Force update of preview settings
- */
- mMANativeHelper.setGeneratePreview(true);
-
- mBeginBoundaryTimeMs = beginMs;
- mEndBoundaryTimeMs = endMs;
-
- mTimelineDurationMs = mEndBoundaryTimeMs - mBeginBoundaryTimeMs;
- }
-
- /**
- * Get the boundary begin time
- *
- * @return The boundary begin time
- */
- public long getBoundaryBeginTime() {
- return mBeginBoundaryTimeMs;
- }
-
- /**
- * Get the boundary end time
- *
- * @return The boundary end time
- */
- public long getBoundaryEndTime() {
- return mEndBoundaryTimeMs;
- }
-
- /**
- * Enable the loop mode for this audio track. Note that only one of the
- * audio tracks in the timeline can have the loop mode enabled. When looping
- * is enabled the samples between mBeginBoundaryTimeMs and
- * mEndBoundaryTimeMs are looped.
- */
- public void enableLoop() {
- if (!mLoop) {
- /**
- * Force update of preview settings
- */
- mMANativeHelper.setGeneratePreview(true);
- mLoop = true;
- }
- }
-
- /**
- * Disable the loop mode
- */
- public void disableLoop() {
- if (mLoop) {
- /**
- * Force update of preview settings
- */
- mMANativeHelper.setGeneratePreview(true);
- mLoop = false;
- }
- }
-
- /**
- * Check if looping is enabled
- *
- * @return true if looping is enabled
- */
- public boolean isLooping() {
- return mLoop;
- }
-
- /**
- * Disable the audio duck effect
- */
- public void disableDucking() {
- if (mIsDuckingEnabled) {
- /**
- * Force update of preview settings
- */
- mMANativeHelper.setGeneratePreview(true);
- mIsDuckingEnabled = false;
- }
- }
-
- /**
- * Enable ducking by specifying the required parameters
- *
- * @param threshold Ducking will be activated when the energy in
- * the media items audio signal goes above this value. The valid
- * range of values is 0db to 90dB. 0dB is equivalent to disabling
- * ducking.
- * @param duckedTrackVolume The relative volume of the audio track when ducking
- * is active. The valid range of values is 0 to 100.
- */
- public void enableDucking(int threshold, int duckedTrackVolume) {
- if (threshold < 0 || threshold > 90) {
- throw new IllegalArgumentException("Invalid threshold value: " + threshold);
- }
-
- if (duckedTrackVolume < 0 || duckedTrackVolume > 100) {
- throw new IllegalArgumentException("Invalid duckedTrackVolume value: "
- + duckedTrackVolume);
- }
-
- /**
- * Force update of preview settings
- */
- mMANativeHelper.setGeneratePreview(true);
-
- mDuckingThreshold = threshold;
- mDuckedTrackVolume = duckedTrackVolume;
- mIsDuckingEnabled = true;
- }
-
- /**
- * Check if ducking is enabled
- *
- * @return true if ducking is enabled
- */
- public boolean isDuckingEnabled() {
- return mIsDuckingEnabled;
- }
-
- /**
- * Get the ducking threshold.
- *
- * @return The ducking threshold
- */
- public int getDuckingThreshhold() {
- return mDuckingThreshold;
- }
-
- /**
- * Get the ducked track volume.
- *
- * @return The ducked track volume
- */
- public int getDuckedTrackVolume() {
- return mDuckedTrackVolume;
- }
-
- /**
- * This API allows to generate a file containing the sample volume levels of
- * this audio track object. This function may take significant time and is
- * blocking. The filename can be retrieved using getAudioWaveformFilename().
- *
- * @param listener The progress listener
- *
- * @throws IOException if the output file cannot be created
- * @throws IllegalArgumentException if the audio file does not have a valid
- * audio track
- * @throws IllegalStateException if the codec type is unsupported
- */
- public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)
- throws IOException {
- if (mAudioWaveformFilename == null) {
- /**
- * AudioWaveformFilename is generated
- */
- final String projectPath = mMANativeHelper.getProjectPath();
- final String audioWaveFilename = String.format(projectPath + "/audioWaveformFile-"
- + getId() + ".dat");
-
- /**
- * Logic to get frame duration = (no. of frames per sample * 1000)/
- * sampling frequency
- */
- final int frameDuration;
- final int sampleCount;
- final int codecType = mMANativeHelper.getAudioCodecType(mAudioType);
- switch (codecType) {
- case MediaProperties.ACODEC_AMRNB: {
- frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRNB * 1000)
- / MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
- sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRNB;
- break;
- }
-
- case MediaProperties.ACODEC_AMRWB: {
- frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRWB * 1000)
- / MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
- sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRWB;
- break;
- }
-
- case MediaProperties.ACODEC_AAC_LC: {
- frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AAC * 1000)
- / MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
- sampleCount = MediaProperties.SAMPLES_PER_FRAME_AAC;
- break;
- }
-
- case MediaProperties.ACODEC_MP3: {
- frameDuration = (MediaProperties.SAMPLES_PER_FRAME_MP3 * 1000)
- / MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
- sampleCount = MediaProperties.SAMPLES_PER_FRAME_MP3;
- break;
- }
-
- default: {
- throw new IllegalStateException("Unsupported codec type: "
- + codecType);
- }
- }
-
- mMANativeHelper.generateAudioGraph( mUniqueId,
- mFilename,
- audioWaveFilename,
- frameDuration,
- MediaProperties.DEFAULT_CHANNEL_COUNT,
- sampleCount,
- listener,
- false);
- /**
- * Record the generated file name
- */
- mAudioWaveformFilename = audioWaveFilename;
- }
- mWaveformData = new SoftReference<WaveformData>(new WaveformData(mAudioWaveformFilename));
- }
-
- /**
- * Get the audio waveform file name if extractAudioWaveform was successful.
- *
- * @return the name of the file, null if the file does not exist
- */
- String getAudioWaveformFilename() {
- return mAudioWaveformFilename;
- }
-
- /**
- * Delete the waveform file
- */
- void invalidate() {
- if (mAudioWaveformFilename != null) {
- new File(mAudioWaveformFilename).delete();
- mAudioWaveformFilename = null;
- mWaveformData = null;
- }
- }
-
- /**
- * Get the audio waveform data.
- *
- * @return The waveform data
- *
- * @throws IOException if the waveform file cannot be found
- */
- public WaveformData getWaveformData() throws IOException {
- if (mWaveformData == null) {
- return null;
- }
-
- WaveformData waveformData = mWaveformData.get();
- if (waveformData != null) {
- return waveformData;
- } else if (mAudioWaveformFilename != null) {
- try {
- waveformData = new WaveformData(mAudioWaveformFilename);
- } catch (IOException e) {
- throw e;
- }
- mWaveformData = new SoftReference<WaveformData>(waveformData);
- return waveformData;
- } else {
- return null;
- }
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof AudioTrack)) {
- return false;
- }
- return mUniqueId.equals(((AudioTrack)object).mUniqueId);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return mUniqueId.hashCode();
- }
-}
diff --git a/media/java/android/media/videoeditor/Effect.java b/media/java/android/media/videoeditor/Effect.java
deleted file mode 100644
index 2f7ae03..0000000
--- a/media/java/android/media/videoeditor/Effect.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-/**
- * This is the super class for all effects. An effect can only be applied to a
- * single media item.
- * {@hide}
- */
-public abstract class Effect {
- /**
- * Instance variables
- */
- private final String mUniqueId;
- /**
- * The effect owner
- */
- private final MediaItem mMediaItem;
-
- protected long mDurationMs;
- /**
- * The start time of the effect relative to the beginning
- * of the media item
- */
- protected long mStartTimeMs;
-
- /**
- * Default constructor
- */
- @SuppressWarnings("unused")
- private Effect() {
- mMediaItem = null;
- mUniqueId = null;
- mStartTimeMs = 0;
- mDurationMs = 0;
- }
-
- /**
- * Constructor
- *
- * @param mediaItem The media item owner
- * @param effectId The effect id
- * @param startTimeMs The start time relative to the media item to which it
- * is applied
- * @param durationMs The effect duration in milliseconds
- */
- public Effect(MediaItem mediaItem, String effectId, long startTimeMs,
- long durationMs) {
- if (mediaItem == null) {
- throw new IllegalArgumentException("Media item cannot be null");
- }
-
- if ((startTimeMs < 0) || (durationMs < 0)) {
- throw new IllegalArgumentException("Invalid start time Or/And Duration");
- }
- if (startTimeMs + durationMs > mediaItem.getDuration()) {
- throw new IllegalArgumentException("Invalid start time and duration");
- }
-
- mMediaItem = mediaItem;
- mUniqueId = effectId;
- mStartTimeMs = startTimeMs;
- mDurationMs = durationMs;
- }
-
- /**
- * Get the id of the effect.
- *
- * @return The id of the effect
- */
- public String getId() {
- return mUniqueId;
- }
-
- /**
- * Set the duration of the effect. If a preview or export is in progress,
- * then this change is effective for next preview or export session.
- *
- * @param durationMs of the effect in milliseconds
- */
- public void setDuration(long durationMs) {
- if (durationMs <0) {
- throw new IllegalArgumentException("Invalid duration");
- }
-
- if (mStartTimeMs + durationMs > mMediaItem.getDuration()) {
- throw new IllegalArgumentException("Duration is too large");
- }
-
- getMediaItem().getNativeContext().setGeneratePreview(true);
-
- final long oldDurationMs = mDurationMs;
- mDurationMs = durationMs;
-
- mMediaItem.invalidateTransitions(mStartTimeMs, oldDurationMs, mStartTimeMs, mDurationMs);
- }
-
- /**
- * Get the duration of the effect
- *
- * @return The duration of the effect in milliseconds
- */
- public long getDuration() {
- return mDurationMs;
- }
-
- /**
- * Set start time of the effect. If a preview or export is in progress, then
- * this change is effective for next preview or export session.
- *
- * @param startTimeMs The start time of the effect relative to the beginning
- * of the media item in milliseconds
- */
- public void setStartTime(long startTimeMs) {
- if (startTimeMs + mDurationMs > mMediaItem.getDuration()) {
- throw new IllegalArgumentException("Start time is too large");
- }
-
- getMediaItem().getNativeContext().setGeneratePreview(true);
- final long oldStartTimeMs = mStartTimeMs;
- mStartTimeMs = startTimeMs;
-
- mMediaItem.invalidateTransitions(oldStartTimeMs, mDurationMs, mStartTimeMs, mDurationMs);
- }
-
- /**
- * Get the start time of the effect
- *
- * @return The start time in milliseconds
- */
- public long getStartTime() {
- return mStartTimeMs;
- }
-
- /**
- * Set the start time and duration
- *
- * @param startTimeMs start time in milliseconds
- * @param durationMs The duration in milliseconds
- */
- public void setStartTimeAndDuration(long startTimeMs, long durationMs) {
- if (startTimeMs + durationMs > mMediaItem.getDuration()) {
- throw new IllegalArgumentException("Invalid start time or duration");
- }
-
- getMediaItem().getNativeContext().setGeneratePreview(true);
- final long oldStartTimeMs = mStartTimeMs;
- final long oldDurationMs = mDurationMs;
-
- mStartTimeMs = startTimeMs;
- mDurationMs = durationMs;
-
- mMediaItem.invalidateTransitions(oldStartTimeMs, oldDurationMs, mStartTimeMs, mDurationMs);
- }
-
- /**
- * Get the media item owner.
- *
- * @return The media item owner
- */
- public MediaItem getMediaItem() {
- return mMediaItem;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof Effect)) {
- return false;
- }
- return mUniqueId.equals(((Effect)object).mUniqueId);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return mUniqueId.hashCode();
- }
-}
diff --git a/media/java/android/media/videoeditor/EffectColor.java b/media/java/android/media/videoeditor/EffectColor.java
deleted file mode 100644
index 6c5ac2d..0000000
--- a/media/java/android/media/videoeditor/EffectColor.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-/**
- * This class allows to apply color effect on a media item.
- * {@hide}
- */
-public class EffectColor extends Effect {
-
- /**
- * Change the video frame color to the RGB color value provided
- */
- public static final int TYPE_COLOR = 1;
- /**
- * Change the video frame color to a gradation from RGB color (at the top of
- * the frame) to black (at the bottom of the frame).
- */
- public static final int TYPE_GRADIENT = 2;
- /**
- * Change the video frame color to sepia
- */
- public static final int TYPE_SEPIA = 3;
- /**
- * Invert the video frame color
- */
- public static final int TYPE_NEGATIVE = 4;
- /**
- * Make the video look like as if it was recorded in 50's
- */
- public static final int TYPE_FIFTIES = 5;
- /**
- * Change the video frame color to the RGB color value GREEN
- */
- public static final int GREEN = 0x0000ff00;
- /**
- * Change the video frame color to the RGB color value PINK
- */
- public static final int PINK = 0x00ff66cc;
- /**
- * Change the video frame color to the RGB color value GRAY
- */
- public static final int GRAY = 0x007f7f7f;
-
- /**
- * The effect type
- */
- private final int mType;
-
- /**
- * The effect color
- */
- private final int mColor;
-
- /**
- * An object of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private EffectColor() {
- this(null, null, 0, 0, 0, 0);
- }
-
- /**
- * Constructor
- *
- * @param mediaItem The media item owner
- * @param effectId The effect id
- * @param startTimeMs The start time relative to the media item to which it
- * is applied
- * @param durationMs The duration of this effect in milliseconds
- * @param type type of the effect. type is one of: TYPE_COLOR,
- * TYPE_GRADIENT, TYPE_SEPIA, TYPE_NEGATIVE, TYPE_FIFTIES.
- * @param color If type is TYPE_COLOR, color is the RGB color as 888.
- * If type is TYPE_GRADIENT, color is the RGB color at the
- * top of the frame. Otherwise, color is ignored
- */
- public EffectColor(MediaItem mediaItem, String effectId, long startTimeMs,
- long durationMs, int type, int color) {
- super(mediaItem, effectId, startTimeMs, durationMs);
- switch (type) {
- case TYPE_COLOR:
- case TYPE_GRADIENT: {
- switch (color) {
- case GREEN:
- case PINK:
- case GRAY:
- mColor = color;
- break;
-
- default:
- throw new IllegalArgumentException("Invalid Color: " + color);
- }
- break;
- }
- case TYPE_SEPIA:
- case TYPE_NEGATIVE:
- case TYPE_FIFTIES: {
- mColor = -1;
- break;
- }
-
- default: {
- throw new IllegalArgumentException("Invalid type: " + type);
- }
- }
- mType = type;
- }
-
- /**
- * Get the effect type.
- *
- * @return The effect type
- */
- public int getType() {
- return mType;
- }
-
- /**
- * Get the color if effect type is TYPE_COLOR or TYPE_GRADIENT.
- *
- * @return the color as RGB 888 if type is TYPE_COLOR or TYPE_GRADIENT.
- */
- public int getColor() {
- return mColor;
- }
-}
diff --git a/media/java/android/media/videoeditor/EffectKenBurns.java b/media/java/android/media/videoeditor/EffectKenBurns.java
deleted file mode 100644
index 64be6b8..0000000
--- a/media/java/android/media/videoeditor/EffectKenBurns.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import android.graphics.Rect;
-
-/**
- * This class represents a Ken Burns effect.
- * {@hide}
- */
-public class EffectKenBurns extends Effect {
- /**
- * Instance variables
- */
- private Rect mStartRect;
- private Rect mEndRect;
-
- /**
- * Objects of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private EffectKenBurns() {
- this(null, null, null, null, 0, 0);
- }
-
- /**
- * Constructor
- *
- * @param mediaItem The media item owner
- * @param effectId The effect id
- * @param startRect The start rectangle
- * @param endRect The end rectangle
- * @param startTimeMs The start time
- * @param durationMs The duration of the Ken Burns effect in milliseconds
- */
- public EffectKenBurns(MediaItem mediaItem, String effectId, Rect startRect,
- Rect endRect, long startTimeMs, long durationMs) {
- super(mediaItem, effectId, startTimeMs, durationMs);
-
- if ( (startRect.width() <= 0) || (startRect.height() <= 0) ) {
- throw new IllegalArgumentException("Invalid Start rectangle");
- }
- if ( (endRect.width() <= 0) || (endRect.height() <= 0) ) {
- throw new IllegalArgumentException("Invalid End rectangle");
- }
-
- mStartRect = startRect;
- mEndRect = endRect;
- }
-
-
- /**
- * Get the start rectangle.
- *
- * @return The start rectangle
- */
- public Rect getStartRect() {
- return mStartRect;
- }
-
-
- /**
- * Get the end rectangle.
- *
- * @return The end rectangle
- */
- public Rect getEndRect() {
- return mEndRect;
- }
-
- /**
- * Get the KenBurn effect start and end rectangle coordinates
- * @param start The rect object to be populated with start
- * rectangle coordinates
- *
- * @param end The rect object to be populated with end
- * rectangle coordinates
- */
- void getKenBurnsSettings(Rect start, Rect end) {
- start.left = getStartRect().left;
- start.top = getStartRect().top;
- start.right = getStartRect().right;
- start.bottom = getStartRect().bottom;
- end.left = getEndRect().left;
- end.top = getEndRect().top;
- end.right = getEndRect().right;
- end.bottom = getEndRect().bottom;
- }
-}
diff --git a/media/java/android/media/videoeditor/ExtractAudioWaveformProgressListener.java b/media/java/android/media/videoeditor/ExtractAudioWaveformProgressListener.java
deleted file mode 100644
index 7ba7de3..0000000
--- a/media/java/android/media/videoeditor/ExtractAudioWaveformProgressListener.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-/**
- * This listener interface is used by
- * {@link MediaVideoItem#extractAudioWaveform(ExtractAudioWaveformProgressListener listener)}
- * or
- * {@link AudioTrack#extractAudioWaveform(ExtractAudioWaveformProgressListener listener)}
- * {@hide}
- */
-public interface ExtractAudioWaveformProgressListener {
- /**
- * This method notifies the listener of the progress status of
- * an extractAudioWaveform operation.
- * This method may be called maximum 100 times for one operation.
- *
- * @param progress The progress in %. At the beginning of the operation,
- * this value is set to 0; at the end, the value is set to 100.
- */
- public void onProgress(int progress);
-}
-
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
deleted file mode 100644
index 2d3de85..0000000
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ /dev/null
@@ -1,4034 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.nio.IntBuffer;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.Semaphore;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Matrix;
-import android.media.videoeditor.VideoEditor.ExportProgressListener;
-import android.media.videoeditor.VideoEditor.PreviewProgressListener;
-import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
-import android.util.Log;
-import android.util.Pair;
-import android.view.Surface;
-
-/**
- *This class provide Native methods to be used by MediaArtist {@hide}
- */
-class MediaArtistNativeHelper {
- private static final String TAG = "MediaArtistNativeHelper";
-
- static {
- System.loadLibrary("videoeditor_jni");
- }
-
- private static final int MAX_THUMBNAIL_PERMITTED = 8;
-
- public static final int TASK_LOADING_SETTINGS = 1;
- public static final int TASK_ENCODING = 2;
-
- /**
- * The resize paint
- */
- private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-
- private final VideoEditor mVideoEditor;
- /*
- * Semaphore to control preview calls
- */
- private final Semaphore mLock;
-
- private EditSettings mStoryBoardSettings;
-
- private String mOutputFilename;
-
- private PreviewClipProperties mClipProperties = null;
-
- private EditSettings mPreviewEditSettings;
-
- private AudioSettings mAudioSettings = null;
-
- private AudioTrack mAudioTrack = null;
-
- private boolean mInvalidatePreviewArray = true;
-
- private boolean mRegenerateAudio = true;
-
- private String mExportFilename = null;
- private int mExportVideoCodec = 0;
- private int mExportAudioCodec = 0;
- private int mProgressToApp;
-
- private String mRenderPreviewOverlayFile;
- private int mRenderPreviewRenderingMode;
-
- private boolean mIsFirstProgress;
-
- private static final String AUDIO_TRACK_PCM_FILE = "AudioPcm.pcm";
-
- // Processing indication
- public static final int PROCESSING_NONE = 0;
- public static final int PROCESSING_AUDIO_PCM = 1;
- public static final int PROCESSING_TRANSITION = 2;
- public static final int PROCESSING_KENBURNS = 3;
- public static final int PROCESSING_INTERMEDIATE1 = 11;
- public static final int PROCESSING_INTERMEDIATE2 = 12;
- public static final int PROCESSING_INTERMEDIATE3 = 13;
- public static final int PROCESSING_EXPORT = 20;
-
- private int mProcessingState;
- private Object mProcessingObject;
- private PreviewProgressListener mPreviewProgressListener;
- private ExportProgressListener mExportProgressListener;
- private ExtractAudioWaveformProgressListener mExtractAudioWaveformProgressListener;
- private MediaProcessingProgressListener mMediaProcessingProgressListener;
- private final String mProjectPath;
-
- private long mPreviewProgress;
-
- private String mAudioTrackPCMFilePath;
-
- private int mTotalClips = 0;
-
- private boolean mErrorFlagSet = false;
-
- @SuppressWarnings("unused")
- private long mManualEditContext;
-
- /* Listeners */
-
- /**
- * Interface definition for a listener to be invoked when there is an update
- * in a running task.
- */
- public interface OnProgressUpdateListener {
- /**
- * Called when there is an update.
- *
- * @param taskId id of the task reporting an update.
- * @param progress progress of the task [0..100].
- * @see BasicEdit#TASK_ENCODING
- */
- public void OnProgressUpdate(int taskId, int progress);
- }
-
- /** Defines the version. */
- public final class Version {
-
- /** Major version number */
- public int major;
-
- /** Minor version number */
- public int minor;
-
- /** Revision number */
- public int revision;
-
- /** VIDEOEDITOR major version number */
- private static final int VIDEOEDITOR_MAJOR_VERSION = 0;
-
- /** VIDEOEDITOR minor version number */
- private static final int VIDEOEDITOR_MINOR_VERSION = 0;
-
- /** VIDEOEDITOR revision number */
- private static final int VIDEOEDITOR_REVISION_VERSION = 1;
-
- /** Method which returns the current VIDEOEDITOR version */
- public Version getVersion() {
- Version version = new Version();
-
- version.major = Version.VIDEOEDITOR_MAJOR_VERSION;
- version.minor = Version.VIDEOEDITOR_MINOR_VERSION;
- version.revision = Version.VIDEOEDITOR_REVISION_VERSION;
-
- return version;
- }
- }
-
- /**
- * Defines output audio formats.
- */
- public final class AudioFormat {
- /** No audio present in output clip. Used to generate video only clip */
- public static final int NO_AUDIO = 0;
-
- /** AMR Narrow Band. */
- public static final int AMR_NB = 1;
-
- /** Advanced Audio Coding (AAC). */
- public static final int AAC = 2;
-
- /** Advanced Audio Codec Plus (HE-AAC v1). */
- public static final int AAC_PLUS = 3;
-
- /** Advanced Audio Codec Plus (HE-AAC v2). */
- public static final int ENHANCED_AAC_PLUS = 4;
-
- /** MPEG layer 3 (MP3). */
- public static final int MP3 = 5;
-
- /** Enhanced Variable RateCodec (EVRC). */
- public static final int EVRC = 6;
-
- /** PCM (PCM). */
- public static final int PCM = 7;
-
- /** No transcoding. Output audio format is same as input audio format */
- public static final int NULL_AUDIO = 254;
-
- /** Unsupported audio format. */
- public static final int UNSUPPORTED_AUDIO = 255;
- }
-
- /**
- * Defines audio sampling frequencies.
- */
- public final class AudioSamplingFrequency {
- /**
- * Default sampling frequency. Uses the default frequency for a specific
- * audio format. For AAC the only supported (and thus default) sampling
- * frequency is 16 kHz. For this audio format the sampling frequency in
- * the OutputParams.
- **/
- public static final int FREQ_DEFAULT = 0;
-
- /** Audio sampling frequency of 8000 Hz. */
- public static final int FREQ_8000 = 8000;
-
- /** Audio sampling frequency of 11025 Hz. */
- public static final int FREQ_11025 = 11025;
-
- /** Audio sampling frequency of 12000 Hz. */
- public static final int FREQ_12000 = 12000;
-
- /** Audio sampling frequency of 16000 Hz. */
- public static final int FREQ_16000 = 16000;
-
- /** Audio sampling frequency of 22050 Hz. */
- public static final int FREQ_22050 = 22050;
-
- /** Audio sampling frequency of 24000 Hz. */
- public static final int FREQ_24000 = 24000;
-
- /** Audio sampling frequency of 32000 Hz. */
- public static final int FREQ_32000 = 32000;
-
- /** Audio sampling frequency of 44100 Hz. */
- public static final int FREQ_44100 = 44100;
-
- /** Audio sampling frequency of 48000 Hz. Not available for output file. */
- public static final int FREQ_48000 = 48000;
- }
-
- /**
- * Defines the supported fixed audio and video bitrates. These values are
- * for output audio video only.
- */
- public final class Bitrate {
- /** Variable bitrate. Means no bitrate regulation */
- public static final int VARIABLE = -1;
-
- /** An undefined bitrate. */
- public static final int UNDEFINED = 0;
-
- /** A bitrate of 9.2 kbits/s. */
- public static final int BR_9_2_KBPS = 9200;
-
- /** A bitrate of 12.2 kbits/s. */
- public static final int BR_12_2_KBPS = 12200;
-
- /** A bitrate of 16 kbits/s. */
- public static final int BR_16_KBPS = 16000;
-
- /** A bitrate of 24 kbits/s. */
- public static final int BR_24_KBPS = 24000;
-
- /** A bitrate of 32 kbits/s. */
- public static final int BR_32_KBPS = 32000;
-
- /** A bitrate of 48 kbits/s. */
- public static final int BR_48_KBPS = 48000;
-
- /** A bitrate of 64 kbits/s. */
- public static final int BR_64_KBPS = 64000;
-
- /** A bitrate of 96 kbits/s. */
- public static final int BR_96_KBPS = 96000;
-
- /** A bitrate of 128 kbits/s. */
- public static final int BR_128_KBPS = 128000;
-
- /** A bitrate of 192 kbits/s. */
- public static final int BR_192_KBPS = 192000;
-
- /** A bitrate of 256 kbits/s. */
- public static final int BR_256_KBPS = 256000;
-
- /** A bitrate of 288 kbits/s. */
- public static final int BR_288_KBPS = 288000;
-
- /** A bitrate of 384 kbits/s. */
- public static final int BR_384_KBPS = 384000;
-
- /** A bitrate of 512 kbits/s. */
- public static final int BR_512_KBPS = 512000;
-
- /** A bitrate of 800 kbits/s. */
- public static final int BR_800_KBPS = 800000;
-
- /** A bitrate of 2 Mbits/s. */
- public static final int BR_2_MBPS = 2000000;
-
- /** A bitrate of 5 Mbits/s. */
- public static final int BR_5_MBPS = 5000000;
-
- /** A bitrate of 8 Mbits/s. */
- public static final int BR_8_MBPS = 8000000;
- }
-
- /**
- * Defines all supported file types.
- */
- public final class FileType {
- /** 3GPP file type. */
- public static final int THREE_GPP = 0;
-
- /** MP4 file type. */
- public static final int MP4 = 1;
-
- /** AMR file type. */
- public static final int AMR = 2;
-
- /** MP3 audio file type. */
- public static final int MP3 = 3;
-
- /** PCM audio file type. */
- public static final int PCM = 4;
-
- /** JPEG image file type. */
- public static final int JPG = 5;
-
- /** GIF image file type. */
- public static final int GIF = 7;
-
- /** PNG image file type. */
- public static final int PNG = 8;
-
- /** M4V file type. */
- public static final int M4V = 10;
-
- /** Unsupported file type. */
- public static final int UNSUPPORTED = 255;
- }
-
- /**
- * Defines rendering types. Rendering can only be applied to files
- * containing video streams.
- **/
- public final class MediaRendering {
- /**
- * Resize to fit the output video with changing the aspect ratio if
- * needed.
- */
- public static final int RESIZING = 0;
-
- /**
- * Crop the input video to fit it with the output video resolution.
- **/
- public static final int CROPPING = 1;
-
- /**
- * Resize to fit the output video resolution but maintain the aspect
- * ratio. This framing type adds black borders if needed.
- */
- public static final int BLACK_BORDERS = 2;
- }
-
- /**
- * Defines the results.
- */
- public final class Result {
- /** No error. result OK */
- public static final int NO_ERROR = 0;
-
- /** File not found */
- public static final int ERR_FILE_NOT_FOUND = 1;
-
- /**
- * In case of UTF8 conversion, the size of the converted path will be
- * more than the corresponding allocated buffer.
- */
- public static final int ERR_BUFFER_OUT_TOO_SMALL = 2;
-
- /** Invalid file type. */
- public static final int ERR_INVALID_FILE_TYPE = 3;
-
- /** Invalid effect kind. */
- public static final int ERR_INVALID_EFFECT_KIND = 4;
-
- /** Invalid video effect. */
- public static final int ERR_INVALID_VIDEO_EFFECT_TYPE = 5;
-
- /** Invalid audio effect. */
- public static final int ERR_INVALID_AUDIO_EFFECT_TYPE = 6;
-
- /** Invalid video transition. */
- public static final int ERR_INVALID_VIDEO_TRANSITION_TYPE = 7;
-
- /** Invalid audio transition. */
- public static final int ERR_INVALID_AUDIO_TRANSITION_TYPE = 8;
-
- /** Invalid encoding frame rate. */
- public static final int ERR_INVALID_VIDEO_ENCODING_FRAME_RATE = 9;
-
- /** External effect is called but this function is not set. */
- public static final int ERR_EXTERNAL_EFFECT_NULL = 10;
-
- /** External transition is called but this function is not set. */
- public static final int ERR_EXTERNAL_TRANSITION_NULL = 11;
-
- /** Begin time cut is larger than the video clip duration. */
- public static final int ERR_BEGIN_CUT_LARGER_THAN_DURATION = 12;
-
- /** Begin cut time is larger or equal than end cut. */
- public static final int ERR_BEGIN_CUT_LARGER_THAN_END_CUT = 13;
-
- /** Two consecutive transitions are overlapping on one clip. */
- public static final int ERR_OVERLAPPING_TRANSITIONS = 14;
-
- /** Internal error, type size mismatch. */
- public static final int ERR_ANALYSIS_DATA_SIZE_TOO_SMALL = 15;
-
- /** An input 3GPP file is invalid/corrupted. */
- public static final int ERR_INVALID_3GPP_FILE = 16;
-
- /** A file contains an unsupported video format. */
- public static final int ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT = 17;
-
- /** A file contains an unsupported audio format. */
- public static final int ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT = 18;
-
- /** A file format is not supported. */
- public static final int ERR_AMR_EDITING_UNSUPPORTED = 19;
-
- /** An input clip has an unexpectedly large Video AU. */
- public static final int ERR_INPUT_VIDEO_AU_TOO_LARGE = 20;
-
- /** An input clip has an unexpectedly large Audio AU. */
- public static final int ERR_INPUT_AUDIO_AU_TOO_LARGE = 21;
-
- /** An input clip has a corrupted Audio AU. */
- public static final int ERR_INPUT_AUDIO_CORRUPTED_AU = 22;
-
- /** The video encoder encountered an Access Unit error. */
- public static final int ERR_ENCODER_ACCES_UNIT_ERROR = 23;
-
- /** Unsupported video format for Video Editing. */
- public static final int ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT = 24;
-
- /** Unsupported H263 profile for Video Editing. */
- public static final int ERR_EDITING_UNSUPPORTED_H263_PROFILE = 25;
-
- /** Unsupported MPEG-4 profile for Video Editing. */
- public static final int ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE = 26;
-
- /** Unsupported MPEG-4 RVLC tool for Video Editing. */
- public static final int ERR_EDITING_UNSUPPORTED_MPEG4_RVLC = 27;
-
- /** Unsupported audio format for Video Editing. */
- public static final int ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT = 28;
-
- /** File contains no supported stream. */
- public static final int ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE = 29;
-
- /** File contains no video stream or an unsupported video stream. */
- public static final int ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE = 30;
-
- /** Internal error, clip analysis version mismatch. */
- public static final int ERR_INVALID_CLIP_ANALYSIS_VERSION = 31;
-
- /**
- * At least one of the clip analysis has been generated on another
- * platform (WIN32, ARM, etc.).
- */
- public static final int ERR_INVALID_CLIP_ANALYSIS_PLATFORM = 32;
-
- /** Clips don't have the same video format (H263 or MPEG4). */
- public static final int ERR_INCOMPATIBLE_VIDEO_FORMAT = 33;
-
- /** Clips don't have the same frame size. */
- public static final int ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE = 34;
-
- /** Clips don't have the same MPEG-4 time scale. */
- public static final int ERR_INCOMPATIBLE_VIDEO_TIME_SCALE = 35;
-
- /** Clips don't have the same use of MPEG-4 data partitioning. */
- public static final int ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING = 36;
-
- /** MP3 clips can't be assembled. */
- public static final int ERR_UNSUPPORTED_MP3_ASSEMBLY = 37;
-
- /**
- * The input 3GPP file does not contain any supported audio or video
- * track.
- */
- public static final int ERR_NO_SUPPORTED_STREAM_IN_FILE = 38;
-
- /**
- * The Volume of the added audio track (AddVolume) must be strictly
- * superior than zero.
- */
- public static final int ERR_ADDVOLUME_EQUALS_ZERO = 39;
-
- /**
- * The time at which an audio track is added can't be higher than the
- * input video track duration..
- */
- public static final int ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION = 40;
-
- /** The audio track file format setting is undefined. */
- public static final int ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT = 41;
-
- /** The added audio track stream has an unsupported format. */
- public static final int ERR_UNSUPPORTED_ADDED_AUDIO_STREAM = 42;
-
- /** The audio mixing feature doesn't support the audio track type. */
- public static final int ERR_AUDIO_MIXING_UNSUPPORTED = 43;
-
- /** The audio mixing feature doesn't support MP3 audio tracks. */
- public static final int ERR_AUDIO_MIXING_MP3_UNSUPPORTED = 44;
-
- /**
- * An added audio track limits the available features: uiAddCts must be
- * 0 and bRemoveOriginal must be true.
- */
- public static final int ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK = 45;
-
- /**
- * An added audio track limits the available features: uiAddCts must be
- * 0 and bRemoveOriginal must be true.
- */
- public static final int ERR_FEATURE_UNSUPPORTED_WITH_AAC = 46;
-
- /** Input audio track is not of a type that can be mixed with output. */
- public static final int ERR_AUDIO_CANNOT_BE_MIXED = 47;
-
- /** Input audio track is not AMR-NB, so it can't be mixed with output. */
- public static final int ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED = 48;
-
- /**
- * An added EVRC audio track limit the available features: uiAddCts must
- * be 0 and bRemoveOriginal must be true.
- */
- public static final int ERR_FEATURE_UNSUPPORTED_WITH_EVRC = 49;
-
- /** H263 profiles other than 0 are not supported. */
- public static final int ERR_H263_PROFILE_NOT_SUPPORTED = 51;
-
- /** File contains no video stream or an unsupported video stream. */
- public static final int ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE = 52;
-
- /** Transcoding of the input file(s) is necessary. */
- public static final int WAR_TRANSCODING_NECESSARY = 53;
-
- /**
- * The size of the output file will exceed the maximum configured value.
- */
- public static final int WAR_MAX_OUTPUT_SIZE_EXCEEDED = 54;
-
- /** The time scale is too big. */
- public static final int WAR_TIMESCALE_TOO_BIG = 55;
-
- /** The year is out of range */
- public static final int ERR_CLOCK_BAD_REF_YEAR = 56;
-
- /** The directory could not be opened */
- public static final int ERR_DIR_OPEN_FAILED = 57;
-
- /** The directory could not be read */
- public static final int ERR_DIR_READ_FAILED = 58;
-
- /** There are no more entries in the current directory */
- public static final int ERR_DIR_NO_MORE_ENTRY = 59;
-
- /** The input parameter/s has error */
- public static final int ERR_PARAMETER = 60;
-
- /** There is a state machine error */
- public static final int ERR_STATE = 61;
-
- /** Memory allocation failed */
- public static final int ERR_ALLOC = 62;
-
- /** Context is invalid */
- public static final int ERR_BAD_CONTEXT = 63;
-
- /** Context creation failed */
- public static final int ERR_CONTEXT_FAILED = 64;
-
- /** Invalid stream ID */
- public static final int ERR_BAD_STREAM_ID = 65;
-
- /** Invalid option ID */
- public static final int ERR_BAD_OPTION_ID = 66;
-
- /** The option is write only */
- public static final int ERR_WRITE_ONLY = 67;
-
- /** The option is read only */
- public static final int ERR_READ_ONLY = 68;
-
- /** The feature is not implemented in this version */
- public static final int ERR_NOT_IMPLEMENTED = 69;
-
- /** The media type is not supported */
- public static final int ERR_UNSUPPORTED_MEDIA_TYPE = 70;
-
- /** No data to be encoded */
- public static final int WAR_NO_DATA_YET = 71;
-
- /** No data to be decoded */
- public static final int WAR_NO_MORE_STREAM = 72;
-
- /** Time stamp is invalid */
- public static final int WAR_INVALID_TIME = 73;
-
- /** No more data to be decoded */
- public static final int WAR_NO_MORE_AU = 74;
-
- /** Semaphore timed out */
- public static final int WAR_TIME_OUT = 75;
-
- /** Memory buffer is full */
- public static final int WAR_BUFFER_FULL = 76;
-
- /** Server has asked for redirection */
- public static final int WAR_REDIRECT = 77;
-
- /** Too many streams in input */
- public static final int WAR_TOO_MUCH_STREAMS = 78;
-
- /** The file cannot be opened/ written into as it is locked */
- public static final int ERR_FILE_LOCKED = 79;
-
- /** The file access mode is invalid */
- public static final int ERR_FILE_BAD_MODE_ACCESS = 80;
-
- /** The file pointer points to an invalid location */
- public static final int ERR_FILE_INVALID_POSITION = 81;
-
- /** Invalid string */
- public static final int ERR_STR_BAD_STRING = 94;
-
- /** The input string cannot be converted */
- public static final int ERR_STR_CONV_FAILED = 95;
-
- /** The string size is too large */
- public static final int ERR_STR_OVERFLOW = 96;
-
- /** Bad string arguments */
- public static final int ERR_STR_BAD_ARGS = 97;
-
- /** The string value is larger than maximum size allowed */
- public static final int WAR_STR_OVERFLOW = 98;
-
- /** The string value is not present in this comparison operation */
- public static final int WAR_STR_NOT_FOUND = 99;
-
- /** The thread is not started */
- public static final int ERR_THREAD_NOT_STARTED = 100;
-
- /** Trancoding done warning */
- public static final int WAR_TRANSCODING_DONE = 101;
-
- /** Unsupported mediatype */
- public static final int WAR_MEDIATYPE_NOT_SUPPORTED = 102;
-
- /** Input file contains invalid/unsupported streams */
- public static final int ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM = 103;
-
- /** Invalid input file */
- public static final int ERR_INVALID_INPUT_FILE = 104;
-
- /** Invalid output video format */
- public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT = 105;
-
- /** Invalid output video frame size */
- public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE = 106;
-
- /** Invalid output video frame rate */
- public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE = 107;
-
- /** Invalid output audio format */
- public static final int ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT = 108;
-
- /** Invalid video frame size for H.263 */
- public static final int ERR_INVALID_VIDEO_FRAME_SIZE_FOR_H263 = 109;
-
- /** Invalid video frame rate for H.263 */
- public static final int ERR_INVALID_VIDEO_FRAME_RATE_FOR_H263 = 110;
-
- /** invalid playback duration */
- public static final int ERR_DURATION_IS_NULL = 111;
-
- /** Invalid H.263 profile in file */
- public static final int ERR_H263_FORBIDDEN_IN_MP4_FILE = 112;
-
- /** Invalid AAC sampling frequency */
- public static final int ERR_INVALID_AAC_SAMPLING_FREQUENCY = 113;
-
- /** Audio conversion failure */
- public static final int ERR_AUDIO_CONVERSION_FAILED = 114;
-
- /** Invalid trim start and end times */
- public static final int ERR_BEGIN_CUT_EQUALS_END_CUT = 115;
-
- /** End time smaller than start time for trim */
- public static final int ERR_END_CUT_SMALLER_THAN_BEGIN_CUT = 116;
-
- /** Output file size is small */
- public static final int ERR_MAXFILESIZE_TOO_SMALL = 117;
-
- /** Output video bitrate is too low */
- public static final int ERR_VIDEOBITRATE_TOO_LOW = 118;
-
- /** Output audio bitrate is too low */
- public static final int ERR_AUDIOBITRATE_TOO_LOW = 119;
-
- /** Output video bitrate is too high */
- public static final int ERR_VIDEOBITRATE_TOO_HIGH = 120;
-
- /** Output audio bitrate is too high */
- public static final int ERR_AUDIOBITRATE_TOO_HIGH = 121;
-
- /** Output file size is too small */
- public static final int ERR_OUTPUT_FILE_SIZE_TOO_SMALL = 122;
-
- /** Unknown stream type */
- public static final int ERR_READER_UNKNOWN_STREAM_TYPE = 123;
-
- /** Invalid metadata in input stream */
- public static final int WAR_READER_NO_METADATA = 124;
-
- /** Invalid file reader info warning */
- public static final int WAR_READER_INFORMATION_NOT_PRESENT = 125;
-
- /** Warning to indicate the the writer is being stopped */
- public static final int WAR_WRITER_STOP_REQ = 131;
-
- /** Video decoder failed to provide frame for transcoding */
- public static final int WAR_VIDEORENDERER_NO_NEW_FRAME = 132;
-
- /** Video deblocking filter is not implemented */
- public static final int WAR_DEBLOCKING_FILTER_NOT_IMPLEMENTED = 133;
-
- /** H.263 decoder profile not supported */
- public static final int ERR_DECODER_H263_PROFILE_NOT_SUPPORTED = 134;
-
- /** The input file contains unsupported H.263 profile */
- public static final int ERR_DECODER_H263_NOT_BASELINE = 135;
-
- /** There is no more space to store the output file */
- public static final int ERR_NOMORE_SPACE_FOR_FILE = 136;
-
- /** Internal error. */
- public static final int ERR_INTERNAL = 255;
- }
-
- /**
- * Defines output video formats.
- */
- public final class VideoFormat {
- /** No video present in output clip. Used to generate audio only clip */
- public static final int NO_VIDEO = 0;
-
- /** H263 video format. */
- public static final int H263 = 1;
-
- /** H264 video */
- public static final int H264 = 2;
-
- /** MPEG4 video format. */
- public static final int MPEG4 = 3;
-
- /** No transcoding. Output video format is same as input video format */
- public static final int NULL_VIDEO = 254;
-
- /** Unsupported video format. */
- public static final int UNSUPPORTED = 255;
- }
-
- /** Defines video frame sizes. */
- public final class VideoFrameSize {
-
- public static final int SIZE_UNDEFINED = -1;
-
- /** SQCIF 128 x 96 pixels. */
- public static final int SQCIF = 0;
-
- /** QQVGA 160 x 120 pixels. */
- public static final int QQVGA = 1;
-
- /** QCIF 176 x 144 pixels. */
- public static final int QCIF = 2;
-
- /** QVGA 320 x 240 pixels. */
- public static final int QVGA = 3;
-
- /** CIF 352 x 288 pixels. */
- public static final int CIF = 4;
-
- /** VGA 640 x 480 pixels. */
- public static final int VGA = 5;
-
- /** WVGA 800 X 480 pixels */
- public static final int WVGA = 6;
-
- /** NTSC 720 X 480 pixels */
- public static final int NTSC = 7;
-
- /** 640 x 360 */
- public static final int nHD = 8;
-
- /** 854 x 480 */
- public static final int WVGA16x9 = 9;
-
- /** 720p 1280 X 720 */
- public static final int V720p = 10;
-
- /** W720p 1080 x 720 */
- public static final int W720p = 11;
-
- /** S720p 960 x 720 */
- public static final int S720p = 12;
-
- /** 1080p 1920 x 1080 */
- public static final int V1080p = 13;
- }
-
- /**
- * Defines output video frame rates.
- */
- public final class VideoFrameRate {
- /** Frame rate of 5 frames per second. */
- public static final int FR_5_FPS = 0;
-
- /** Frame rate of 7.5 frames per second. */
- public static final int FR_7_5_FPS = 1;
-
- /** Frame rate of 10 frames per second. */
- public static final int FR_10_FPS = 2;
-
- /** Frame rate of 12.5 frames per second. */
- public static final int FR_12_5_FPS = 3;
-
- /** Frame rate of 15 frames per second. */
- public static final int FR_15_FPS = 4;
-
- /** Frame rate of 20 frames per second. */
- public static final int FR_20_FPS = 5;
-
- /** Frame rate of 25 frames per second. */
- public static final int FR_25_FPS = 6;
-
- /** Frame rate of 30 frames per second. */
- public static final int FR_30_FPS = 7;
- }
-
- /**
- * Defines Video Effect Types.
- */
- public static class VideoEffect {
-
- public static final int NONE = 0;
-
- public static final int FADE_FROM_BLACK = 8;
-
- public static final int FADE_TO_BLACK = 16;
-
- public static final int EXTERNAL = 256;
-
- public static final int BLACK_AND_WHITE = 257;
-
- public static final int PINK = 258;
-
- public static final int GREEN = 259;
-
- public static final int SEPIA = 260;
-
- public static final int NEGATIVE = 261;
-
- public static final int FRAMING = 262;
-
- public static final int TEXT = 263;
-
- public static final int ZOOM_IN = 264;
-
- public static final int ZOOM_OUT = 265;
-
- public static final int FIFTIES = 266;
-
- public static final int COLORRGB16 = 267;
-
- public static final int GRADIENT = 268;
- }
-
- /**
- * Defines the video transitions.
- */
- public static class VideoTransition {
- /** No transition */
- public static final int NONE = 0;
-
- /** Cross fade transition */
- public static final int CROSS_FADE = 1;
-
- /** External transition. Currently not available. */
- public static final int EXTERNAL = 256;
-
- /** AlphaMagic transition. */
- public static final int ALPHA_MAGIC = 257;
-
- /** Slide transition. */
- public static final int SLIDE_TRANSITION = 258;
-
- /** Fade to black transition. */
- public static final int FADE_BLACK = 259;
- }
-
- /**
- * Defines settings for the AlphaMagic transition
- */
- public static class AlphaMagicSettings {
- /** Name of the alpha file (JPEG file). */
- public String file;
-
- /** Blending percentage [0..100] 0 = no blending. */
- public int blendingPercent;
-
- /** Invert the default rotation direction of the AlphaMagic effect. */
- public boolean invertRotation;
-
- public int rgbWidth;
- public int rgbHeight;
- }
-
- /** Defines the direction of the Slide transition. */
- public static final class SlideDirection {
-
- /** Right out left in. */
- public static final int RIGHT_OUT_LEFT_IN = 0;
-
- /** Left out right in. */
- public static final int LEFT_OUT_RIGTH_IN = 1;
-
- /** Top out bottom in. */
- public static final int TOP_OUT_BOTTOM_IN = 2;
-
- /** Bottom out top in */
- public static final int BOTTOM_OUT_TOP_IN = 3;
- }
-
- /** Defines the Slide transition settings. */
- public static class SlideTransitionSettings {
- /**
- * Direction of the slide transition. See {@link SlideDirection
- * SlideDirection} for valid values.
- */
- public int direction;
- }
-
- /**
- * Defines the settings of a single clip.
- */
- public static class ClipSettings {
-
- /**
- * The path to the clip file.
- * <p>
- * File format of the clip, it can be:
- * <ul>
- * <li>3GP file containing MPEG4/H263/H264 video and AAC/AMR audio
- * <li>JPG file
- * </ul>
- */
-
- public String clipPath;
-
- /**
- * The path of the decoded file. This is used only for image files.
- */
- public String clipDecodedPath;
-
- /**
- * The path of the Original file. This is used only for image files.
- */
- public String clipOriginalPath;
-
- /**
- * File type of the clip. See {@link FileType FileType} for valid
- * values.
- */
- public int fileType;
-
- /** Begin of the cut in the clip in milliseconds. */
- public int beginCutTime;
-
- /**
- * End of the cut in the clip in milliseconds. Set both
- * <code>beginCutTime</code> and <code>endCutTime</code> to
- * <code>0</code> to get the full length of the clip without a cut. In
- * case of JPG clip, this is the duration of the JPEG file.
- */
- public int endCutTime;
-
- /**
- * Begin of the cut in the clip in percentage of the file duration.
- */
- public int beginCutPercent;
-
- /**
- * End of the cut in the clip in percentage of the file duration. Set
- * both <code>beginCutPercent</code> and <code>endCutPercent</code> to
- * <code>0</code> to get the full length of the clip without a cut.
- */
- public int endCutPercent;
-
- /** Enable panning and zooming. */
- public boolean panZoomEnabled;
-
- /** Zoom percentage at start of clip. 0 = no zoom, 100 = full zoom */
- public int panZoomPercentStart;
-
- /** Top left X coordinate at start of clip. */
- public int panZoomTopLeftXStart;
-
- /** Top left Y coordinate at start of clip. */
- public int panZoomTopLeftYStart;
-
- /** Zoom percentage at start of clip. 0 = no zoom, 100 = full zoom */
- public int panZoomPercentEnd;
-
- /** Top left X coordinate at end of clip. */
- public int panZoomTopLeftXEnd;
-
- /** Top left Y coordinate at end of clip. */
- public int panZoomTopLeftYEnd;
-
- /**
- * Set The media rendering. See {@link MediaRendering MediaRendering}
- * for valid values.
- */
- public int mediaRendering;
-
- /**
- * RGB width and Height
- */
- public int rgbWidth;
- public int rgbHeight;
- /**
- * Video rotation degree.
- */
- public int rotationDegree;
- }
-
- /**
- * Defines settings for a transition.
- */
- public static class TransitionSettings {
-
- /** Duration of the transition in msec. */
- public int duration;
-
- /**
- * Transition type for video. See {@link VideoTransition
- * VideoTransition} for valid values.
- */
- public int videoTransitionType;
-
- /**
- * Transition type for audio. See {@link AudioTransition
- * AudioTransition} for valid values.
- */
- public int audioTransitionType;
-
- /**
- * Transition behaviour. See {@link TransitionBehaviour
- * TransitionBehaviour} for valid values.
- */
- public int transitionBehaviour;
-
- /**
- * Settings for AlphaMagic transition. Only needs to be set if
- * <code>videoTransitionType</code> is set to
- * <code>VideoTransition.ALPHA_MAGIC</code>. See
- * {@link AlphaMagicSettings AlphaMagicSettings}.
- */
- public AlphaMagicSettings alphaSettings;
-
- /**
- * Settings for the Slide transition. See
- * {@link SlideTransitionSettings SlideTransitionSettings}.
- */
- public SlideTransitionSettings slideSettings;
- }
-
- public static final class AudioTransition {
- /** No audio transition. */
- public static final int NONE = 0;
-
- /** Cross-fade audio transition. */
- public static final int CROSS_FADE = 1;
- }
-
- /**
- * Defines transition behaviors.
- */
- public static final class TransitionBehaviour {
-
- /** The transition uses an increasing speed. */
- public static final int SPEED_UP = 0;
-
- /** The transition uses a linear (constant) speed. */
- public static final int LINEAR = 1;
-
- /** The transition uses a decreasing speed. */
- public static final int SPEED_DOWN = 2;
-
- /**
- * The transition uses a constant speed, but slows down in the middle
- * section.
- */
- public static final int SLOW_MIDDLE = 3;
-
- /**
- * The transition uses a constant speed, but increases speed in the
- * middle section.
- */
- public static final int FAST_MIDDLE = 4;
- }
-
- /**
- * Defines settings for the background music.
- */
- public static class BackgroundMusicSettings {
-
- /** Background music file. */
- public String file;
-
- /** File type. See {@link FileType FileType} for valid values. */
- public int fileType;
-
- /**
- * Insertion time in milliseconds, in the output video where the
- * background music must be inserted.
- */
- public long insertionTime;
-
- /**
- * Volume, as a percentage of the background music track, to use. If
- * this field is set to 100, the background music will replace the audio
- * from the video input file(s).
- */
- public int volumePercent;
-
- /**
- * Start time in milliseconds in the background muisc file from where
- * the background music should loop. Set both <code>beginLoop</code> and
- * <code>endLoop</code> to <code>0</code> to disable looping.
- */
- public long beginLoop;
-
- /**
- * End time in milliseconds in the background music file to where the
- * background music should loop. Set both <code>beginLoop</code> and
- * <code>endLoop</code> to <code>0</code> to disable looping.
- */
- public long endLoop;
-
- public boolean enableDucking;
-
- public int duckingThreshold;
-
- public int lowVolume;
-
- public boolean isLooping;
- }
-
- /** Defines settings for an effect. */
- public static class AudioEffect {
- /** No audio effect. */
- public static final int NONE = 0;
-
- /** Fade-in effect. */
- public static final int FADE_IN = 8;
-
- /** Fade-out effect. */
- public static final int FADE_OUT = 16;
- }
-
- /** Defines the effect settings. */
- public static class EffectSettings {
-
- /** Start time of the effect in milliseconds. */
- public int startTime;
-
- /** Duration of the effect in milliseconds. */
- public int duration;
-
- /**
- * Video effect type. See {@link VideoEffect VideoEffect} for valid
- * values.
- */
- public int videoEffectType;
-
- /**
- * Audio effect type. See {@link AudioEffect AudioEffect} for valid
- * values.
- */
- public int audioEffectType;
-
- /**
- * Start time of the effect in percents of the duration of the clip. A
- * value of 0 percent means start time is from the beginning of the
- * clip.
- */
- public int startPercent;
-
- /**
- * Duration of the effect in percents of the duration of the clip.
- */
- public int durationPercent;
-
- /**
- * Framing file.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
- * this field is ignored.
- */
- public String framingFile;
-
- /**
- * Framing buffer.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
- * this field is ignored.
- */
- public int[] framingBuffer;
-
- /**
- * Bitmap type Can be from RGB_565 (4), ARGB_4444 (5), ARGB_8888 (6);
- **/
-
- public int bitmapType;
-
- public int width;
-
- public int height;
-
- /**
- * Top left x coordinate. This coordinate is used to set the x
- * coordinate of the picture in the framing file when the framing file
- * is selected. The x coordinate is also used to set the location of the
- * text in the text effect.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING} or
- * {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this field is
- * ignored.
- */
- public int topLeftX;
-
- /**
- * Top left y coordinate. This coordinate is used to set the y
- * coordinate of the picture in the framing file when the framing file
- * is selected. The y coordinate is also used to set the location of the
- * text in the text effect.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING} or
- * {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this field is
- * ignored.
- */
- public int topLeftY;
-
- /**
- * Should the frame be resized or not. If this field is set to
- * <link>true</code> then the frame size is matched with the output
- * video size.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
- * this field is ignored.
- */
- public boolean framingResize;
-
- /**
- * Size to which the framing buffer needs to be resized to
- * This is valid only if framingResize is true
- */
- public int framingScaledSize;
- /**
- * Text to insert in the video.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this
- * field is ignored.
- */
- public String text;
-
- /**
- * Text attributes for the text to insert in the video.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this
- * field is ignored. For more details about this field see the
- * integration guide.
- */
- public String textRenderingData;
-
- /** Width of the text buffer in pixels. */
- public int textBufferWidth;
-
- /** Height of the text buffer in pixels. */
- public int textBufferHeight;
-
- /**
- * Processing rate for the fifties effect. A high value (e.g. 30)
- * results in high effect strength.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#FIFTIES VideoEffect.FIFTIES}. Otherwise
- * this field is ignored.
- */
- public int fiftiesFrameRate;
-
- /**
- * RGB 16 color of the RGB16 and gradient color effect.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#COLORRGB16 VideoEffect.COLORRGB16} or
- * {@link VideoEffect#GRADIENT VideoEffect.GRADIENT}. Otherwise this
- * field is ignored.
- */
- public int rgb16InputColor;
-
- /**
- * Start alpha blending percentage.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
- * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
- * is ignored.
- */
- public int alphaBlendingStartPercent;
-
- /**
- * Middle alpha blending percentage.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
- * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
- * is ignored.
- */
- public int alphaBlendingMiddlePercent;
-
- /**
- * End alpha blending percentage.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
- * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
- * is ignored.
- */
- public int alphaBlendingEndPercent;
-
- /**
- * Duration, in percentage of effect duration of the fade-in phase.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
- * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
- * is ignored.
- */
- public int alphaBlendingFadeInTimePercent;
-
- /**
- * Duration, in percentage of effect duration of the fade-out phase.
- * <p>
- * This field is only used when the field <code>videoEffectType</code>
- * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
- * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
- * is ignored.
- */
- public int alphaBlendingFadeOutTimePercent;
- }
-
- /** Defines the clip properties for preview */
- public static class PreviewClips {
-
- /**
- * The path to the clip file.
- * <p>
- * File format of the clip, it can be:
- * <ul>
- * <li>3GP file containing MPEG4/H263 video and AAC/AMR audio
- * <li>JPG file
- * </ul>
- */
-
- public String clipPath;
-
- /**
- * File type of the clip. See {@link FileType FileType} for valid
- * values.
- */
- public int fileType;
-
- /** Begin of the cut in the clip in milliseconds. */
- public long beginPlayTime;
-
- public long endPlayTime;
-
- /**
- * Set The media rendering. See {@link MediaRendering MediaRendering}
- * for valid values.
- */
- public int mediaRendering;
-
- }
-
- /** Defines the audio settings. */
- public static class AudioSettings {
-
- String pFile;
-
- /** < PCM file path */
- String Id;
-
- boolean bRemoveOriginal;
-
- /** < If true, the original audio track is not taken into account */
- int channels;
-
- /** < Number of channels (1=mono, 2=stereo) of BGM clip */
- int Fs;
-
- /**
- * < Sampling audio frequency (8000 for amr, 16000 or more for aac) of
- * BGM clip
- */
- int ExtendedFs;
-
- /** < Extended frequency for AAC+, eAAC+ streams of BGM clip */
- long startMs;
-
- /** < Time, in milliseconds, at which the added audio track is inserted */
- long beginCutTime;
-
- long endCutTime;
-
- int fileType;
-
- int volume;
-
- /** < Volume, in percentage, of the added audio track */
- boolean loop;
-
- /** < Looping on/off > **/
-
- /** Audio mix and Duck **/
- int ducking_threshold;
-
- int ducking_lowVolume;
-
- boolean bInDucking_enable;
-
- String pcmFilePath;
- }
-
- /** Encapsulates preview clips and effect settings */
- public static class PreviewSettings {
-
- public PreviewClips[] previewClipsArray;
-
- /** The effect settings. */
- public EffectSettings[] effectSettingsArray;
-
- }
-
- /** Encapsulates clip properties */
- public static class PreviewClipProperties {
-
- public Properties[] clipProperties;
-
- }
-
- /** Defines the editing settings. */
- public static class EditSettings {
-
- /**
- * Array of clip settings. There is one <code>clipSetting</code> for
- * each clip.
- */
- public ClipSettings[] clipSettingsArray;
-
- /**
- * Array of transition settings. If there are n clips (and thus n
- * <code>clipSettings</code>) then there are (n-1) transitions and (n-1)
- * <code>transistionSettings</code> in
- * <code>transistionSettingsArray</code>.
- */
- public TransitionSettings[] transitionSettingsArray;
-
- /** The effect settings. */
- public EffectSettings[] effectSettingsArray;
-
- /**
- * Video frame rate of the output clip. See {@link VideoFrameRate
- * VideoFrameRate} for valid values.
- */
- public int videoFrameRate;
-
- /** Output file name. Must be an absolute path. */
- public String outputFile;
-
- /**
- * Size of the video frames in the output clip. See
- * {@link VideoFrameSize VideoFrameSize} for valid values.
- */
- public int videoFrameSize;
-
- /**
- * Format of the video stream in the output clip. See
- * {@link VideoFormat VideoFormat} for valid values.
- */
- public int videoFormat;
-
- /**
- * Profile of the video stream in the output clip.
- */
- public int videoProfile;
-
- /**
- * Level of the video stream in the output clip.
- */
- public int videoLevel;
-
- /**
- * Format of the audio stream in the output clip. See
- * {@link AudioFormat AudioFormat} for valid values.
- */
- public int audioFormat;
-
- /**
- * Sampling frequency of the audio stream in the output clip. See
- * {@link AudioSamplingFrequency AudioSamplingFrequency} for valid
- * values.
- */
- public int audioSamplingFreq;
-
- /**
- * Maximum file size. By setting this you can set the maximum size of
- * the output clip. Set it to <code>0</code> to let the class ignore
- * this filed.
- */
- public int maxFileSize;
-
- /**
- * Number of audio channels in output clip. Use <code>0</code> for none,
- * <code>1</code> for mono or <code>2</code> for stereo. None is only
- * allowed when the <code>audioFormat</code> field is set to
- * {@link AudioFormat#NO_AUDIO AudioFormat.NO_AUDIO} or
- * {@link AudioFormat#NULL_AUDIO AudioFormat.NULL_AUDIO} Mono is only
- * allowed when the <code>audioFormat</code> field is set to
- * {@link AudioFormat#AAC AudioFormat.AAC}
- */
- public int audioChannels;
-
- /** Video bitrate. See {@link Bitrate Bitrate} for valid values. */
- public int videoBitrate;
-
- /** Audio bitrate. See {@link Bitrate Bitrate} for valid values. */
- public int audioBitrate;
-
- /**
- * Background music settings. See {@link BackgroundMusicSettings
- * BackgroundMusicSettings} for valid values.
- */
- public BackgroundMusicSettings backgroundMusicSettings;
-
- public int primaryTrackVolume;
-
- }
-
- /**
- * Defines the media properties.
- **/
-
- public static class Properties {
-
- /**
- * Duration of the media in milliseconds.
- */
-
- public int duration;
-
- /**
- * File type.
- */
-
- public int fileType;
-
- /**
- * Video format.
- */
-
- public int videoFormat;
-
- /**
- * Duration of the video stream of the media in milliseconds.
- */
-
- public int videoDuration;
-
- /**
- * Bitrate of the video stream of the media.
- */
-
- public int videoBitrate;
-
- /**
- * Width of the video frames or the width of the still picture in
- * pixels.
- */
-
- public int width;
-
- /**
- * Height of the video frames or the height of the still picture in
- * pixels.
- */
-
- public int height;
-
- /**
- * Average frame rate of video in the media in frames per second.
- */
-
- public float averageFrameRate;
-
- /**
- * Profile of the video in the media.
- */
-
- public int profile;
-
- /**
- * Level of the video in the media.
- */
-
- public int level;
-
- /**
- * Is Video Profile supported.
- */
-
- public boolean profileSupported;
-
- /**
- * Is Video Level supported.
- */
-
- public boolean levelSupported;
-
- /**
- * Audio format.
- */
-
- public int audioFormat;
-
- /**
- * Duration of the audio stream of the media in milliseconds.
- */
-
- public int audioDuration;
-
- /**
- * Bitrate of the audio stream of the media.
- */
-
- public int audioBitrate;
-
- /**
- * Number of audio channels in the media.
- */
-
- public int audioChannels;
-
- /**
- * Sampling frequency of the audio stream in the media in samples per
- * second.
- */
-
- public int audioSamplingFrequency;
-
- /**
- * Volume value of the audio track as percentage.
- */
- public int audioVolumeValue;
-
- /**
- * Video rotation degree.
- */
- public int videoRotation;
-
- public String Id;
- }
-
- /**
- * Constructor
- *
- * @param projectPath The path where the VideoEditor stores all files
- * related to the project
- * @param lock The semaphore
- * @param veObj The video editor reference
- */
- public MediaArtistNativeHelper(String projectPath, Semaphore lock, VideoEditor veObj) {
- mProjectPath = projectPath;
- if (veObj != null) {
- mVideoEditor = veObj;
- } else {
- mVideoEditor = null;
- throw new IllegalArgumentException("video editor object is null");
- }
- if (mStoryBoardSettings == null) {
- mStoryBoardSettings = new EditSettings();
- }
-
- mLock = lock;
-
- _init(mProjectPath, "null");
- mAudioTrackPCMFilePath = null;
- }
-
- /**
- * @return The project path
- */
- String getProjectPath() {
- return mProjectPath;
- }
-
- /**
- * @return The Audio Track PCM file path
- */
- String getProjectAudioTrackPCMFilePath() {
- return mAudioTrackPCMFilePath;
- }
-
- /**
- * Invalidates the PCM file
- */
- void invalidatePcmFile() {
- if (mAudioTrackPCMFilePath != null) {
- new File(mAudioTrackPCMFilePath).delete();
- mAudioTrackPCMFilePath = null;
- }
- }
-
- @SuppressWarnings("unused")
- private void onProgressUpdate(int taskId, int progress) {
- if (mProcessingState == PROCESSING_EXPORT) {
- if (mExportProgressListener != null) {
- if (mProgressToApp < progress) {
- mExportProgressListener.onProgress(mVideoEditor, mOutputFilename, progress);
- /* record previous progress */
- mProgressToApp = progress;
- }
- }
- }
- else {
- // Adapt progress depending on current state
- int actualProgress = 0;
- int action = 0;
-
- if (mProcessingState == PROCESSING_AUDIO_PCM) {
- action = MediaProcessingProgressListener.ACTION_DECODE;
- } else {
- action = MediaProcessingProgressListener.ACTION_ENCODE;
- }
-
- switch (mProcessingState) {
- case PROCESSING_AUDIO_PCM:
- actualProgress = progress;
- break;
- case PROCESSING_TRANSITION:
- actualProgress = progress;
- break;
- case PROCESSING_KENBURNS:
- actualProgress = progress;
- break;
- case PROCESSING_INTERMEDIATE1:
- if ((progress == 0) && (mProgressToApp != 0)) {
- mProgressToApp = 0;
- }
- if ((progress != 0) || (mProgressToApp != 0)) {
- actualProgress = progress/4;
- }
- break;
- case PROCESSING_INTERMEDIATE2:
- if ((progress != 0) || (mProgressToApp != 0)) {
- actualProgress = 25 + progress/4;
- }
- break;
- case PROCESSING_INTERMEDIATE3:
- if ((progress != 0) || (mProgressToApp != 0)) {
- actualProgress = 50 + progress/2;
- }
- break;
- case PROCESSING_NONE:
-
- default:
- Log.e(TAG, "ERROR unexpected State=" + mProcessingState);
- return;
- }
- if ((mProgressToApp != actualProgress) && (actualProgress != 0)) {
-
- mProgressToApp = actualProgress;
-
- if (mMediaProcessingProgressListener != null) {
- // Send the progress indication
- mMediaProcessingProgressListener.onProgress(mProcessingObject, action,
- actualProgress);
- }
- }
- /* avoid 0 in next intermediate call */
- if (mProgressToApp == 0) {
- if (mMediaProcessingProgressListener != null) {
- /*
- * Send the progress indication
- */
- mMediaProcessingProgressListener.onProgress(mProcessingObject, action,
- actualProgress);
- }
- mProgressToApp = 1;
- }
- }
- }
-
- @SuppressWarnings("unused")
- private void onPreviewProgressUpdate(int progress, boolean isFinished,
- boolean updateOverlay, String filename, int renderingMode, int error) {
- if (mPreviewProgressListener != null) {
- if (mIsFirstProgress) {
- mPreviewProgressListener.onStart(mVideoEditor);
- mIsFirstProgress = false;
- }
-
- final VideoEditor.OverlayData overlayData;
- if (updateOverlay) {
- overlayData = new VideoEditor.OverlayData();
- if (filename != null) {
- overlayData.set(BitmapFactory.decodeFile(filename), renderingMode);
- } else {
- overlayData.setClear();
- }
- } else {
- overlayData = null;
- }
-
- if (progress != 0) {
- mPreviewProgress = progress;
- }
-
- if (isFinished) {
- mPreviewProgressListener.onStop(mVideoEditor);
- } else if (error != 0) {
- mPreviewProgressListener.onError(mVideoEditor, error);
- } else {
- mPreviewProgressListener.onProgress(mVideoEditor, progress, overlayData);
- }
- }
- }
-
- /**
- * Release the native helper object
- */
- void releaseNativeHelper() throws InterruptedException {
- release();
- }
-
- /**
- * Release the native helper to end the Audio Graph process
- */
- @SuppressWarnings("unused")
- private void onAudioGraphExtractProgressUpdate(int progress, boolean isVideo) {
- if ((mExtractAudioWaveformProgressListener != null) && (progress > 0)) {
- mExtractAudioWaveformProgressListener.onProgress(progress);
- }
- }
-
- /**
- * Populates the Effect Settings in EffectSettings
- *
- * @param effects The reference of EffectColor
- *
- * @return The populated effect settings in EffectSettings reference
- */
- EffectSettings getEffectSettings(EffectColor effects) {
- EffectSettings effectSettings = new EffectSettings();
- effectSettings.startTime = (int)effects.getStartTime();
- effectSettings.duration = (int)effects.getDuration();
- effectSettings.videoEffectType = getEffectColorType(effects);
- effectSettings.audioEffectType = 0;
- effectSettings.startPercent = 0;
- effectSettings.durationPercent = 0;
- effectSettings.framingFile = null;
- effectSettings.topLeftX = 0;
- effectSettings.topLeftY = 0;
- effectSettings.framingResize = false;
- effectSettings.text = null;
- effectSettings.textRenderingData = null;
- effectSettings.textBufferWidth = 0;
- effectSettings.textBufferHeight = 0;
- if (effects.getType() == EffectColor.TYPE_FIFTIES) {
- effectSettings.fiftiesFrameRate = 15;
- } else {
- effectSettings.fiftiesFrameRate = 0;
- }
-
- if ((effectSettings.videoEffectType == VideoEffect.COLORRGB16)
- || (effectSettings.videoEffectType == VideoEffect.GRADIENT)) {
- effectSettings.rgb16InputColor = effects.getColor();
- }
-
- effectSettings.alphaBlendingStartPercent = 0;
- effectSettings.alphaBlendingMiddlePercent = 0;
- effectSettings.alphaBlendingEndPercent = 0;
- effectSettings.alphaBlendingFadeInTimePercent = 0;
- effectSettings.alphaBlendingFadeOutTimePercent = 0;
- return effectSettings;
- }
-
- /**
- * Populates the Overlay Settings in EffectSettings
- *
- * @param overlay The reference of OverlayFrame
- *
- * @return The populated overlay settings in EffectSettings reference
- */
- EffectSettings getOverlaySettings(OverlayFrame overlay) {
- EffectSettings effectSettings = new EffectSettings();
- Bitmap bitmap = null;
-
- effectSettings.startTime = (int)overlay.getStartTime();
- effectSettings.duration = (int)overlay.getDuration();
- effectSettings.videoEffectType = VideoEffect.FRAMING;
- effectSettings.audioEffectType = 0;
- effectSettings.startPercent = 0;
- effectSettings.durationPercent = 0;
- effectSettings.framingFile = null;
-
- if ((bitmap = overlay.getBitmap()) != null) {
- effectSettings.framingFile = overlay.getFilename();
-
- if (effectSettings.framingFile == null) {
- try {
- (overlay).save(mProjectPath);
- } catch (IOException e) {
- Log.e(TAG, "getOverlaySettings : File not found");
- }
- effectSettings.framingFile = overlay.getFilename();
- }
- if (bitmap.getConfig() == Bitmap.Config.ARGB_8888)
- effectSettings.bitmapType = 6;
- else if (bitmap.getConfig() == Bitmap.Config.ARGB_4444)
- effectSettings.bitmapType = 5;
- else if (bitmap.getConfig() == Bitmap.Config.RGB_565)
- effectSettings.bitmapType = 4;
- else if (bitmap.getConfig() == Bitmap.Config.ALPHA_8)
- throw new RuntimeException("Bitmap config not supported");
-
- effectSettings.width = bitmap.getWidth();
- effectSettings.height = bitmap.getHeight();
- effectSettings.framingBuffer = new int[effectSettings.width];
- int tmp = 0;
- short maxAlpha = 0;
- short minAlpha = (short)0xFF;
- short alpha = 0;
- while (tmp < effectSettings.height) {
- bitmap.getPixels(effectSettings.framingBuffer, 0,
- effectSettings.width, 0, tmp,
- effectSettings.width, 1);
- for (int i = 0; i < effectSettings.width; i++) {
- alpha = (short)((effectSettings.framingBuffer[i] >> 24) & 0xFF);
- if (alpha > maxAlpha) {
- maxAlpha = alpha;
- }
- if (alpha < minAlpha) {
- minAlpha = alpha;
- }
- }
- tmp += 1;
- }
- alpha = (short)((maxAlpha + minAlpha) / 2);
- alpha = (short)((alpha * 100) / 256);
- effectSettings.alphaBlendingEndPercent = alpha;
- effectSettings.alphaBlendingMiddlePercent = alpha;
- effectSettings.alphaBlendingStartPercent = alpha;
- effectSettings.alphaBlendingFadeInTimePercent = 100;
- effectSettings.alphaBlendingFadeOutTimePercent = 100;
- effectSettings.framingBuffer = null;
-
- /*
- * Set the resized RGB file dimensions
- */
- effectSettings.width = overlay.getResizedRGBSizeWidth();
- if(effectSettings.width == 0) {
- effectSettings.width = bitmap.getWidth();
- }
-
- effectSettings.height = overlay.getResizedRGBSizeHeight();
- if(effectSettings.height == 0) {
- effectSettings.height = bitmap.getHeight();
- }
-
- }
-
- effectSettings.topLeftX = 0;
- effectSettings.topLeftY = 0;
-
- effectSettings.framingResize = true;
- effectSettings.text = null;
- effectSettings.textRenderingData = null;
- effectSettings.textBufferWidth = 0;
- effectSettings.textBufferHeight = 0;
- effectSettings.fiftiesFrameRate = 0;
- effectSettings.rgb16InputColor = 0;
- int mediaItemHeight;
- int aspectRatio;
- if (overlay.getMediaItem() instanceof MediaImageItem) {
- if (((MediaImageItem)overlay.getMediaItem()).getGeneratedImageClip() != null) {
- // Ken Burns was applied
- mediaItemHeight = ((MediaImageItem)overlay.getMediaItem()).getGeneratedClipHeight();
- aspectRatio = getAspectRatio(
- ((MediaImageItem)overlay.getMediaItem()).getGeneratedClipWidth()
- , mediaItemHeight);
- } else {
- //For image get the scaled height. Aspect ratio would remain the same
- mediaItemHeight = ((MediaImageItem)overlay.getMediaItem()).getScaledHeight();
- aspectRatio = overlay.getMediaItem().getAspectRatio();
- }
- } else {
- aspectRatio = overlay.getMediaItem().getAspectRatio();
- mediaItemHeight = overlay.getMediaItem().getHeight();
- }
- effectSettings.framingScaledSize = findVideoResolution(aspectRatio, mediaItemHeight);
- return effectSettings;
- }
-
- /* get Video Editor aspect ratio */
- int nativeHelperGetAspectRatio() {
- return mVideoEditor.getAspectRatio();
- }
-
- /**
- * Sets the export audio codec
- *
- * @param export audio codec
- *
- */
- void setAudioCodec(int codec) {
- mExportAudioCodec = codec;
- }
- /**
- * Sets the export video codec
- *
- * @param export video codec
- *
- */
- void setVideoCodec(int codec) {
- mExportVideoCodec = codec;
- }
-
- /**
- * Sets the audio regenerate flag
- *
- * @param flag The boolean to set the audio regenerate flag
- *
- */
- void setAudioflag(boolean flag) {
- //check if the file exists.
- if (!(new File(String.format(mProjectPath + "/" + AUDIO_TRACK_PCM_FILE)).exists())) {
- flag = true;
- }
- mRegenerateAudio = flag;
- }
-
- /**
- * Gets the audio regenerate flag
- *
- * @param return The boolean to get the audio regenerate flag
- *
- */
- boolean getAudioflag() {
- return mRegenerateAudio;
- }
-
- /**
- * Maps the average frame rate to one of the defined enum values
- *
- * @param averageFrameRate The average frame rate of video item
- *
- * @return The frame rate from one of the defined enum values
- */
- int GetClosestVideoFrameRate(int averageFrameRate) {
- if (averageFrameRate >= 25) {
- return VideoFrameRate.FR_30_FPS;
- } else if (averageFrameRate >= 20) {
- return VideoFrameRate.FR_25_FPS;
- } else if (averageFrameRate >= 15) {
- return VideoFrameRate.FR_20_FPS;
- } else if (averageFrameRate >= 12) {
- return VideoFrameRate.FR_15_FPS;
- } else if (averageFrameRate >= 10) {
- return VideoFrameRate.FR_12_5_FPS;
- } else if (averageFrameRate >= 7) {
- return VideoFrameRate.FR_10_FPS;
- } else if (averageFrameRate >= 5) {
- return VideoFrameRate.FR_7_5_FPS;
- } else {
- return -1;
- }
- }
-
- /**
- * Helper function to adjust the effect or overlay start time
- * depending on the begin and end boundary time of meddia item
- */
- public void adjustEffectsStartTimeAndDuration(EffectSettings lEffect, int beginCutTime,
- int endCutTime) {
-
- int effectStartTime = 0;
- int effectDuration = 0;
-
- /**
- * cbct -> clip begin cut time
- * cect -> clip end cut time
- ****************************************
- * | |
- * | cbct cect |
- * | <-1--> | | |
- * | <--|-2-> | |
- * | | <---3---> | |
- * | | <--|-4---> |
- * | | | <--5--> |
- * | <---|------6----|----> |
- * | |
- * < : effectStart
- * > : effectStart + effectDuration
- ****************************************
- **/
-
- /** 1 & 5 */
- /**
- * Effect falls out side the trim duration. In such a case effects shall
- * not be applied.
- */
- if ((lEffect.startTime > endCutTime)
- || ((lEffect.startTime + lEffect.duration) <= beginCutTime)) {
-
- effectStartTime = 0;
- effectDuration = 0;
-
- lEffect.startTime = effectStartTime;
- lEffect.duration = effectDuration;
- return;
- }
-
- /** 2 */
- if ((lEffect.startTime < beginCutTime)
- && ((lEffect.startTime + lEffect.duration) > beginCutTime)
- && ((lEffect.startTime + lEffect.duration) <= endCutTime)) {
- effectStartTime = 0;
- effectDuration = lEffect.duration;
-
- effectDuration -= (beginCutTime - lEffect.startTime);
- lEffect.startTime = effectStartTime;
- lEffect.duration = effectDuration;
- return;
- }
-
- /** 3 */
- if ((lEffect.startTime >= beginCutTime)
- && ((lEffect.startTime + lEffect.duration) <= endCutTime)) {
- effectStartTime = lEffect.startTime - beginCutTime;
- lEffect.startTime = effectStartTime;
- lEffect.duration = lEffect.duration;
- return;
- }
-
- /** 4 */
- if ((lEffect.startTime >= beginCutTime)
- && ((lEffect.startTime + lEffect.duration) > endCutTime)) {
- effectStartTime = lEffect.startTime - beginCutTime;
- effectDuration = endCutTime - lEffect.startTime;
- lEffect.startTime = effectStartTime;
- lEffect.duration = effectDuration;
- return;
- }
-
- /** 6 */
- if ((lEffect.startTime < beginCutTime)
- && ((lEffect.startTime + lEffect.duration) > endCutTime)) {
- effectStartTime = 0;
- effectDuration = endCutTime - beginCutTime;
- lEffect.startTime = effectStartTime;
- lEffect.duration = effectDuration;
- return;
- }
-
- }
-
- /**
- * Generates the clip for preview or export
- *
- * @param editSettings The EditSettings reference for generating
- * a clip for preview or export
- *
- * @return error value
- */
- public int generateClip(EditSettings editSettings) {
- int err = 0;
-
- try {
- err = nativeGenerateClip(editSettings);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG, "Illegal Argument exception in load settings");
- return -1;
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Illegal state exception in load settings");
- return -1;
- } catch (RuntimeException ex) {
- Log.e(TAG, "Runtime exception in load settings");
- return -1;
- }
- return err;
- }
-
- /**
- * Init function to initialiZe the ClipSettings reference to
- * default values
- *
- * @param lclipSettings The ClipSettings reference
- */
- void initClipSettings(ClipSettings lclipSettings) {
- lclipSettings.clipPath = null;
- lclipSettings.clipDecodedPath = null;
- lclipSettings.clipOriginalPath = null;
- lclipSettings.fileType = 0;
- lclipSettings.endCutTime = 0;
- lclipSettings.beginCutTime = 0;
- lclipSettings.beginCutPercent = 0;
- lclipSettings.endCutPercent = 0;
- lclipSettings.panZoomEnabled = false;
- lclipSettings.panZoomPercentStart = 0;
- lclipSettings.panZoomTopLeftXStart = 0;
- lclipSettings.panZoomTopLeftYStart = 0;
- lclipSettings.panZoomPercentEnd = 0;
- lclipSettings.panZoomTopLeftXEnd = 0;
- lclipSettings.panZoomTopLeftYEnd = 0;
- lclipSettings.mediaRendering = 0;
- lclipSettings.rotationDegree = 0;
- }
-
-
- /**
- * Populates the settings for generating an effect clip
- *
- * @param lMediaItem The media item for which the effect clip
- * needs to be generated
- * @param lclipSettings The ClipSettings reference containing
- * clips data
- * @param e The EditSettings reference containing effect specific data
- * @param uniqueId The unique id used in the name of the output clip
- * @param clipNo Used for internal purpose
- *
- * @return The name and path of generated clip
- */
- String generateEffectClip(MediaItem lMediaItem, ClipSettings lclipSettings,
- EditSettings e,String uniqueId,int clipNo) {
- int err = 0;
- EditSettings editSettings = null;
- String EffectClipPath = null;
- int outVideoProfile = 0;
- int outVideoLevel = 0;
- editSettings = new EditSettings();
-
- editSettings.clipSettingsArray = new ClipSettings[1];
- editSettings.clipSettingsArray[0] = lclipSettings;
-
- editSettings.backgroundMusicSettings = null;
- editSettings.transitionSettingsArray = null;
- editSettings.effectSettingsArray = e.effectSettingsArray;
-
- EffectClipPath = String.format(mProjectPath + "/" + "ClipEffectIntermediate" + "_"
- + lMediaItem.getId() + uniqueId + ".3gp");
-
- File tmpFile = new File(EffectClipPath);
- if (tmpFile.exists()) {
- tmpFile.delete();
- }
-
- outVideoProfile = VideoEditorProfile.getExportProfile(VideoFormat.H264);
- outVideoLevel = VideoEditorProfile.getExportLevel(VideoFormat.H264);
- editSettings.videoProfile = outVideoProfile;
- editSettings.videoLevel= outVideoLevel;
-
- if (lMediaItem instanceof MediaVideoItem) {
- MediaVideoItem m = (MediaVideoItem)lMediaItem;
-
- editSettings.audioFormat = AudioFormat.AAC;
- editSettings.audioChannels = 2;
- editSettings.audioBitrate = Bitrate.BR_64_KBPS;
- editSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
-
- editSettings.videoFormat = VideoFormat.H264;
- editSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
- editSettings.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(),
- m.getHeight());
- editSettings.videoBitrate = findVideoBitrate(editSettings.videoFrameSize);
- } else {
- MediaImageItem m = (MediaImageItem)lMediaItem;
- editSettings.audioBitrate = Bitrate.BR_64_KBPS;
- editSettings.audioChannels = 2;
- editSettings.audioFormat = AudioFormat.AAC;
- editSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
-
- editSettings.videoFormat = VideoFormat.H264;
- editSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
- editSettings.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(),
- m.getScaledHeight());
- editSettings.videoBitrate = findVideoBitrate(editSettings.videoFrameSize);
- }
-
- editSettings.outputFile = EffectClipPath;
-
- if (clipNo == 1) {
- mProcessingState = PROCESSING_INTERMEDIATE1;
- } else if (clipNo == 2) {
- mProcessingState = PROCESSING_INTERMEDIATE2;
- }
- mProcessingObject = lMediaItem;
- err = generateClip(editSettings);
- mProcessingState = PROCESSING_NONE;
-
- if (err == 0) {
- lclipSettings.clipPath = EffectClipPath;
- lclipSettings.fileType = FileType.THREE_GPP;
- return EffectClipPath;
- } else {
- throw new RuntimeException("preview generation cannot be completed");
- }
- }
-
-
- /**
- * Populates the settings for generating a Ken Burn effect clip
- *
- * @param m The media image item for which the Ken Burn effect clip
- * needs to be generated
- * @param e The EditSettings reference clip specific data
- *
- * @return The name and path of generated clip
- */
- String generateKenBurnsClip(EditSettings e, MediaImageItem m) {
- String output = null;
- int err = 0;
- int outVideoProfile = 0;
- int outVideoLevel = 0;
-
- e.backgroundMusicSettings = null;
- e.transitionSettingsArray = null;
- e.effectSettingsArray = null;
- output = String.format(mProjectPath + "/" + "ImageClip-" + m.getId() + ".3gp");
-
- File tmpFile = new File(output);
- if (tmpFile.exists()) {
- tmpFile.delete();
- }
-
- outVideoProfile = VideoEditorProfile.getExportProfile(VideoFormat.H264);
- outVideoLevel = VideoEditorProfile.getExportLevel(VideoFormat.H264);
- e.videoProfile = outVideoProfile;
- e.videoLevel = outVideoLevel;
-
- e.outputFile = output;
- e.audioBitrate = Bitrate.BR_64_KBPS;
- e.audioChannels = 2;
- e.audioFormat = AudioFormat.AAC;
- e.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
-
- e.videoFormat = VideoFormat.H264;
- e.videoFrameRate = VideoFrameRate.FR_30_FPS;
- e.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(),
- m.getScaledHeight());
- e.videoBitrate = findVideoBitrate(e.videoFrameSize);
-
- mProcessingState = PROCESSING_KENBURNS;
- mProcessingObject = m;
- err = generateClip(e);
- // Reset the processing state and check for errors
- mProcessingState = PROCESSING_NONE;
- if (err != 0) {
- throw new RuntimeException("preview generation cannot be completed");
- }
- return output;
- }
-
-
- /**
- * Calculates the output resolution for transition clip
- *
- * @param m1 First media item associated with transition
- * @param m2 Second media item associated with transition
- *
- * @return The transition resolution
- */
- private int getTransitionResolution(MediaItem m1, MediaItem m2) {
- int clip1Height = 0;
- int clip2Height = 0;
- int videoSize = 0;
-
- if (m1 != null && m2 != null) {
- if (m1 instanceof MediaVideoItem) {
- clip1Height = m1.getHeight();
- } else if (m1 instanceof MediaImageItem) {
- clip1Height = ((MediaImageItem)m1).getScaledHeight();
- }
- if (m2 instanceof MediaVideoItem) {
- clip2Height = m2.getHeight();
- } else if (m2 instanceof MediaImageItem) {
- clip2Height = ((MediaImageItem)m2).getScaledHeight();
- }
- if (clip1Height > clip2Height) {
- videoSize = findVideoResolution(mVideoEditor.getAspectRatio(), clip1Height);
- } else {
- videoSize = findVideoResolution(mVideoEditor.getAspectRatio(), clip2Height);
- }
- } else if (m1 == null && m2 != null) {
- if (m2 instanceof MediaVideoItem) {
- clip2Height = m2.getHeight();
- } else if (m2 instanceof MediaImageItem) {
- clip2Height = ((MediaImageItem)m2).getScaledHeight();
- }
- videoSize = findVideoResolution(mVideoEditor.getAspectRatio(), clip2Height);
- } else if (m1 != null && m2 == null) {
- if (m1 instanceof MediaVideoItem) {
- clip1Height = m1.getHeight();
- } else if (m1 instanceof MediaImageItem) {
- clip1Height = ((MediaImageItem)m1).getScaledHeight();
- }
- videoSize = findVideoResolution(mVideoEditor.getAspectRatio(), clip1Height);
- }
- return videoSize;
- }
-
- /**
- * Populates the settings for generating an transition clip
- *
- * @param m1 First media item associated with transition
- * @param m2 Second media item associated with transition
- * @param e The EditSettings reference containing
- * clip specific data
- * @param uniqueId The unique id used in the name of the output clip
- * @param t The Transition specific data
- *
- * @return The name and path of generated clip
- */
- String generateTransitionClip(EditSettings e, String uniqueId,
- MediaItem m1, MediaItem m2,Transition t) {
- String outputFilename = null;
- int err = 0;
- int outVideoProfile = 0;
- int outVideoLevel = 0;
- outputFilename = String.format(mProjectPath + "/" + uniqueId + ".3gp");
-
- outVideoProfile = VideoEditorProfile.getExportProfile(VideoFormat.H264);
- outVideoLevel = VideoEditorProfile.getExportLevel(VideoFormat.H264);
- e.videoProfile = outVideoProfile;
- e.videoLevel = outVideoLevel;
-
- e.outputFile = outputFilename;
- e.audioBitrate = Bitrate.BR_64_KBPS;
- e.audioChannels = 2;
- e.audioFormat = AudioFormat.AAC;
- e.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
-
- e.videoFormat = VideoFormat.H264;
- e.videoFrameRate = VideoFrameRate.FR_30_FPS;
- e.videoFrameSize = getTransitionResolution(m1, m2);
- e.videoBitrate = findVideoBitrate(e.videoFrameSize);
-
- if (new File(outputFilename).exists()) {
- new File(outputFilename).delete();
- }
- mProcessingState = PROCESSING_INTERMEDIATE3;
- mProcessingObject = t;
- err = generateClip(e);
- // Reset the processing state and check for errors
- mProcessingState = PROCESSING_NONE;
- if (err != 0) {
- throw new RuntimeException("preview generation cannot be completed");
- }
- return outputFilename;
- }
-
- /**
- * Populates effects and overlays in EffectSettings structure
- * and also adjust the start time and duration of effects and overlays
- * w.r.t to total story board time
- *
- * @param m1 Media item associated with effect
- * @param effectSettings The EffectSettings reference containing
- * effect specific data
- * @param beginCutTime The begin cut time of the clip associated with effect
- * @param endCutTime The end cut time of the clip associated with effect
- * @param storyBoardTime The current story board time
- *
- * @return The updated index
- */
- private int populateEffects(MediaItem m, EffectSettings[] effectSettings, int i,
- int beginCutTime, int endCutTime, int storyBoardTime) {
-
- if (m.getBeginTransition() != null && m.getBeginTransition().getDuration() > 0
- && m.getEndTransition() != null && m.getEndTransition().getDuration() > 0) {
- beginCutTime += m.getBeginTransition().getDuration();
- endCutTime -= m.getEndTransition().getDuration();
- } else if (m.getBeginTransition() == null && m.getEndTransition() != null
- && m.getEndTransition().getDuration() > 0) {
- endCutTime -= m.getEndTransition().getDuration();
- } else if (m.getEndTransition() == null && m.getBeginTransition() != null
- && m.getBeginTransition().getDuration() > 0) {
- beginCutTime += m.getBeginTransition().getDuration();
- }
-
- final List<Effect> effects = m.getAllEffects();
- final List<Overlay> overlays = m.getAllOverlays();
-
- for (Overlay overlay : overlays) {
- effectSettings[i] = getOverlaySettings((OverlayFrame)overlay);
- adjustEffectsStartTimeAndDuration(effectSettings[i], beginCutTime, endCutTime);
- effectSettings[i].startTime += storyBoardTime;
- i++;
- }
-
- for (Effect effect : effects) {
- if (effect instanceof EffectColor) {
- effectSettings[i] = getEffectSettings((EffectColor)effect);
- adjustEffectsStartTimeAndDuration(effectSettings[i], beginCutTime, endCutTime);
- effectSettings[i].startTime += storyBoardTime;
- i++;
- }
- }
-
- return i;
- }
-
- /**
- * Adjusts the media item boundaries for use in export or preview
- *
- * @param clipSettings The ClipSettings reference
- * @param clipProperties The Properties reference
- * @param m The media item
- */
- private void adjustMediaItemBoundary(ClipSettings clipSettings,
- Properties clipProperties, MediaItem m) {
- if (m.getBeginTransition() != null && m.getBeginTransition().getDuration() > 0
- && m.getEndTransition() != null && m.getEndTransition().getDuration() > 0) {
- clipSettings.beginCutTime += m.getBeginTransition().getDuration();
- clipSettings.endCutTime -= m.getEndTransition().getDuration();
- } else if (m.getBeginTransition() == null && m.getEndTransition() != null
- && m.getEndTransition().getDuration() > 0) {
- clipSettings.endCutTime -= m.getEndTransition().getDuration();
- } else if (m.getEndTransition() == null && m.getBeginTransition() != null
- && m.getBeginTransition().getDuration() > 0) {
- clipSettings.beginCutTime += m.getBeginTransition().getDuration();
- }
-
- clipProperties.duration = clipSettings.endCutTime - clipSettings.beginCutTime;
-
- if (clipProperties.videoDuration != 0) {
- clipProperties.videoDuration = clipSettings.endCutTime - clipSettings.beginCutTime;
- }
-
- if (clipProperties.audioDuration != 0) {
- clipProperties.audioDuration = clipSettings.endCutTime - clipSettings.beginCutTime;
- }
- }
-
- /**
- * Generates the transition if transition is present
- * and is in invalidated state
- *
- * @param transition The Transition reference
- * @param editSettings The EditSettings reference
- * @param clipPropertiesArray The clip Properties array
- * @param i The index in clip Properties array for current clip
- */
- private void generateTransition(Transition transition, EditSettings editSettings,
- PreviewClipProperties clipPropertiesArray, int index) {
- if (!(transition.isGenerated())) {
- transition.generate();
- }
- editSettings.clipSettingsArray[index] = new ClipSettings();
- editSettings.clipSettingsArray[index].clipPath = transition.getFilename();
- editSettings.clipSettingsArray[index].fileType = FileType.THREE_GPP;
- editSettings.clipSettingsArray[index].beginCutTime = 0;
- editSettings.clipSettingsArray[index].endCutTime = (int)transition.getDuration();
- editSettings.clipSettingsArray[index].mediaRendering = MediaRendering.BLACK_BORDERS;
-
- try {
- clipPropertiesArray.clipProperties[index] =
- getMediaProperties(transition.getFilename());
- } catch (Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
- }
-
- clipPropertiesArray.clipProperties[index].Id = null;
- clipPropertiesArray.clipProperties[index].audioVolumeValue = 100;
- clipPropertiesArray.clipProperties[index].duration = (int)transition.getDuration();
- if (clipPropertiesArray.clipProperties[index].videoDuration != 0) {
- clipPropertiesArray.clipProperties[index].videoDuration = (int)transition.getDuration();
- }
-
- if (clipPropertiesArray.clipProperties[index].audioDuration != 0) {
- clipPropertiesArray.clipProperties[index].audioDuration = (int)transition.getDuration();
- }
- }
-
- /**
- * Sets the volume for current media item in clip properties array
- *
- * @param m The media item
- * @param clipProperties The clip properties array reference
- * @param i The index in clip Properties array for current clip
- */
- private void adjustVolume(MediaItem m, PreviewClipProperties clipProperties,
- int index) {
- if (m instanceof MediaVideoItem) {
- final boolean videoMuted = ((MediaVideoItem)m).isMuted();
- if (videoMuted == false) {
- mClipProperties.clipProperties[index].audioVolumeValue =
- ((MediaVideoItem)m).getVolume();
- } else {
- mClipProperties.clipProperties[index].audioVolumeValue = 0;
- }
- } else if (m instanceof MediaImageItem) {
- mClipProperties.clipProperties[index].audioVolumeValue = 0;
- }
- }
-
- /**
- * Checks for odd size image width and height
- *
- * @param m The media item
- * @param clipProperties The clip properties array reference
- * @param i The index in clip Properties array for current clip
- */
- private void checkOddSizeImage(MediaItem m, PreviewClipProperties clipProperties, int index) {
- if (m instanceof MediaImageItem) {
- int width = mClipProperties.clipProperties[index].width;
- int height = mClipProperties.clipProperties[index].height;
-
- if ((width % 2) != 0) {
- width -= 1;
- }
- if ((height % 2) != 0) {
- height -= 1;
- }
- mClipProperties.clipProperties[index].width = width;
- mClipProperties.clipProperties[index].height = height;
- }
- }
-
- /**
- * Populates the media item properties and calculates the maximum
- * height among all the clips
- *
- * @param m The media item
- * @param i The index in clip Properties array for current clip
- * @param maxHeight The max height from the clip properties
- *
- * @return Updates the max height if current clip's height is greater
- * than all previous clips height
- */
- private int populateMediaItemProperties(MediaItem m, int index, int maxHeight) {
- mPreviewEditSettings.clipSettingsArray[index] = new ClipSettings();
- if (m instanceof MediaVideoItem) {
- mPreviewEditSettings.clipSettingsArray[index] =
- ((MediaVideoItem)m).getVideoClipProperties();
- if (((MediaVideoItem)m).getHeight() > maxHeight) {
- maxHeight = ((MediaVideoItem)m).getHeight();
- }
- } else if (m instanceof MediaImageItem) {
- mPreviewEditSettings.clipSettingsArray[index] =
- ((MediaImageItem)m).getImageClipProperties();
- if (((MediaImageItem)m).getScaledHeight() > maxHeight) {
- maxHeight = ((MediaImageItem)m).getScaledHeight();
- }
- }
- /** + Handle the image files here */
- if (mPreviewEditSettings.clipSettingsArray[index].fileType == FileType.JPG) {
- mPreviewEditSettings.clipSettingsArray[index].clipDecodedPath =
- ((MediaImageItem)m).getDecodedImageFileName();
-
- mPreviewEditSettings.clipSettingsArray[index].clipOriginalPath =
- mPreviewEditSettings.clipSettingsArray[index].clipPath;
- }
- return maxHeight;
- }
-
- /**
- * Populates the background music track properties
- *
- * @param mediaBGMList The background music list
- *
- */
- private void populateBackgroundMusicProperties(List<AudioTrack> mediaBGMList) {
-
- if (mediaBGMList.size() == 1) {
- mAudioTrack = mediaBGMList.get(0);
- } else {
- mAudioTrack = null;
- }
-
- if (mAudioTrack != null) {
- mAudioSettings = new AudioSettings();
- Properties mAudioProperties = new Properties();
- mAudioSettings.pFile = null;
- mAudioSettings.Id = mAudioTrack.getId();
- try {
- mAudioProperties = getMediaProperties(mAudioTrack.getFilename());
- } catch (Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
- }
- mAudioSettings.bRemoveOriginal = false;
- mAudioSettings.channels = mAudioProperties.audioChannels;
- mAudioSettings.Fs = mAudioProperties.audioSamplingFrequency;
- mAudioSettings.loop = mAudioTrack.isLooping();
- mAudioSettings.ExtendedFs = 0;
- mAudioSettings.pFile = mAudioTrack.getFilename();
- mAudioSettings.startMs = mAudioTrack.getStartTime();
- mAudioSettings.beginCutTime = mAudioTrack.getBoundaryBeginTime();
- mAudioSettings.endCutTime = mAudioTrack.getBoundaryEndTime();
- if (mAudioTrack.isMuted()) {
- mAudioSettings.volume = 0;
- } else {
- mAudioSettings.volume = mAudioTrack.getVolume();
- }
- mAudioSettings.fileType = mAudioProperties.fileType;
- mAudioSettings.ducking_lowVolume = mAudioTrack.getDuckedTrackVolume();
- mAudioSettings.ducking_threshold = mAudioTrack.getDuckingThreshhold();
- mAudioSettings.bInDucking_enable = mAudioTrack.isDuckingEnabled();
- mAudioTrackPCMFilePath = String.format(mProjectPath + "/" + AUDIO_TRACK_PCM_FILE);
- mAudioSettings.pcmFilePath = mAudioTrackPCMFilePath;
-
- mPreviewEditSettings.backgroundMusicSettings = new BackgroundMusicSettings();
- mPreviewEditSettings.backgroundMusicSettings.file = mAudioTrackPCMFilePath;
- mPreviewEditSettings.backgroundMusicSettings.fileType = mAudioProperties.fileType;
- mPreviewEditSettings.backgroundMusicSettings.insertionTime =
- mAudioTrack.getStartTime();
- mPreviewEditSettings.backgroundMusicSettings.volumePercent = mAudioTrack.getVolume();
- mPreviewEditSettings.backgroundMusicSettings.beginLoop =
- mAudioTrack.getBoundaryBeginTime();
- mPreviewEditSettings.backgroundMusicSettings.endLoop =
- mAudioTrack.getBoundaryEndTime();
- mPreviewEditSettings.backgroundMusicSettings.enableDucking =
- mAudioTrack.isDuckingEnabled();
- mPreviewEditSettings.backgroundMusicSettings.duckingThreshold =
- mAudioTrack.getDuckingThreshhold();
- mPreviewEditSettings.backgroundMusicSettings.lowVolume =
- mAudioTrack.getDuckedTrackVolume();
- mPreviewEditSettings.backgroundMusicSettings.isLooping = mAudioTrack.isLooping();
- mPreviewEditSettings.primaryTrackVolume = 100;
- mProcessingState = PROCESSING_AUDIO_PCM;
- mProcessingObject = mAudioTrack;
- } else {
- mAudioSettings = null;
- mPreviewEditSettings.backgroundMusicSettings = null;
- mAudioTrackPCMFilePath = null;
- }
- }
-
- /**
- * Calculates all the effects in all the media items
- * in media items list
- *
- * @param mediaItemsList The media item list
- *
- * @return The total number of effects
- *
- */
- private int getTotalEffects(List<MediaItem> mediaItemsList) {
- int totalEffects = 0;
- final Iterator<MediaItem> it = mediaItemsList.iterator();
- while (it.hasNext()) {
- final MediaItem t = it.next();
- totalEffects += t.getAllEffects().size();
- totalEffects += t.getAllOverlays().size();
- final Iterator<Effect> ef = t.getAllEffects().iterator();
- while (ef.hasNext()) {
- final Effect e = ef.next();
- if (e instanceof EffectKenBurns) {
- totalEffects--;
- }
- }
- }
- return totalEffects;
- }
-
- /**
- * This function is responsible for forming clip settings
- * array and clip properties array including transition clips
- * and effect settings for preview purpose or export.
- *
- *
- * @param mediaItemsList The media item list
- * @param mediaTransitionList The transitions list
- * @param mediaBGMList The background music list
- * @param listener The MediaProcessingProgressListener
- *
- */
- void previewStoryBoard(List<MediaItem> mediaItemsList,
- List<Transition> mediaTransitionList, List<AudioTrack> mediaBGMList,
- MediaProcessingProgressListener listener) {
- if (mInvalidatePreviewArray) {
- int previewIndex = 0;
- int totalEffects = 0;
- int storyBoardTime = 0;
- int maxHeight = 0;
- int beginCutTime = 0;
- int endCutTime = 0;
- int effectIndex = 0;
- Transition lTransition = null;
- MediaItem lMediaItem = null;
- mPreviewEditSettings = new EditSettings();
- mClipProperties = new PreviewClipProperties();
- mTotalClips = 0;
-
- mTotalClips = mediaItemsList.size();
- for (Transition transition : mediaTransitionList) {
- if (transition.getDuration() > 0) {
- mTotalClips++;
- }
- }
-
- totalEffects = getTotalEffects(mediaItemsList);
-
- mPreviewEditSettings.clipSettingsArray = new ClipSettings[mTotalClips];
- mPreviewEditSettings.effectSettingsArray = new EffectSettings[totalEffects];
- mClipProperties.clipProperties = new Properties[mTotalClips];
-
- /** record the call back progress listener */
- mMediaProcessingProgressListener = listener;
- mProgressToApp = 0;
-
- if (mediaItemsList.size() > 0) {
- for (int i = 0; i < mediaItemsList.size(); i++) {
- /* Get the Media Item from the list */
- lMediaItem = mediaItemsList.get(i);
- if (lMediaItem instanceof MediaVideoItem) {
- beginCutTime = (int)((MediaVideoItem)lMediaItem).getBoundaryBeginTime();
- endCutTime = (int)((MediaVideoItem)lMediaItem).getBoundaryEndTime();
- } else if (lMediaItem instanceof MediaImageItem) {
- beginCutTime = 0;
- endCutTime = (int)((MediaImageItem)lMediaItem).getTimelineDuration();
- }
- /* Get the transition associated with Media Item */
- lTransition = lMediaItem.getBeginTransition();
- if (lTransition != null && (lTransition.getDuration() > 0)) {
- /* generate transition clip */
- generateTransition(lTransition, mPreviewEditSettings,
- mClipProperties, previewIndex);
- storyBoardTime += mClipProperties.clipProperties[previewIndex].duration;
- previewIndex++;
- }
- /* Populate media item properties */
- maxHeight = populateMediaItemProperties(lMediaItem, previewIndex, maxHeight);
- /* Get the clip properties of the media item. */
- if (lMediaItem instanceof MediaImageItem) {
- int tmpCnt = 0;
- boolean bEffectKbPresent = false;
- final List<Effect> effectList = lMediaItem.getAllEffects();
- /**
- * Check if Ken Burns effect is present
- */
- while (tmpCnt < effectList.size()) {
- if (effectList.get(tmpCnt) instanceof EffectKenBurns) {
- bEffectKbPresent = true;
- break;
- }
- tmpCnt++;
- }
-
- if (bEffectKbPresent) {
- try {
- if(((MediaImageItem)lMediaItem).getGeneratedImageClip() != null) {
- mClipProperties.clipProperties[previewIndex]
- = getMediaProperties(((MediaImageItem)lMediaItem).
- getGeneratedImageClip());
- }
- else {
- mClipProperties.clipProperties[previewIndex]
- = getMediaProperties(((MediaImageItem)lMediaItem).
- getScaledImageFileName());
- mClipProperties.clipProperties[previewIndex].width =
- ((MediaImageItem)lMediaItem).getScaledWidth();
- mClipProperties.clipProperties[previewIndex].height =
- ((MediaImageItem)lMediaItem).getScaledHeight();
- }
- } catch (Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
- }
- } else {
- try {
- mClipProperties.clipProperties[previewIndex]
- = getMediaProperties(((MediaImageItem)lMediaItem).
- getScaledImageFileName());
- } catch (Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
- }
- mClipProperties.clipProperties[previewIndex].width =
- ((MediaImageItem)lMediaItem).getScaledWidth();
- mClipProperties.clipProperties[previewIndex].height =
- ((MediaImageItem)lMediaItem).getScaledHeight();
- }
- } else {
- try {
- mClipProperties.clipProperties[previewIndex]
- = getMediaProperties(lMediaItem.getFilename());
- } catch (Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found");
- }
- }
- mClipProperties.clipProperties[previewIndex].Id = lMediaItem.getId();
- checkOddSizeImage(lMediaItem, mClipProperties, previewIndex);
- adjustVolume(lMediaItem, mClipProperties, previewIndex);
-
- /*
- * Adjust media item start time and end time w.r.t to begin
- * and end transitions associated with media item
- */
-
- adjustMediaItemBoundary(mPreviewEditSettings.clipSettingsArray[previewIndex],
- mClipProperties.clipProperties[previewIndex], lMediaItem);
-
- /*
- * Get all the effects and overlays for that media item and
- * adjust start time and duration of effects
- */
-
- effectIndex = populateEffects(lMediaItem,
- mPreviewEditSettings.effectSettingsArray, effectIndex, beginCutTime,
- endCutTime, storyBoardTime);
- storyBoardTime += mClipProperties.clipProperties[previewIndex].duration;
- previewIndex++;
-
- /* Check if there is any end transition at last media item */
-
- if (i == (mediaItemsList.size() - 1)) {
- lTransition = lMediaItem.getEndTransition();
- if (lTransition != null && (lTransition.getDuration() > 0)) {
- generateTransition(lTransition, mPreviewEditSettings, mClipProperties,
- previewIndex);
- break;
- }
- }
- }
-
- if (!mErrorFlagSet) {
- mPreviewEditSettings.videoFrameSize = findVideoResolution(mVideoEditor
- .getAspectRatio(), maxHeight);
- populateBackgroundMusicProperties(mediaBGMList);
-
- /** call to native populate settings */
- try {
- nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG, "Illegal argument exception in nativePopulateSettings");
- throw ex;
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Illegal state exception in nativePopulateSettings");
- throw ex;
- } catch (RuntimeException ex) {
- Log.e(TAG, "Runtime exception in nativePopulateSettings");
- throw ex;
- }
- mInvalidatePreviewArray = false;
- mProcessingState = PROCESSING_NONE;
- }
- }
- if (mErrorFlagSet) {
- mErrorFlagSet = false;
- throw new RuntimeException("preview generation cannot be completed");
- }
- }
- } /* END of previewStoryBoard */
-
- /**
- * This function is responsible for starting the preview
- *
- *
- * @param surface The surface on which preview has to be displayed
- * @param fromMs The time in ms from which preview has to be started
- * @param toMs The time in ms till preview has to be played
- * @param loop To loop the preview or not
- * @param callbackAfterFrameCount INdicated after how many frames
- * the callback is needed
- * @param listener The PreviewProgressListener
- */
- void doPreview(Surface surface, long fromMs, long toMs, boolean loop,
- int callbackAfterFrameCount, PreviewProgressListener listener) {
- mPreviewProgress = fromMs;
- mIsFirstProgress = true;
- mPreviewProgressListener = listener;
-
- if (!mInvalidatePreviewArray) {
- try {
- /** Modify the image files names to rgb image files. */
- for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length;
- clipCnt++) {
- if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
- mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
- mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath;
- }
- }
- nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
- nativeStartPreview(surface, fromMs, toMs, callbackAfterFrameCount, loop);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG, "Illegal argument exception in nativeStartPreview");
- throw ex;
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Illegal state exception in nativeStartPreview");
- throw ex;
- } catch (RuntimeException ex) {
- Log.e(TAG, "Runtime exception in nativeStartPreview");
- throw ex;
- }
- } else {
- throw new IllegalStateException("generatePreview is in progress");
- }
- }
-
- /**
- * This function is responsible for stopping the preview
- */
- long stopPreview() {
- return nativeStopPreview();
- }
-
- /**
- * This function is responsible for rendering a single frame
- * from the complete story board on the surface
- *
- * @param surface The surface on which frame has to be rendered
- * @param time The time in ms at which the frame has to be rendered
- * @param surfaceWidth The surface width
- * @param surfaceHeight The surface height
- * @param overlayData The overlay data
- *
- * @return The actual time from the story board at which the frame was extracted
- * and rendered
- */
- long renderPreviewFrame(Surface surface, long time, int surfaceWidth,
- int surfaceHeight, VideoEditor.OverlayData overlayData) {
- if (mInvalidatePreviewArray) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Call generate preview first");
- }
- throw new IllegalStateException("Call generate preview first");
- }
-
- long timeMs = 0;
- try {
- for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length;
- clipCnt++) {
- if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
- mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
- mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath;
- }
- }
-
- // Reset the render preview frame params that shall be set by native.
- mRenderPreviewOverlayFile = null;
- mRenderPreviewRenderingMode = MediaRendering.RESIZING;
-
- nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
-
- timeMs = (long)nativeRenderPreviewFrame(surface, time, surfaceWidth, surfaceHeight);
-
- if (mRenderPreviewOverlayFile != null) {
- overlayData.set(BitmapFactory.decodeFile(mRenderPreviewOverlayFile),
- mRenderPreviewRenderingMode);
- } else {
- overlayData.setClear();
- }
- } catch (IllegalArgumentException ex) {
- Log.e(TAG, "Illegal Argument exception in nativeRenderPreviewFrame");
- throw ex;
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Illegal state exception in nativeRenderPreviewFrame");
- throw ex;
- } catch (RuntimeException ex) {
- Log.e(TAG, "Runtime exception in nativeRenderPreviewFrame");
- throw ex;
- }
-
- return timeMs;
- }
-
- private void previewFrameEditInfo(String filename, int renderingMode) {
- mRenderPreviewOverlayFile = filename;
- mRenderPreviewRenderingMode = renderingMode;
- }
-
-
- /**
- * This function is responsible for rendering a single frame
- * from a single media item on the surface
- *
- * @param surface The surface on which frame has to be rendered
- * @param filepath The file path for which the frame needs to be displayed
- * @param time The time in ms at which the frame has to be rendered
- * @param framewidth The frame width
- * @param framewidth The frame height
- *
- * @return The actual time from media item at which the frame was extracted
- * and rendered
- */
- long renderMediaItemPreviewFrame(Surface surface, String filepath,
- long time, int framewidth, int frameheight) {
- long timeMs = 0;
- try {
- timeMs = (long)nativeRenderMediaItemPreviewFrame(surface, filepath, framewidth,
- frameheight, 0, 0, time);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG, "Illegal Argument exception in renderMediaItemPreviewFrame");
- throw ex;
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Illegal state exception in renderMediaItemPreviewFrame");
- throw ex;
- } catch (RuntimeException ex) {
- Log.e(TAG, "Runtime exception in renderMediaItemPreviewFrame");
- throw ex;
- }
-
- return timeMs;
- }
-
- /**
- * This function sets the flag to invalidate the preview array
- * and for generating the preview again
- */
- void setGeneratePreview(boolean isRequired) {
- boolean semAcquiredDone = false;
- try {
- lock();
- semAcquiredDone = true;
- mInvalidatePreviewArray = isRequired;
- } catch (InterruptedException ex) {
- Log.e(TAG, "Runtime exception in renderMediaItemPreviewFrame");
- } finally {
- if (semAcquiredDone) {
- unlock();
- }
- }
- }
-
- /**
- * @return Returns the current status of preview invalidation
- * flag
- */
- boolean getGeneratePreview() {
- return mInvalidatePreviewArray;
- }
-
- /**
- * Calculates the aspect ratio from widht and height
- *
- * @param w The width of media item
- * @param h The height of media item
- *
- * @return The calculated aspect ratio
- */
- int getAspectRatio(int w, int h) {
- double apRatio = (double)(w) / (double)(h);
- BigDecimal bd = new BigDecimal(apRatio);
- bd = bd.setScale(3, BigDecimal.ROUND_HALF_UP);
- apRatio = bd.doubleValue();
- int var = MediaProperties.ASPECT_RATIO_16_9;
- if (apRatio >= 1.7) {
- var = MediaProperties.ASPECT_RATIO_16_9;
- } else if (apRatio >= 1.6) {
- var = MediaProperties.ASPECT_RATIO_5_3;
- } else if (apRatio >= 1.5) {
- var = MediaProperties.ASPECT_RATIO_3_2;
- } else if (apRatio > 1.3) {
- var = MediaProperties.ASPECT_RATIO_4_3;
- } else if (apRatio >= 1.2) {
- var = MediaProperties.ASPECT_RATIO_11_9;
- }
- return var;
- }
-
- /**
- * Maps the file type used in native layer
- * to file type used in JAVA layer
- *
- * @param fileType The file type in native layer
- *
- * @return The File type in JAVA layer
- */
- int getFileType(int fileType) {
- int retValue = -1;
- switch (fileType) {
- case FileType.UNSUPPORTED:
- retValue = MediaProperties.FILE_UNSUPPORTED;
- break;
- case FileType.THREE_GPP:
- retValue = MediaProperties.FILE_3GP;
- break;
- case FileType.MP4:
- retValue = MediaProperties.FILE_MP4;
- break;
- case FileType.JPG:
- retValue = MediaProperties.FILE_JPEG;
- break;
- case FileType.PNG:
- retValue = MediaProperties.FILE_PNG;
- break;
- case FileType.MP3:
- retValue = MediaProperties.FILE_MP3;
- break;
- case FileType.M4V:
- retValue = MediaProperties.FILE_M4V;
- break;
- case FileType.AMR:
- retValue = MediaProperties.FILE_AMR;
- break;
-
- default:
- retValue = -1;
- }
- return retValue;
- }
-
- /**
- * Maps the video codec type used in native layer
- * to video codec type used in JAVA layer
- *
- * @param codecType The video codec type in native layer
- *
- * @return The video codec type in JAVA layer
- */
- int getVideoCodecType(int codecType) {
- int retValue = -1;
- switch (codecType) {
- case VideoFormat.H263:
- retValue = MediaProperties.VCODEC_H263;
- break;
- case VideoFormat.H264:
- retValue = MediaProperties.VCODEC_H264;
- break;
- case VideoFormat.MPEG4:
- retValue = MediaProperties.VCODEC_MPEG4;
- break;
- case VideoFormat.UNSUPPORTED:
-
- default:
- retValue = -1;
- }
- return retValue;
- }
-
- /**
- * Maps the audio codec type used in native layer
- * to audio codec type used in JAVA layer
- *
- * @param audioType The audio codec type in native layer
- *
- * @return The audio codec type in JAVA layer
- */
- int getAudioCodecType(int codecType) {
- int retValue = -1;
- switch (codecType) {
- case AudioFormat.AMR_NB:
- retValue = MediaProperties.ACODEC_AMRNB;
- break;
- case AudioFormat.AAC:
- retValue = MediaProperties.ACODEC_AAC_LC;
- break;
- case AudioFormat.MP3:
- retValue = MediaProperties.ACODEC_MP3;
- break;
-
- default:
- retValue = -1;
- }
- return retValue;
- }
-
- /**
- * Returns the frame rate as integer
- *
- * @param fps The fps as enum
- *
- * @return The frame rate as integer
- */
- int getFrameRate(int fps) {
- int retValue = -1;
- switch (fps) {
- case VideoFrameRate.FR_5_FPS:
- retValue = 5;
- break;
- case VideoFrameRate.FR_7_5_FPS:
- retValue = 8;
- break;
- case VideoFrameRate.FR_10_FPS:
- retValue = 10;
- break;
- case VideoFrameRate.FR_12_5_FPS:
- retValue = 13;
- break;
- case VideoFrameRate.FR_15_FPS:
- retValue = 15;
- break;
- case VideoFrameRate.FR_20_FPS:
- retValue = 20;
- break;
- case VideoFrameRate.FR_25_FPS:
- retValue = 25;
- break;
- case VideoFrameRate.FR_30_FPS:
- retValue = 30;
- break;
-
- default:
- retValue = -1;
- }
- return retValue;
- }
-
- /**
- * Maps the file type used in JAVA layer
- * to file type used in native layer
- *
- * @param fileType The file type in JAVA layer
- *
- * @return The File type in native layer
- */
- int getMediaItemFileType(int fileType) {
- int retValue = -1;
-
- switch (fileType) {
- case MediaProperties.FILE_UNSUPPORTED:
- retValue = FileType.UNSUPPORTED;
- break;
- case MediaProperties.FILE_3GP:
- retValue = FileType.THREE_GPP;
- break;
- case MediaProperties.FILE_MP4:
- retValue = FileType.MP4;
- break;
- case MediaProperties.FILE_JPEG:
- retValue = FileType.JPG;
- break;
- case MediaProperties.FILE_PNG:
- retValue = FileType.PNG;
- break;
- case MediaProperties.FILE_M4V:
- retValue = FileType.M4V;
- break;
-
- default:
- retValue = -1;
- }
- return retValue;
-
- }
-
- /**
- * Maps the rendering mode used in native layer
- * to rendering mode used in JAVA layer
- *
- * @param renderingMode The rendering mode in JAVA layer
- *
- * @return The rendering mode in native layer
- */
- int getMediaItemRenderingMode(int renderingMode) {
- int retValue = -1;
- switch (renderingMode) {
- case MediaItem.RENDERING_MODE_BLACK_BORDER:
- retValue = MediaRendering.BLACK_BORDERS;
- break;
- case MediaItem.RENDERING_MODE_STRETCH:
- retValue = MediaRendering.RESIZING;
- break;
- case MediaItem.RENDERING_MODE_CROPPING:
- retValue = MediaRendering.CROPPING;
- break;
-
- default:
- retValue = -1;
- }
- return retValue;
- }
-
- /**
- * Maps the transition behavior used in JAVA layer
- * to transition behavior used in native layer
- *
- * @param transitionType The transition behavior in JAVA layer
- *
- * @return The transition behavior in native layer
- */
- int getVideoTransitionBehaviour(int transitionType) {
- int retValue = -1;
- switch (transitionType) {
- case Transition.BEHAVIOR_SPEED_UP:
- retValue = TransitionBehaviour.SPEED_UP;
- break;
- case Transition.BEHAVIOR_SPEED_DOWN:
- retValue = TransitionBehaviour.SPEED_DOWN;
- break;
- case Transition.BEHAVIOR_LINEAR:
- retValue = TransitionBehaviour.LINEAR;
- break;
- case Transition.BEHAVIOR_MIDDLE_SLOW:
- retValue = TransitionBehaviour.SLOW_MIDDLE;
- break;
- case Transition.BEHAVIOR_MIDDLE_FAST:
- retValue = TransitionBehaviour.FAST_MIDDLE;
- break;
-
- default:
- retValue = -1;
- }
- return retValue;
- }
-
- /**
- * Maps the transition slide direction used in JAVA layer
- * to transition slide direction used in native layer
- *
- * @param slideDirection The transition slide direction
- * in JAVA layer
- *
- * @return The transition slide direction in native layer
- */
- int getSlideSettingsDirection(int slideDirection) {
- int retValue = -1;
- switch (slideDirection) {
- case TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN:
- retValue = SlideDirection.RIGHT_OUT_LEFT_IN;
- break;
- case TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN:
- retValue = SlideDirection.LEFT_OUT_RIGTH_IN;
- break;
- case TransitionSliding.DIRECTION_TOP_OUT_BOTTOM_IN:
- retValue = SlideDirection.TOP_OUT_BOTTOM_IN;
- break;
- case TransitionSliding.DIRECTION_BOTTOM_OUT_TOP_IN:
- retValue = SlideDirection.BOTTOM_OUT_TOP_IN;
- break;
-
- default:
- retValue = -1;
- }
- return retValue;
- }
-
- /**
- * Maps the effect color type used in JAVA layer
- * to effect color type used in native layer
- *
- * @param effect The EffectColor reference
- *
- * @return The color effect value from native layer
- */
- private int getEffectColorType(EffectColor effect) {
- int retValue = -1;
- switch (effect.getType()) {
- case EffectColor.TYPE_COLOR:
- if (effect.getColor() == EffectColor.GREEN) {
- retValue = VideoEffect.GREEN;
- } else if (effect.getColor() == EffectColor.PINK) {
- retValue = VideoEffect.PINK;
- } else if (effect.getColor() == EffectColor.GRAY) {
- retValue = VideoEffect.BLACK_AND_WHITE;
- } else {
- retValue = VideoEffect.COLORRGB16;
- }
- break;
- case EffectColor.TYPE_GRADIENT:
- retValue = VideoEffect.GRADIENT;
- break;
- case EffectColor.TYPE_SEPIA:
- retValue = VideoEffect.SEPIA;
- break;
- case EffectColor.TYPE_NEGATIVE:
- retValue = VideoEffect.NEGATIVE;
- break;
- case EffectColor.TYPE_FIFTIES:
- retValue = VideoEffect.FIFTIES;
- break;
-
- default:
- retValue = -1;
- }
- return retValue;
- }
-
- /**
- * Calculates video resolution for output clip
- * based on clip's height and aspect ratio of storyboard
- *
- * @param aspectRatio The aspect ratio of story board
- * @param height The height of clip
- *
- * @return The video resolution
- */
- private int findVideoResolution(int aspectRatio, int height) {
- final Pair<Integer, Integer>[] resolutions;
- final Pair<Integer, Integer> maxResolution;
- int retValue = VideoFrameSize.SIZE_UNDEFINED;
- switch (aspectRatio) {
- case MediaProperties.ASPECT_RATIO_3_2:
- if (height == MediaProperties.HEIGHT_480)
- retValue = VideoFrameSize.NTSC;
- else if (height == MediaProperties.HEIGHT_720)
- retValue = VideoFrameSize.W720p;
- break;
- case MediaProperties.ASPECT_RATIO_16_9:
- if (height == MediaProperties.HEIGHT_480)
- retValue = VideoFrameSize.WVGA16x9;
- else if (height == MediaProperties.HEIGHT_720)
- retValue = VideoFrameSize.V720p;
- else if (height == MediaProperties.HEIGHT_1080)
- retValue = VideoFrameSize.V1080p;
- break;
- case MediaProperties.ASPECT_RATIO_4_3:
- if (height == MediaProperties.HEIGHT_480)
- retValue = VideoFrameSize.VGA;
- else if (height == MediaProperties.HEIGHT_720)
- retValue = VideoFrameSize.S720p;
- break;
- case MediaProperties.ASPECT_RATIO_5_3:
- if (height == MediaProperties.HEIGHT_480)
- retValue = VideoFrameSize.WVGA;
- break;
- case MediaProperties.ASPECT_RATIO_11_9:
- if (height == MediaProperties.HEIGHT_144)
- retValue = VideoFrameSize.QCIF;
- else if (height == MediaProperties.HEIGHT_288)
- retValue = VideoFrameSize.CIF;
- break;
- }
- if (retValue == VideoFrameSize.SIZE_UNDEFINED) {
- resolutions = MediaProperties.getSupportedResolutions(mVideoEditor.getAspectRatio());
- // Get the highest resolution
- maxResolution = resolutions[resolutions.length - 1];
- retValue = findVideoResolution(mVideoEditor.getAspectRatio(), maxResolution.second);
- }
-
- return retValue;
- }
-
- /**
- * Calculate a reasonable bitrate for generating intermediate clips.
- */
- private int findVideoBitrate(int videoFrameSize) {
- switch (videoFrameSize) {
- case VideoFrameSize.SQCIF:
- case VideoFrameSize.QQVGA:
- case VideoFrameSize.QCIF:
- return Bitrate.BR_128_KBPS;
- case VideoFrameSize.QVGA:
- case VideoFrameSize.CIF:
- return Bitrate.BR_384_KBPS;
- case VideoFrameSize.VGA:
- case VideoFrameSize.WVGA:
- case VideoFrameSize.NTSC:
- case VideoFrameSize.nHD:
- case VideoFrameSize.WVGA16x9:
- return Bitrate.BR_2_MBPS;
- case VideoFrameSize.V720p:
- case VideoFrameSize.W720p:
- case VideoFrameSize.S720p:
- return Bitrate.BR_5_MBPS;
- case VideoFrameSize.V1080p:
- default:
- return Bitrate.BR_8_MBPS;
- }
- }
-
- /**
- * This method is responsible for exporting a movie
- *
- * @param filePath The output file path
- * @param projectDir The output project directory
- * @param height The height of clip
- * @param bitrate The bitrate at which the movie should be exported
- * @param mediaItemsList The media items list
- * @param mediaTransitionList The transitions list
- * @param mediaBGMList The background track list
- * @param listener The ExportProgressListener
- *
- */
- void export(String filePath, String projectDir, int height, int bitrate,
- List<MediaItem> mediaItemsList, List<Transition> mediaTransitionList,
- List<AudioTrack> mediaBGMList, ExportProgressListener listener) {
-
- int outBitrate = 0;
- mExportFilename = filePath;
- previewStoryBoard(mediaItemsList, mediaTransitionList, mediaBGMList,null);
- mExportProgressListener = listener;
- int outVideoProfile = 0;
- int outVideoLevel = 0;
-
- /** Check the platform specific maximum export resolution */
- VideoEditorProfile veProfile = VideoEditorProfile.get();
- if (veProfile == null) {
- throw new RuntimeException("Can't get the video editor profile");
- }
- final int maxOutputHeight = veProfile.maxOutputVideoFrameHeight;
- final int maxOutputWidth = veProfile.maxOutputVideoFrameWidth;
- if (height > maxOutputHeight) {
- throw new IllegalArgumentException(
- "Unsupported export resolution. Supported maximum width:" +
- maxOutputWidth + " height:" + maxOutputHeight +
- " current height:" + height);
- }
- outVideoProfile = VideoEditorProfile.getExportProfile(mExportVideoCodec);
- outVideoLevel = VideoEditorProfile.getExportLevel(mExportVideoCodec);
-
- mProgressToApp = 0;
-
- switch (bitrate) {
- case MediaProperties.BITRATE_28K:
- outBitrate = Bitrate.BR_32_KBPS;
- break;
- case MediaProperties.BITRATE_40K:
- outBitrate = Bitrate.BR_48_KBPS;
- break;
- case MediaProperties.BITRATE_64K:
- outBitrate = Bitrate.BR_64_KBPS;
- break;
- case MediaProperties.BITRATE_96K:
- outBitrate = Bitrate.BR_96_KBPS;
- break;
- case MediaProperties.BITRATE_128K:
- outBitrate = Bitrate.BR_128_KBPS;
- break;
- case MediaProperties.BITRATE_192K:
- outBitrate = Bitrate.BR_192_KBPS;
- break;
- case MediaProperties.BITRATE_256K:
- outBitrate = Bitrate.BR_256_KBPS;
- break;
- case MediaProperties.BITRATE_384K:
- outBitrate = Bitrate.BR_384_KBPS;
- break;
- case MediaProperties.BITRATE_512K:
- outBitrate = Bitrate.BR_512_KBPS;
- break;
- case MediaProperties.BITRATE_800K:
- outBitrate = Bitrate.BR_800_KBPS;
- break;
- case MediaProperties.BITRATE_2M:
- outBitrate = Bitrate.BR_2_MBPS;
- break;
- case MediaProperties.BITRATE_5M:
- outBitrate = Bitrate.BR_5_MBPS;
- break;
- case MediaProperties.BITRATE_8M:
- outBitrate = Bitrate.BR_8_MBPS;
- break;
-
- default:
- throw new IllegalArgumentException("Argument Bitrate incorrect");
- }
- mPreviewEditSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
- mPreviewEditSettings.outputFile = mOutputFilename = filePath;
-
- int aspectRatio = mVideoEditor.getAspectRatio();
- mPreviewEditSettings.videoFrameSize = findVideoResolution(aspectRatio, height);
- mPreviewEditSettings.videoFormat = mExportVideoCodec;
- mPreviewEditSettings.audioFormat = mExportAudioCodec;
- mPreviewEditSettings.videoProfile = outVideoProfile;
- mPreviewEditSettings.videoLevel = outVideoLevel;
- mPreviewEditSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
- mPreviewEditSettings.maxFileSize = 0;
- mPreviewEditSettings.audioChannels = 2;
- mPreviewEditSettings.videoBitrate = outBitrate;
- mPreviewEditSettings.audioBitrate = Bitrate.BR_96_KBPS;
-
- mPreviewEditSettings.transitionSettingsArray = new TransitionSettings[mTotalClips - 1];
- for (int index = 0; index < mTotalClips - 1; index++) {
- mPreviewEditSettings.transitionSettingsArray[index] = new TransitionSettings();
- mPreviewEditSettings.transitionSettingsArray[index].videoTransitionType =
- VideoTransition.NONE;
- mPreviewEditSettings.transitionSettingsArray[index].audioTransitionType =
- AudioTransition.NONE;
- }
-
- for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length; clipCnt++) {
- if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
- mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
- mPreviewEditSettings.clipSettingsArray[clipCnt].clipOriginalPath;
- }
- }
- nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
-
- int err = 0;
- try {
- mProcessingState = PROCESSING_EXPORT;
- mProcessingObject = null;
- err = generateClip(mPreviewEditSettings);
- mProcessingState = PROCESSING_NONE;
- } catch (IllegalArgumentException ex) {
- Log.e(TAG, "IllegalArgument for generateClip");
- throw ex;
- } catch (IllegalStateException ex) {
- Log.e(TAG, "IllegalStateExceptiont for generateClip");
- throw ex;
- } catch (RuntimeException ex) {
- Log.e(TAG, "RuntimeException for generateClip");
- throw ex;
- }
-
- if (err != 0) {
- Log.e(TAG, "RuntimeException for generateClip");
- throw new RuntimeException("generateClip failed with error=" + err);
- }
-
- mExportProgressListener = null;
- }
-
- /**
- * This methods takes care of stopping the Export process
- *
- * @param The input file name for which export has to be stopped
- */
- void stop(String filename) {
- try {
- stopEncoding();
- new File(mExportFilename).delete();
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Illegal state exception in unload settings");
- throw ex;
- } catch (RuntimeException ex) {
- Log.e(TAG, "Runtime exception in unload settings");
- throw ex;
- }
- }
-
- /**
- * This method extracts a frame from the input file
- * and returns the frame as a bitmap. See getPixelsList() for more information.
- */
- Bitmap getPixels(String filename, int width, int height, long timeMs,
- int videoRotation) {
- final Bitmap result[] = new Bitmap[1];
- getPixelsList(filename, width, height, timeMs, timeMs, 1, new int[] {0},
- new MediaItem.GetThumbnailListCallback() {
- public void onThumbnail(Bitmap bitmap, int index) {
- result[0] = bitmap;
- }
- }, videoRotation);
- return result[0];
- }
-
- /**
- * This method extracts a list of frame from the
- * input file and returns the frame in bitmap array
- *
- * @param filename The input file name
- * @param width The width of the output frame, before rotation
- * @param height The height of the output frame, before rotation
- * @param startMs The starting time in ms
- * @param endMs The end time in ms
- * @param thumbnailCount The number of frames to be extracted
- * @param indices The indices of thumbnails wanted
- * @param callback The callback used to pass back the bitmaps
- * @param videoRotation The rotation degree need to be done for the bitmap
- *
- * @return The frames as bitmaps in bitmap array
- **/
- void getPixelsList(String filename, final int width, final int height,
- long startMs, long endMs, int thumbnailCount, int[] indices,
- final MediaItem.GetThumbnailListCallback callback,
- final int videoRotation) {
-
- // The decoder needs output width and height as even
- final int decWidth = (width + 1) & 0xFFFFFFFE;
- final int decHeight = (height + 1) & 0xFFFFFFFE;
- final int thumbnailSize = decWidth * decHeight;
-
- // We convert the decoder output (in int[]) to a bitmap by first
- // copy it into an IntBuffer, then use Bitmap.copyPixelsFromBuffer to
- // copy it to the bitmap.
- final int[] decArray = new int[thumbnailSize];
- final IntBuffer decBuffer = IntBuffer.allocate(thumbnailSize);
-
- // If we need to resize and/or rotate the decoder output, we need a
- // temporary bitmap to hold the decoded output.
- final boolean needToMassage =
- (decWidth != width || decHeight != height || videoRotation != 0);
- final Bitmap tmpBitmap = needToMassage
- ? Bitmap.createBitmap(decWidth, decHeight, Bitmap.Config.ARGB_8888)
- : null;
-
- // The final output bitmap width/height may swap because of rotation.
- final boolean needToSwapWH = (videoRotation == 90 || videoRotation == 270);
- final int outWidth = needToSwapWH ? height : width;
- final int outHeight = needToSwapWH ? width : height;
-
- nativeGetPixelsList(filename, decArray, decWidth, decHeight,
- thumbnailCount, startMs, endMs, indices,
- new NativeGetPixelsListCallback() {
- public void onThumbnail(int index) {
- // This is the bitmap we will output to the client
- Bitmap outBitmap = Bitmap.createBitmap(
- outWidth, outHeight, Bitmap.Config.ARGB_8888);
-
- // Copy int[] to IntBuffer
- decBuffer.rewind();
- decBuffer.put(decArray, 0, thumbnailSize);
- decBuffer.rewind();
-
- if (!needToMassage) {
- // We can directly read the decoded result to output bitmap
- outBitmap.copyPixelsFromBuffer(decBuffer);
- } else {
- // Copy the decoded result to an intermediate bitmap first
- tmpBitmap.copyPixelsFromBuffer(decBuffer);
-
- // Create a canvas to resize/rotate the bitmap
- // First scale the decoded bitmap to (0,0)-(1,1), rotate it
- // with (0.5, 0.5) as center, then scale it to
- // (outWidth, outHeight).
- final Canvas canvas = new Canvas(outBitmap);
- Matrix m = new Matrix();
- float sx = 1f / decWidth;
- float sy = 1f / decHeight;
- m.postScale(sx, sy);
- m.postRotate(videoRotation, 0.5f, 0.5f);
- m.postScale(outWidth, outHeight);
- canvas.drawBitmap(tmpBitmap, m, sResizePaint);
- }
- callback.onThumbnail(outBitmap, index);
- }
- });
-
- if (tmpBitmap != null) {
- tmpBitmap.recycle();
- }
- }
-
- interface NativeGetPixelsListCallback {
- public void onThumbnail(int index);
- }
-
- /**
- * This method generates the audio graph
- *
- * @param uniqueId The unique id
- * @param inFileName The inputFile
- * @param OutAudiGraphFileName output filename
- * @param frameDuration The each frame duration
- * @param audioChannels The number of audio channels
- * @param samplesCount Total number of samples count
- * @param listener ExtractAudioWaveformProgressListener reference
- * @param isVideo The flag to indicate if the file is video file or not
- *
- **/
- void generateAudioGraph(String uniqueId, String inFileName, String OutAudiGraphFileName,
- int frameDuration, int audioChannels, int samplesCount,
- ExtractAudioWaveformProgressListener listener, boolean isVideo) {
- String tempPCMFileName;
-
- mExtractAudioWaveformProgressListener = listener;
-
- /**
- * In case of Video, first call will generate the PCM file to make the
- * audio graph
- */
- if (isVideo) {
- tempPCMFileName = String.format(mProjectPath + "/" + uniqueId + ".pcm");
- } else {
- tempPCMFileName = mAudioTrackPCMFilePath;
- }
-
- /**
- * For Video item, generate the PCM
- */
- if (isVideo) {
- nativeGenerateRawAudio(inFileName, tempPCMFileName);
- }
-
- nativeGenerateAudioGraph(tempPCMFileName, OutAudiGraphFileName, frameDuration,
- audioChannels, samplesCount);
-
- /**
- * Once the audio graph file is generated, delete the pcm file
- */
- if (isVideo) {
- new File(tempPCMFileName).delete();
- }
- }
-
- void clearPreviewSurface(Surface surface) {
- nativeClearSurface(surface);
- }
-
- /**
- * Grab the semaphore which arbitrates access to the editor
- *
- * @throws InterruptedException
- */
- private void lock() throws InterruptedException {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "lock: grabbing semaphore", new Throwable());
- }
- mLock.acquire();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "lock: grabbed semaphore");
- }
- }
-
- /**
- * Release the semaphore which arbitrates access to the editor
- */
- private void unlock() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "unlock: releasing semaphore");
- }
- mLock.release();
- }
-
- /** Native Methods */
- native Properties getMediaProperties(String file) throws IllegalArgumentException,
- IllegalStateException, RuntimeException, Exception;
-
- /**
- * Get the version of ManualEdit.
- *
- * @return version of ManualEdit
- * @throws RuntimeException if an error occurred
- * @see Version
- */
- private static native Version getVersion() throws RuntimeException;
-
- /**
- * Returns the video thumbnail in an array of integers. Output format is
- * ARGB8888.
- *
- * @param pixelArray the array that receives the pixel values
- * @param width width of the video thumbnail
- * @param height height of the video thumbnail
- * @param timeMS desired time of the thumbnail in ms
- * @return actual time in ms of the thumbnail generated
- * @throws IllegalStateException if the class has not been initialized
- * @throws IllegalArgumentException if the pixelArray is not available or
- * one of the dimensions is negative or zero or the time is
- * negative
- * @throws RuntimeException on runtime errors in native code
- */
- private native int nativeGetPixels(String fileName, int[] pixelArray, int width, int height,
- long timeMS);
-
- private native int nativeGetPixelsList(String fileName, int[] pixelArray,
- int width, int height, int nosofTN, long startTimeMs,
- long endTimeMs, int[] indices, NativeGetPixelsListCallback callback);
-
- /**
- * Releases the JNI and cleans up the core native module.. Should be called
- * only after init( )
- *
- * @throws IllegalStateException if the method could not be called
- */
- private native void release() throws IllegalStateException, RuntimeException;
-
- /*
- * Clear the preview surface
- */
- private native void nativeClearSurface(Surface surface);
-
- /**
- * Stops the encoding. This method should only be called after encoding has
- * started using method <code> startEncoding</code>
- *
- * @throws IllegalStateException if the method could not be called
- */
- private native void stopEncoding() throws IllegalStateException, RuntimeException;
-
-
- private native void _init(String tempPath, String libraryPath)
- throws IllegalArgumentException, IllegalStateException, RuntimeException;
-
- private native void nativeStartPreview(Surface mSurface, long fromMs, long toMs,
- int callbackAfterFrameCount, boolean loop) throws IllegalArgumentException,
- IllegalStateException, RuntimeException;
-
- private native void nativePopulateSettings(EditSettings editSettings,
- PreviewClipProperties mProperties, AudioSettings mAudioSettings)
- throws IllegalArgumentException, IllegalStateException, RuntimeException;
-
- private native int nativeRenderPreviewFrame(Surface mSurface, long timeMs,
- int surfaceWidth, int surfaceHeight)
- throws IllegalArgumentException,
- IllegalStateException, RuntimeException;
-
- private native int nativeRenderMediaItemPreviewFrame(Surface mSurface, String filepath,
- int framewidth, int frameheight, int surfacewidth, int surfaceheight, long timeMs)
- throws IllegalArgumentException, IllegalStateException, RuntimeException;
-
- private native int nativeStopPreview();
-
- private native int nativeGenerateAudioGraph(String pcmFilePath, String outGraphPath,
- int frameDuration, int channels, int sampleCount);
-
- private native int nativeGenerateRawAudio(String InFileName, String PCMFileName);
-
- private native int nativeGenerateClip(EditSettings editSettings)
- throws IllegalArgumentException, IllegalStateException, RuntimeException;
-
-}
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
deleted file mode 100644
index 590b4ae..0000000
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ /dev/null
@@ -1,1021 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.media.videoeditor;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import java.util.ArrayList;
-import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.EditSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.FileType;
-import android.media.videoeditor.MediaArtistNativeHelper.Properties;
-import android.util.Log;
-import android.util.Pair;
-
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-import java.lang.Math;
-import java.util.List;
-
-/**
- * This class represents an image item on the storyboard. Note that images are
- * scaled down to the maximum supported resolution by preserving the native
- * aspect ratio. To learn the scaled image dimensions use
- * {@link #getScaledWidth()} and {@link #getScaledHeight()} respectively.
- *
- * {@hide}
- */
-public class MediaImageItem extends MediaItem {
- /**
- * Logging
- */
- private static final String TAG = "MediaImageItem";
-
- /**
- * The resize paint
- */
- private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-
- /**
- * Instance variables
- */
- private final int mWidth;
- private final int mHeight;
- private final int mAspectRatio;
- private long mDurationMs;
- private int mScaledWidth, mScaledHeight;
- private String mScaledFilename;
- private final VideoEditorImpl mVideoEditor;
- private String mDecodedFilename;
- private int mGeneratedClipHeight;
- private int mGeneratedClipWidth;
- private String mFileName;
-
- private final MediaArtistNativeHelper mMANativeHelper;
-
- /**
- * This class cannot be instantiated by using the default constructor
- */
- @SuppressWarnings("unused")
- private MediaImageItem() throws IOException {
- this(null, null, null, 0, RENDERING_MODE_BLACK_BORDER);
- }
-
- /**
- * Constructor
- *
- * @param editor The video editor reference
- * @param mediaItemId The media item id
- * @param filename The image file name
- * @param durationMs The duration of the image on the storyboard
- * @param renderingMode The rendering mode
- *
- * @throws IOException
- */
- public MediaImageItem(VideoEditor editor, String mediaItemId, String filename, long durationMs,
- int renderingMode) throws IOException {
-
- super(editor, mediaItemId, filename, renderingMode);
-
- mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
- mVideoEditor = ((VideoEditorImpl)editor);
- try {
- final Properties properties = mMANativeHelper.getMediaProperties(filename);
-
- switch (mMANativeHelper.getFileType(properties.fileType)) {
- case MediaProperties.FILE_JPEG:
- case MediaProperties.FILE_PNG: {
- break;
- }
-
- default: {
- throw new IllegalArgumentException("Unsupported Input File Type");
- }
- }
- } catch (Exception e) {
- throw new IllegalArgumentException("Unsupported file or file not found: " + filename);
- }
- mFileName = filename;
- /**
- * Determine the dimensions of the image
- */
- final BitmapFactory.Options dbo = new BitmapFactory.Options();
- dbo.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(filename, dbo);
-
- mWidth = dbo.outWidth;
- mHeight = dbo.outHeight;
- mDurationMs = durationMs;
- mDecodedFilename = String.format(mMANativeHelper.getProjectPath() +
- "/" + "decoded" + getId()+ ".rgb");
-
- try {
- mAspectRatio = mMANativeHelper.getAspectRatio(mWidth, mHeight);
- } catch(IllegalArgumentException e) {
- throw new IllegalArgumentException ("Null width and height");
- }
-
- mGeneratedClipHeight = 0;
- mGeneratedClipWidth = 0;
-
- /**
- * Images are stored in memory scaled to the maximum resolution to
- * save memory.
- */
- final Pair<Integer, Integer>[] resolutions =
- MediaProperties.getSupportedResolutions(mAspectRatio);
-
- /**
- * Get the highest resolution
- */
- final Pair<Integer, Integer> maxResolution = resolutions[resolutions.length - 1];
-
- final Bitmap imageBitmap;
-
- if (mWidth > maxResolution.first || mHeight > maxResolution.second) {
- /**
- * We need to scale the image
- */
- imageBitmap = scaleImage(filename, maxResolution.first,
- maxResolution.second);
- mScaledFilename = String.format(mMANativeHelper.getProjectPath() +
- "/" + "scaled" + getId()+ ".JPG");
- if (!((new File(mScaledFilename)).exists())) {
- super.mRegenerateClip = true;
- final FileOutputStream f1 = new FileOutputStream(mScaledFilename);
- imageBitmap.compress(Bitmap.CompressFormat.JPEG, 50,f1);
- f1.close();
- }
- mScaledWidth = (imageBitmap.getWidth() >> 1) << 1;
- mScaledHeight = (imageBitmap.getHeight() >> 1) << 1;
- } else {
- mScaledFilename = filename;
- mScaledWidth = (mWidth >> 1) << 1;
- mScaledHeight = (mHeight >> 1) << 1;
- imageBitmap = BitmapFactory.decodeFile(mScaledFilename);
- }
- int newWidth = mScaledWidth;
- int newHeight = mScaledHeight;
- if (!((new File(mDecodedFilename)).exists())) {
- final FileOutputStream fl = new FileOutputStream(mDecodedFilename);
- final DataOutputStream dos = new DataOutputStream(fl);
- final int [] framingBuffer = new int[newWidth];
- final ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
- IntBuffer intBuffer;
- final byte[] array = byteBuffer.array();
- int tmp = 0;
- while (tmp < newHeight) {
- imageBitmap.getPixels(framingBuffer, 0, mScaledWidth, 0,
- tmp, newWidth, 1);
- intBuffer = byteBuffer.asIntBuffer();
- intBuffer.put(framingBuffer, 0, newWidth);
- dos.write(array);
- tmp += 1;
- }
- fl.close();
- }
- imageBitmap.recycle();
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int getFileType() {
- if (mFilename.endsWith(".jpg") || mFilename.endsWith(".jpeg")
- || mFilename.endsWith(".JPG") || mFilename.endsWith(".JPEG")) {
- return MediaProperties.FILE_JPEG;
- } else if (mFilename.endsWith(".png") || mFilename.endsWith(".PNG")) {
- return MediaProperties.FILE_PNG;
- } else {
- return MediaProperties.FILE_UNSUPPORTED;
- }
- }
-
- /**
- * @return The scaled image file name
- */
- String getScaledImageFileName() {
- return mScaledFilename;
- }
-
- /**
- * @return The generated Kenburns clip height.
- */
- int getGeneratedClipHeight() {
- return mGeneratedClipHeight;
- }
-
- /**
- * @return The generated Kenburns clip width.
- */
- int getGeneratedClipWidth() {
- return mGeneratedClipWidth;
- }
-
- /**
- * @return The file name of image which is decoded and stored
- * in RGB format
- */
- String getDecodedImageFileName() {
- return mDecodedFilename;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int getWidth() {
- return mWidth;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int getHeight() {
- return mHeight;
- }
-
- /**
- * @return The scaled width of the image.
- */
- public int getScaledWidth() {
- return mScaledWidth;
- }
-
- /**
- * @return The scaled height of the image.
- */
- public int getScaledHeight() {
- return mScaledHeight;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int getAspectRatio() {
- return mAspectRatio;
- }
-
- /**
- * This method will adjust the duration of bounding transitions, effects
- * and overlays if the current duration of the transactions become greater
- * than the maximum allowable duration.
- *
- * @param durationMs The duration of the image in the storyboard timeline
- */
- public void setDuration(long durationMs) {
- if (durationMs == mDurationMs) {
- return;
- }
-
- mMANativeHelper.setGeneratePreview(true);
-
- /**
- * Invalidate the end transitions if necessary.
- * This invalidation is necessary for the case in which an effect or
- * an overlay is overlapping with the end transition
- * (before the duration is changed) and it no longer overlaps with the
- * transition after the duration is increased.
- *
- * The beginning transition does not need to be invalidated at this time
- * because an effect or an overlay overlaps with the beginning
- * transition, the begin transition is unaffected by a media item
- * duration change.
- */
- invalidateEndTransition();
-
- mDurationMs = durationMs;
-
- adjustTransitions();
- final List<Overlay> adjustedOverlays = adjustOverlays();
- final List<Effect> adjustedEffects = adjustEffects();
-
- /**
- * Invalidate the beginning and end transitions after adjustments.
- * This invalidation is necessary for the case in which an effect or
- * an overlay was not overlapping with the beginning or end transitions
- * before the setDuration reduces the duration of the media item and
- * causes an overlap of the beginning and/or end transition with the
- * effect.
- */
- invalidateBeginTransition(adjustedEffects, adjustedOverlays);
- invalidateEndTransition();
- if (getGeneratedImageClip() != null) {
- /*
- * Delete the file
- */
- new File(getGeneratedImageClip()).delete();
- /*
- * Invalidate the filename
- */
- setGeneratedImageClip(null);
- super.setRegenerateClip(true);
- }
- mVideoEditor.updateTimelineDuration();
- }
-
- /**
- * Invalidate the begin transition if any effects and overlays overlap
- * with the begin transition.
- *
- * @param effects List of effects to check for transition overlap
- * @param overlays List of overlays to check for transition overlap
- */
- private void invalidateBeginTransition(List<Effect> effects, List<Overlay> overlays) {
- if (mBeginTransition != null && mBeginTransition.isGenerated()) {
- final long transitionDurationMs = mBeginTransition.getDuration();
-
- /**
- * The begin transition must be invalidated if it overlaps with
- * an effect.
- */
- for (Effect effect : effects) {
- /**
- * Check if the effect overlaps with the begin transition
- */
- if (effect.getStartTime() < transitionDurationMs) {
- mBeginTransition.invalidate();
- break;
- }
- }
-
- if (mBeginTransition.isGenerated()) {
- /**
- * The end transition must be invalidated if it overlaps with
- * an overlay.
- */
- for (Overlay overlay : overlays) {
- /**
- * Check if the overlay overlaps with the end transition
- */
- if (overlay.getStartTime() < transitionDurationMs) {
- mBeginTransition.invalidate();
- break;
- }
- }
- }
- }
- }
-
- /**
- * Invalidate the end transition if any effects and overlays overlap
- * with the end transition.
- */
- private void invalidateEndTransition() {
- if (mEndTransition != null && mEndTransition.isGenerated()) {
- final long transitionDurationMs = mEndTransition.getDuration();
-
- /**
- * The end transition must be invalidated if it overlaps with
- * an effect.
- */
- final List<Effect> effects = getAllEffects();
- for (Effect effect : effects) {
- /**
- * Check if the effect overlaps with the end transition
- */
- if (effect.getStartTime() + effect.getDuration() >
- mDurationMs - transitionDurationMs) {
- mEndTransition.invalidate();
- break;
- }
- }
-
- if (mEndTransition.isGenerated()) {
- /**
- * The end transition must be invalidated if it overlaps with
- * an overlay.
- */
- final List<Overlay> overlays = getAllOverlays();
- for (Overlay overlay : overlays) {
- /**
- * Check if the overlay overlaps with the end transition
- */
- if (overlay.getStartTime() + overlay.getDuration() >
- mDurationMs - transitionDurationMs) {
- mEndTransition.invalidate();
- break;
- }
- }
- }
- }
- }
-
- /**
- * Adjust the start time and/or duration of effects.
- *
- * @return The list of effects which were adjusted
- */
- private List<Effect> adjustEffects() {
- final List<Effect> adjustedEffects = new ArrayList<Effect>();
- final List<Effect> effects = getAllEffects();
- for (Effect effect : effects) {
- /**
- * Adjust the start time if necessary
- */
- final long effectStartTimeMs;
- if (effect.getStartTime() > getDuration()) {
- effectStartTimeMs = 0;
- } else {
- effectStartTimeMs = effect.getStartTime();
- }
-
- /**
- * Adjust the duration if necessary
- */
- final long effectDurationMs;
- if (effectStartTimeMs + effect.getDuration() > getDuration()) {
- effectDurationMs = getDuration() - effectStartTimeMs;
- } else {
- effectDurationMs = effect.getDuration();
- }
-
- if (effectStartTimeMs != effect.getStartTime() ||
- effectDurationMs != effect.getDuration()) {
- effect.setStartTimeAndDuration(effectStartTimeMs, effectDurationMs);
- adjustedEffects.add(effect);
- }
- }
-
- return adjustedEffects;
- }
-
- /**
- * Adjust the start time and/or duration of overlays.
- *
- * @return The list of overlays which were adjusted
- */
- private List<Overlay> adjustOverlays() {
- final List<Overlay> adjustedOverlays = new ArrayList<Overlay>();
- final List<Overlay> overlays = getAllOverlays();
- for (Overlay overlay : overlays) {
- /**
- * Adjust the start time if necessary
- */
- final long overlayStartTimeMs;
- if (overlay.getStartTime() > getDuration()) {
- overlayStartTimeMs = 0;
- } else {
- overlayStartTimeMs = overlay.getStartTime();
- }
-
- /**
- * Adjust the duration if necessary
- */
- final long overlayDurationMs;
- if (overlayStartTimeMs + overlay.getDuration() > getDuration()) {
- overlayDurationMs = getDuration() - overlayStartTimeMs;
- } else {
- overlayDurationMs = overlay.getDuration();
- }
-
- if (overlayStartTimeMs != overlay.getStartTime() ||
- overlayDurationMs != overlay.getDuration()) {
- overlay.setStartTimeAndDuration(overlayStartTimeMs, overlayDurationMs);
- adjustedOverlays.add(overlay);
- }
- }
-
- return adjustedOverlays;
- }
- /**
- * This function get the proper width by given aspect ratio
- * and height.
- *
- * @param aspectRatio Given aspect ratio
- * @param height Given height
- */
- private int getWidthByAspectRatioAndHeight(int aspectRatio, int height) {
- int width = 0;
-
- switch (aspectRatio) {
- case MediaProperties.ASPECT_RATIO_3_2:
- if (height == MediaProperties.HEIGHT_480)
- width = 720;
- else if (height == MediaProperties.HEIGHT_720)
- width = 1080;
- break;
-
- case MediaProperties.ASPECT_RATIO_16_9:
- if (height == MediaProperties.HEIGHT_360)
- width = 640;
- else if (height == MediaProperties.HEIGHT_480)
- width = 854;
- else if (height == MediaProperties.HEIGHT_720)
- width = 1280;
- else if (height == MediaProperties.HEIGHT_1080)
- width = 1920;
- break;
-
- case MediaProperties.ASPECT_RATIO_4_3:
- if (height == MediaProperties.HEIGHT_480)
- width = 640;
- if (height == MediaProperties.HEIGHT_720)
- width = 960;
- break;
-
- case MediaProperties.ASPECT_RATIO_5_3:
- if (height == MediaProperties.HEIGHT_480)
- width = 800;
- break;
-
- case MediaProperties.ASPECT_RATIO_11_9:
- if (height == MediaProperties.HEIGHT_144)
- width = 176;
- break;
-
- default : {
- throw new IllegalArgumentException(
- "Illegal arguments for aspectRatio");
- }
- }
-
- return width;
- }
-
- /**
- * This function sets the Ken Burn effect generated clip
- * name.
- *
- * @param generatedFilePath The name of the generated clip
- */
- @Override
- void setGeneratedImageClip(String generatedFilePath) {
- super.setGeneratedImageClip(generatedFilePath);
-
- // set the Kenburns clip width and height
- mGeneratedClipHeight = getScaledHeight();
- mGeneratedClipWidth = getWidthByAspectRatioAndHeight(
- mVideoEditor.getAspectRatio(), mGeneratedClipHeight);
- }
-
- /**
- * @return The name of the image clip
- * generated with ken burns effect.
- */
- @Override
- String getGeneratedImageClip() {
- return super.getGeneratedImageClip();
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public long getDuration() {
- return mDurationMs;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public long getTimelineDuration() {
- return mDurationMs;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public Bitmap getThumbnail(int width, int height, long timeMs) throws IOException {
- if (getGeneratedImageClip() != null) {
- return mMANativeHelper.getPixels(getGeneratedImageClip(),
- width, height, timeMs, 0);
- } else {
- return scaleImage(mFilename, width, height);
- }
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public void getThumbnailList(int width, int height,
- long startMs, long endMs,
- int thumbnailCount,
- int[] indices,
- GetThumbnailListCallback callback)
- throws IOException {
- //KenBurns was not applied on this.
- if (getGeneratedImageClip() == null) {
- final Bitmap thumbnail = scaleImage(mFilename, width, height);
- for (int i = 0; i < indices.length; i++) {
- callback.onThumbnail(thumbnail, indices[i]);
- }
- } else {
- if (startMs > endMs) {
- throw new IllegalArgumentException("Start time is greater than end time");
- }
-
- if (endMs > mDurationMs) {
- throw new IllegalArgumentException("End time is greater than file duration");
- }
-
- mMANativeHelper.getPixelsList(getGeneratedImageClip(), width,
- height, startMs, endMs, thumbnailCount, indices, callback, 0);
- }
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- void invalidateTransitions(long startTimeMs, long durationMs) {
- /**
- * Check if the item overlaps with the beginning and end transitions
- */
- if (mBeginTransition != null) {
- if (isOverlapping(startTimeMs, durationMs, 0, mBeginTransition.getDuration())) {
- mBeginTransition.invalidate();
- }
- }
-
- if (mEndTransition != null) {
- final long transitionDurationMs = mEndTransition.getDuration();
- if (isOverlapping(startTimeMs, durationMs,
- getDuration() - transitionDurationMs, transitionDurationMs)) {
- mEndTransition.invalidate();
- }
- }
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,
- long newDurationMs) {
- /**
- * Check if the item overlaps with the beginning and end transitions
- */
- if (mBeginTransition != null) {
- final long transitionDurationMs = mBeginTransition.getDuration();
- final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs, 0,
- transitionDurationMs);
- final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs, 0,
- transitionDurationMs);
- /**
- * Invalidate transition if:
- *
- * 1. New item overlaps the transition, the old one did not
- * 2. New item does not overlap the transition, the old one did
- * 3. New and old item overlap the transition if begin or end
- * time changed
- */
- if (newOverlap != oldOverlap) { // Overlap has changed
- mBeginTransition.invalidate();
- } else if (newOverlap) { // Both old and new overlap
- if ((oldStartTimeMs != newStartTimeMs) ||
- !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
- newStartTimeMs + newDurationMs > transitionDurationMs)) {
- mBeginTransition.invalidate();
- }
- }
- }
-
- if (mEndTransition != null) {
- final long transitionDurationMs = mEndTransition.getDuration();
- final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
- mDurationMs - transitionDurationMs, transitionDurationMs);
- final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
- mDurationMs - transitionDurationMs, transitionDurationMs);
- /**
- * Invalidate transition if:
- *
- * 1. New item overlaps the transition, the old one did not
- * 2. New item does not overlap the transition, the old one did
- * 3. New and old item overlap the transition if begin or end
- * time changed
- */
- if (newOverlap != oldOverlap) { // Overlap has changed
- mEndTransition.invalidate();
- } else if (newOverlap) { // Both old and new overlap
- if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
- ((oldStartTimeMs > mDurationMs - transitionDurationMs) ||
- newStartTimeMs > mDurationMs - transitionDurationMs)) {
- mEndTransition.invalidate();
- }
- }
- }
- }
-
- /**
- * This function invalidates the rgb image clip,ken burns effect clip,
- * and scaled image clip
- */
- void invalidate() {
- if (getGeneratedImageClip() != null) {
- new File(getGeneratedImageClip()).delete();
- setGeneratedImageClip(null);
- setRegenerateClip(true);
- }
-
- if (mScaledFilename != null) {
- if(mFileName != mScaledFilename) {
- new File(mScaledFilename).delete();
- }
- mScaledFilename = null;
- }
-
- if (mDecodedFilename != null) {
- new File(mDecodedFilename).delete();
- mDecodedFilename = null;
- }
- }
-
- /**
- * @param KenBurnEffect object.
- * @return an Object of {@link ClipSettings} with Ken Burn settings
- * needed to generate the clip
- */
- private ClipSettings getKenBurns(EffectKenBurns effectKB) {
- int PanZoomXa;
- int PanZoomXb;
- int width = 0, height = 0;
- Rect start = new Rect();
- Rect end = new Rect();
- ClipSettings clipSettings = null;
- clipSettings = new ClipSettings();
- /**
- * image:
- ---------------------------------------
- | Xa |
- | Ya --------------- |
- | | | |
- | | | |
- | --------------- Xb ratioB |
- | ratioA ------- |
- | Yb | | |
- | | | |
- | ------- |
- ---------------------------------------
- */
-
- effectKB.getKenBurnsSettings(start, end);
- width = getWidth();
- height = getHeight();
- if ((start.left < 0) || (start.left > width) || (start.right < 0) || (start.right > width)
- || (start.top < 0) || (start.top > height) || (start.bottom < 0)
- || (start.bottom > height) || (end.left < 0) || (end.left > width)
- || (end.right < 0) || (end.right > width) || (end.top < 0) || (end.top > height)
- || (end.bottom < 0) || (end.bottom > height)) {
- throw new IllegalArgumentException("Illegal arguments for KebBurns");
- }
-
- if (((width - (start.right - start.left) == 0) || (height - (start.bottom - start.top) == 0))
- && ((width - (end.right - end.left) == 0) || (height - (end.bottom - end.top) == 0))) {
- setRegenerateClip(false);
- clipSettings.clipPath = getDecodedImageFileName();
- clipSettings.fileType = FileType.JPG;
- clipSettings.beginCutTime = 0;
- clipSettings.endCutTime = (int)getTimelineDuration();
- clipSettings.beginCutPercent = 0;
- clipSettings.endCutPercent = 0;
- clipSettings.panZoomEnabled = false;
- clipSettings.panZoomPercentStart = 0;
- clipSettings.panZoomTopLeftXStart = 0;
- clipSettings.panZoomTopLeftYStart = 0;
- clipSettings.panZoomPercentEnd = 0;
- clipSettings.panZoomTopLeftXEnd = 0;
- clipSettings.panZoomTopLeftYEnd = 0;
- clipSettings.mediaRendering = mMANativeHelper
- .getMediaItemRenderingMode(getRenderingMode());
-
- clipSettings.rgbWidth = getScaledWidth();
- clipSettings.rgbHeight = getScaledHeight();
-
- return clipSettings;
- }
-
- PanZoomXa = (1000 * start.width()) / width;
- PanZoomXb = (1000 * end.width()) / width;
-
- clipSettings.clipPath = getDecodedImageFileName();
- clipSettings.fileType = mMANativeHelper.getMediaItemFileType(getFileType());
- clipSettings.beginCutTime = 0;
- clipSettings.endCutTime = (int)getTimelineDuration();
- clipSettings.beginCutPercent = 0;
- clipSettings.endCutPercent = 0;
- clipSettings.panZoomEnabled = true;
- clipSettings.panZoomPercentStart = PanZoomXa;
- clipSettings.panZoomTopLeftXStart = (start.left * 1000) / width;
- clipSettings.panZoomTopLeftYStart = (start.top * 1000) / height;
- clipSettings.panZoomPercentEnd = PanZoomXb;
- clipSettings.panZoomTopLeftXEnd = (end.left * 1000) / width;
- clipSettings.panZoomTopLeftYEnd = (end.top * 1000) / height;
- clipSettings.mediaRendering
- = mMANativeHelper.getMediaItemRenderingMode(getRenderingMode());
-
- clipSettings.rgbWidth = getScaledWidth();
- clipSettings.rgbHeight = getScaledHeight();
-
- return clipSettings;
- }
-
-
- /**
- * @param KenBurnEffect object.
- * @return an Object of {@link ClipSettings} with Ken Burns
- * generated clip name
- */
- ClipSettings generateKenburnsClip(EffectKenBurns effectKB) {
- EditSettings editSettings = new EditSettings();
- editSettings.clipSettingsArray = new ClipSettings[1];
- String output = null;
- ClipSettings clipSettings = new ClipSettings();
- initClipSettings(clipSettings);
- editSettings.clipSettingsArray[0] = getKenBurns(effectKB);
- if ((getGeneratedImageClip() == null) && (getRegenerateClip())) {
- output = mMANativeHelper.generateKenBurnsClip(editSettings, this);
- setGeneratedImageClip(output);
- setRegenerateClip(false);
- clipSettings.clipPath = output;
- clipSettings.fileType = FileType.THREE_GPP;
-
- mGeneratedClipHeight = getScaledHeight();
- mGeneratedClipWidth = getWidthByAspectRatioAndHeight(
- mVideoEditor.getAspectRatio(), mGeneratedClipHeight);
- } else {
- if (getGeneratedImageClip() == null) {
- clipSettings.clipPath = getDecodedImageFileName();
- clipSettings.fileType = FileType.JPG;
-
- clipSettings.rgbWidth = getScaledWidth();
- clipSettings.rgbHeight = getScaledHeight();
-
- } else {
- clipSettings.clipPath = getGeneratedImageClip();
- clipSettings.fileType = FileType.THREE_GPP;
- }
- }
- clipSettings.mediaRendering = mMANativeHelper.getMediaItemRenderingMode(getRenderingMode());
- clipSettings.beginCutTime = 0;
- clipSettings.endCutTime = (int)getTimelineDuration();
-
- return clipSettings;
- }
-
- /**
- * @return an Object of {@link ClipSettings} with Image Clip
- * properties data populated.If the image has Ken Burns effect applied,
- * then file path contains generated image clip name with Ken Burns effect
- */
- ClipSettings getImageClipProperties() {
- ClipSettings clipSettings = new ClipSettings();
- List<Effect> effects = null;
- EffectKenBurns effectKB = null;
- boolean effectKBPresent = false;
-
- effects = getAllEffects();
- for (Effect effect : effects) {
- if (effect instanceof EffectKenBurns) {
- effectKB = (EffectKenBurns)effect;
- effectKBPresent = true;
- break;
- }
- }
-
- if (effectKBPresent) {
- clipSettings = generateKenburnsClip(effectKB);
- } else {
- /**
- * Init the clip settings object
- */
- initClipSettings(clipSettings);
- clipSettings.clipPath = getDecodedImageFileName();
- clipSettings.fileType = FileType.JPG;
- clipSettings.beginCutTime = 0;
- clipSettings.endCutTime = (int)getTimelineDuration();
- clipSettings.mediaRendering = mMANativeHelper
- .getMediaItemRenderingMode(getRenderingMode());
- clipSettings.rgbWidth = getScaledWidth();
- clipSettings.rgbHeight = getScaledHeight();
-
- }
- return clipSettings;
- }
-
- /**
- * Resize a bitmap to the specified width and height
- *
- * @param filename The filename
- * @param width The thumbnail width
- * @param height The thumbnail height
- *
- * @return The resized bitmap
- */
- private Bitmap scaleImage(String filename, int width, int height)
- throws IOException {
- final BitmapFactory.Options dbo = new BitmapFactory.Options();
- dbo.inJustDecodeBounds = true;
- BitmapFactory.decodeFile(filename, dbo);
-
- final int nativeWidth = dbo.outWidth;
- final int nativeHeight = dbo.outHeight;
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "generateThumbnail: Input: " + nativeWidth + "x" + nativeHeight
- + ", resize to: " + width + "x" + height);
- }
-
- final Bitmap srcBitmap;
- float bitmapWidth, bitmapHeight;
- if (nativeWidth > width || nativeHeight > height) {
- float dx = ((float)nativeWidth) / ((float)width);
- float dy = ((float)nativeHeight) / ((float)height);
-
- if (dx > dy) {
- bitmapWidth = width;
-
- if (((float)nativeHeight / dx) < (float)height) {
- bitmapHeight = (float)Math.ceil(nativeHeight / dx);
- } else { // value equals the requested height
- bitmapHeight = (float)Math.floor(nativeHeight / dx);
- }
-
- } else {
- if (((float)nativeWidth / dy) > (float)width) {
- bitmapWidth = (float)Math.floor(nativeWidth / dy);
- } else { // value equals the requested width
- bitmapWidth = (float)Math.ceil(nativeWidth / dy);
- }
-
- bitmapHeight = height;
- }
-
- /**
- * Create the bitmap from file
- */
- int sampleSize = (int) Math.ceil(Math.max(
- (float) nativeWidth / bitmapWidth,
- (float) nativeHeight / bitmapHeight));
- sampleSize = nextPowerOf2(sampleSize);
- final BitmapFactory.Options options = new BitmapFactory.Options();
- options.inSampleSize = sampleSize;
- srcBitmap = BitmapFactory.decodeFile(filename, options);
- } else {
- bitmapWidth = width;
- bitmapHeight = height;
- srcBitmap = BitmapFactory.decodeFile(filename);
-
- }
-
- if (srcBitmap == null) {
- Log.e(TAG, "generateThumbnail: Cannot decode image bytes");
- throw new IOException("Cannot decode file: " + mFilename);
- }
-
- /**
- * Create the canvas bitmap
- */
- final Bitmap bitmap = Bitmap.createBitmap((int)bitmapWidth,
- (int)bitmapHeight,
- Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(bitmap);
- canvas.drawBitmap(srcBitmap, new Rect(0, 0, srcBitmap.getWidth(),
- srcBitmap.getHeight()),
- new Rect(0, 0, (int)bitmapWidth,
- (int)bitmapHeight), sResizePaint);
- canvas.setBitmap(null);
- /**
- * Release the source bitmap
- */
- srcBitmap.recycle();
- return bitmap;
- }
-
- public static int nextPowerOf2(int n) {
- n -= 1;
- n |= n >>> 16;
- n |= n >>> 8;
- n |= n >>> 4;
- n |= n >>> 2;
- n |= n >>> 1;
- return n + 1;
- }
-}
diff --git a/media/java/android/media/videoeditor/MediaItem.java b/media/java/android/media/videoeditor/MediaItem.java
deleted file mode 100644
index 4e9ea75..0000000
--- a/media/java/android/media/videoeditor/MediaItem.java
+++ /dev/null
@@ -1,814 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import java.io.DataOutputStream;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-
-import android.graphics.Bitmap;
-import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.FileType;
-import android.media.videoeditor.MediaArtistNativeHelper.MediaRendering;
-
-/**
- * This abstract class describes the base class for any MediaItem. Objects are
- * defined with a file path as a source data.
- * {@hide}
- */
-public abstract class MediaItem {
- /**
- * A constant which can be used to specify the end of the file (instead of
- * providing the actual duration of the media item).
- */
- public final static int END_OF_FILE = -1;
-
- /**
- * Rendering modes
- */
- /**
- * When using the RENDERING_MODE_BLACK_BORDER rendering mode video frames
- * are resized by preserving the aspect ratio until the movie matches one of
- * the dimensions of the output movie. The areas outside the resized video
- * clip are rendered black.
- */
- public static final int RENDERING_MODE_BLACK_BORDER = 0;
-
- /**
- * When using the RENDERING_MODE_STRETCH rendering mode video frames are
- * stretched horizontally or vertically to match the current aspect ratio of
- * the video editor.
- */
- public static final int RENDERING_MODE_STRETCH = 1;
-
- /**
- * When using the RENDERING_MODE_CROPPING rendering mode video frames are
- * scaled horizontally or vertically by preserving the original aspect ratio
- * of the media item.
- */
- public static final int RENDERING_MODE_CROPPING = 2;
-
- /**
- * The unique id of the MediaItem
- */
- private final String mUniqueId;
-
- /**
- * The name of the file associated with the MediaItem
- */
- protected final String mFilename;
-
- /**
- * List of effects
- */
- private final List<Effect> mEffects;
-
- /**
- * List of overlays
- */
- private final List<Overlay> mOverlays;
-
- /**
- * The rendering mode
- */
- private int mRenderingMode;
-
- private final MediaArtistNativeHelper mMANativeHelper;
-
- private final String mProjectPath;
-
- /**
- * Beginning and end transitions
- */
- protected Transition mBeginTransition;
-
- protected Transition mEndTransition;
-
- protected String mGeneratedImageClip;
-
- protected boolean mRegenerateClip;
-
- private boolean mBlankFrameGenerated = false;
-
- private String mBlankFrameFilename = null;
-
- /**
- * Constructor
- *
- * @param editor The video editor reference
- * @param mediaItemId The MediaItem id
- * @param filename name of the media file.
- * @param renderingMode The rendering mode
- * @throws IOException if file is not found
- * @throws IllegalArgumentException if a capability such as file format is
- * not supported the exception object contains the unsupported
- * capability
- */
- protected MediaItem(VideoEditor editor, String mediaItemId, String filename,
- int renderingMode) throws IOException {
- if (filename == null) {
- throw new IllegalArgumentException("MediaItem : filename is null");
- }
- File file = new File(filename);
- if (!file.exists()) {
- throw new IOException(filename + " not found ! ");
- }
-
- /*Compare file_size with 2GB*/
- if (VideoEditor.MAX_SUPPORTED_FILE_SIZE <= file.length()) {
- throw new IllegalArgumentException("File size is more than 2GB");
- }
- mUniqueId = mediaItemId;
- mFilename = filename;
- mRenderingMode = renderingMode;
- mEffects = new ArrayList<Effect>();
- mOverlays = new ArrayList<Overlay>();
- mBeginTransition = null;
- mEndTransition = null;
- mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
- mProjectPath = editor.getPath();
- mRegenerateClip = false;
- mGeneratedImageClip = null;
- }
-
- /**
- * @return The id of the media item
- */
- public String getId() {
- return mUniqueId;
- }
-
- /**
- * @return The media source file name
- */
- public String getFilename() {
- return mFilename;
- }
-
- /**
- * If aspect ratio of the MediaItem is different from the aspect ratio of
- * the editor then this API controls the rendering mode.
- *
- * @param renderingMode rendering mode. It is one of:
- * {@link #RENDERING_MODE_BLACK_BORDER},
- * {@link #RENDERING_MODE_STRETCH}
- */
- public void setRenderingMode(int renderingMode) {
- switch (renderingMode) {
- case RENDERING_MODE_BLACK_BORDER:
- case RENDERING_MODE_STRETCH:
- case RENDERING_MODE_CROPPING:
- break;
-
- default:
- throw new IllegalArgumentException("Invalid Rendering Mode");
- }
-
- mMANativeHelper.setGeneratePreview(true);
-
- mRenderingMode = renderingMode;
- if (mBeginTransition != null) {
- mBeginTransition.invalidate();
- }
-
- if (mEndTransition != null) {
- mEndTransition.invalidate();
- }
-
- for (Overlay overlay : mOverlays) {
- ((OverlayFrame)overlay).invalidateGeneratedFiles();
- }
- }
-
- /**
- * @return The rendering mode
- */
- public int getRenderingMode() {
- return mRenderingMode;
- }
-
- /**
- * @param transition The beginning transition
- */
- void setBeginTransition(Transition transition) {
- mBeginTransition = transition;
- }
-
- /**
- * @return The begin transition
- */
- public Transition getBeginTransition() {
- return mBeginTransition;
- }
-
- /**
- * @param transition The end transition
- */
- void setEndTransition(Transition transition) {
- mEndTransition = transition;
- }
-
- /**
- * @return The end transition
- */
- public Transition getEndTransition() {
- return mEndTransition;
- }
-
- /**
- * @return The timeline duration. This is the actual duration in the
- * timeline (trimmed duration)
- */
- public abstract long getTimelineDuration();
-
- /**
- * @return The is the full duration of the media item (not trimmed)
- */
- public abstract long getDuration();
-
- /**
- * @return The source file type
- */
- public abstract int getFileType();
-
- /**
- * @return Get the native width of the media item
- */
- public abstract int getWidth();
-
- /**
- * @return Get the native height of the media item
- */
- public abstract int getHeight();
-
- /**
- * Get aspect ratio of the source media item.
- *
- * @return the aspect ratio as described in MediaProperties.
- * MediaProperties.ASPECT_RATIO_UNDEFINED if aspect ratio is not
- * supported as in MediaProperties
- */
- public abstract int getAspectRatio();
-
- /**
- * Add the specified effect to this media item.
- *
- * Note that certain types of effects cannot be applied to video and to
- * image media items. For example in certain implementation a Ken Burns
- * implementation cannot be applied to video media item.
- *
- * This method invalidates transition video clips if the
- * effect overlaps with the beginning and/or the end transition.
- *
- * @param effect The effect to apply
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if the effect start and/or duration are
- * invalid or if the effect cannot be applied to this type of media
- * item or if the effect id is not unique across all the Effects
- * added.
- */
- public void addEffect(Effect effect) {
-
- if (effect == null) {
- throw new IllegalArgumentException("NULL effect cannot be applied");
- }
-
- if (effect.getMediaItem() != this) {
- throw new IllegalArgumentException("Media item mismatch");
- }
-
- if (mEffects.contains(effect)) {
- throw new IllegalArgumentException("Effect already exists: " + effect.getId());
- }
-
- if (effect.getStartTime() + effect.getDuration() > getDuration()) {
- throw new IllegalArgumentException(
- "Effect start time + effect duration > media clip duration");
- }
-
- mMANativeHelper.setGeneratePreview(true);
-
- mEffects.add(effect);
-
- invalidateTransitions(effect.getStartTime(), effect.getDuration());
-
- if (effect instanceof EffectKenBurns) {
- mRegenerateClip = true;
- }
- }
-
- /**
- * Remove the effect with the specified id.
- *
- * This method invalidates a transition video clip if the effect overlaps
- * with a transition.
- *
- * @param effectId The id of the effect to be removed
- *
- * @return The effect that was removed
- * @throws IllegalStateException if a preview or an export is in progress
- */
- public Effect removeEffect(String effectId) {
- for (Effect effect : mEffects) {
- if (effect.getId().equals(effectId)) {
- mMANativeHelper.setGeneratePreview(true);
-
- mEffects.remove(effect);
-
- invalidateTransitions(effect.getStartTime(), effect.getDuration());
- if (effect instanceof EffectKenBurns) {
- if (mGeneratedImageClip != null) {
- /**
- * Delete the file
- */
- new File(mGeneratedImageClip).delete();
- /**
- * Invalidate the filename
- */
- mGeneratedImageClip = null;
- }
- mRegenerateClip = false;
- }
- return effect;
- }
- }
- return null;
- }
-
- /**
- * Set the filepath of the generated image clip when the effect is added.
- *
- * @param The filepath of the generated image clip.
- */
- void setGeneratedImageClip(String generatedFilePath) {
- mGeneratedImageClip = generatedFilePath;
- }
-
- /**
- * Get the filepath of the generated image clip when the effect is added.
- *
- * @return The filepath of the generated image clip (null if it does not
- * exist)
- */
- String getGeneratedImageClip() {
- return mGeneratedImageClip;
- }
-
- /**
- * Find the effect with the specified id
- *
- * @param effectId The effect id
- * @return The effect with the specified id (null if it does not exist)
- */
- public Effect getEffect(String effectId) {
- for (Effect effect : mEffects) {
- if (effect.getId().equals(effectId)) {
- return effect;
- }
- }
- return null;
- }
-
- /**
- * Get the list of effects.
- *
- * @return the effects list. If no effects exist an empty list will be
- * returned.
- */
- public List<Effect> getAllEffects() {
- return mEffects;
- }
-
- /**
- * Add an overlay to the storyboard. This method invalidates a transition
- * video clip if the overlay overlaps with a transition.
- *
- * @param overlay The overlay to add
- * @throws IllegalStateException if a preview or an export is in progress or
- * if the overlay id is not unique across all the overlays added
- * or if the bitmap is not specified or if the dimensions of the
- * bitmap do not match the dimensions of the media item
- * @throws FileNotFoundException, IOException if overlay could not be saved
- * to project path
- */
- public void addOverlay(Overlay overlay) throws FileNotFoundException, IOException {
- if (overlay == null) {
- throw new IllegalArgumentException("NULL Overlay cannot be applied");
- }
-
- if (overlay.getMediaItem() != this) {
- throw new IllegalArgumentException("Media item mismatch");
- }
-
- if (mOverlays.contains(overlay)) {
- throw new IllegalArgumentException("Overlay already exists: " + overlay.getId());
- }
-
- if (overlay.getStartTime() + overlay.getDuration() > getDuration()) {
- throw new IllegalArgumentException(
- "Overlay start time + overlay duration > media clip duration");
- }
-
- if (overlay instanceof OverlayFrame) {
- final OverlayFrame frame = (OverlayFrame)overlay;
- final Bitmap bitmap = frame.getBitmap();
- if (bitmap == null) {
- throw new IllegalArgumentException("Overlay bitmap not specified");
- }
-
- final int scaledWidth, scaledHeight;
- if (this instanceof MediaVideoItem) {
- scaledWidth = getWidth();
- scaledHeight = getHeight();
- } else {
- scaledWidth = ((MediaImageItem)this).getScaledWidth();
- scaledHeight = ((MediaImageItem)this).getScaledHeight();
- }
-
- /**
- * The dimensions of the overlay bitmap must be the same as the
- * media item dimensions
- */
- if (bitmap.getWidth() != scaledWidth || bitmap.getHeight() != scaledHeight) {
- throw new IllegalArgumentException(
- "Bitmap dimensions must match media item dimensions");
- }
-
- mMANativeHelper.setGeneratePreview(true);
- ((OverlayFrame)overlay).save(mProjectPath);
-
- mOverlays.add(overlay);
- invalidateTransitions(overlay.getStartTime(), overlay.getDuration());
-
- } else {
- throw new IllegalArgumentException("Overlay not supported");
- }
- }
-
- /**
- * @param flag The flag to indicate if regeneration of clip is true or
- * false.
- */
- void setRegenerateClip(boolean flag) {
- mRegenerateClip = flag;
- }
-
- /**
- * @return flag The flag to indicate if regeneration of clip is true or
- * false.
- */
- boolean getRegenerateClip() {
- return mRegenerateClip;
- }
-
- /**
- * Remove the overlay with the specified id.
- *
- * This method invalidates a transition video clip if the overlay overlaps
- * with a transition.
- *
- * @param overlayId The id of the overlay to be removed
- *
- * @return The overlay that was removed
- * @throws IllegalStateException if a preview or an export is in progress
- */
- public Overlay removeOverlay(String overlayId) {
- for (Overlay overlay : mOverlays) {
- if (overlay.getId().equals(overlayId)) {
- mMANativeHelper.setGeneratePreview(true);
-
- mOverlays.remove(overlay);
- if (overlay instanceof OverlayFrame) {
- ((OverlayFrame)overlay).invalidate();
- }
- invalidateTransitions(overlay.getStartTime(), overlay.getDuration());
- return overlay;
- }
- }
- return null;
- }
-
- /**
- * Find the overlay with the specified id
- *
- * @param overlayId The overlay id
- *
- * @return The overlay with the specified id (null if it does not exist)
- */
- public Overlay getOverlay(String overlayId) {
- for (Overlay overlay : mOverlays) {
- if (overlay.getId().equals(overlayId)) {
- return overlay;
- }
- }
-
- return null;
- }
-
- /**
- * Get the list of overlays associated with this media item
- *
- * Note that if any overlay source files are not accessible anymore,
- * this method will still provide the full list of overlays.
- *
- * @return The list of overlays. If no overlays exist an empty list will
- * be returned.
- */
- public List<Overlay> getAllOverlays() {
- return mOverlays;
- }
-
- /**
- * Create a thumbnail at specified time in a video stream in Bitmap format
- *
- * @param width width of the thumbnail in pixels
- * @param height height of the thumbnail in pixels
- * @param timeMs The time in the source video file at which the thumbnail is
- * requested (even if trimmed).
- *
- * @return The thumbnail as a Bitmap.
- *
- * @throws IOException if a file error occurs
- * @throws IllegalArgumentException if time is out of video duration
- */
- public abstract Bitmap getThumbnail(int width, int height, long timeMs)
- throws IOException;
-
- /**
- * Get the array of Bitmap thumbnails between start and end.
- *
- * @param width width of the thumbnail in pixels
- * @param height height of the thumbnail in pixels
- * @param startMs The start of time range in milliseconds
- * @param endMs The end of the time range in milliseconds
- * @param thumbnailCount The thumbnail count
- * @param indices The indices of the thumbnails wanted
- * @param callback The callback used to pass back the bitmaps
- *
- * @throws IOException if a file error occurs
- */
- public abstract void getThumbnailList(int width, int height,
- long startMs, long endMs,
- int thumbnailCount,
- int[] indices,
- GetThumbnailListCallback callback)
- throws IOException;
-
- public interface GetThumbnailListCallback {
- public void onThumbnail(Bitmap bitmap, int index);
- }
-
- // This is for compatibility, only used in tests.
- public Bitmap[] getThumbnailList(int width, int height,
- long startMs, long endMs,
- int thumbnailCount)
- throws IOException {
- final Bitmap[] bitmaps = new Bitmap[thumbnailCount];
- int[] indices = new int[thumbnailCount];
- for (int i = 0; i < thumbnailCount; i++) {
- indices[i] = i;
- }
- getThumbnailList(width, height, startMs, endMs,
- thumbnailCount, indices, new GetThumbnailListCallback() {
- public void onThumbnail(Bitmap bitmap, int index) {
- bitmaps[index] = bitmap;
- }
- });
-
- return bitmaps;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof MediaItem)) {
- return false;
- }
- return mUniqueId.equals(((MediaItem)object).mUniqueId);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return mUniqueId.hashCode();
- }
-
- /**
- * Invalidate the start and end transitions if necessary
- *
- * @param startTimeMs The start time of the effect or overlay
- * @param durationMs The duration of the effect or overlay
- */
- abstract void invalidateTransitions(long startTimeMs, long durationMs);
-
- /**
- * Invalidate the start and end transitions if necessary. This method is
- * typically called when the start time and/or duration of an overlay or
- * effect is changing.
- *
- * @param oldStartTimeMs The old start time of the effect or overlay
- * @param oldDurationMs The old duration of the effect or overlay
- * @param newStartTimeMs The new start time of the effect or overlay
- * @param newDurationMs The new duration of the effect or overlay
- */
- abstract void invalidateTransitions(long oldStartTimeMs, long oldDurationMs,
- long newStartTimeMs, long newDurationMs);
-
- /**
- * Check if two items overlap in time
- *
- * @param startTimeMs1 Item 1 start time
- * @param durationMs1 Item 1 duration
- * @param startTimeMs2 Item 2 start time
- * @param durationMs2 Item 2 end time
- * @return true if the two items overlap
- */
- protected boolean isOverlapping(long startTimeMs1, long durationMs1,
- long startTimeMs2, long durationMs2) {
- if (startTimeMs1 + durationMs1 <= startTimeMs2) {
- return false;
- } else if (startTimeMs1 >= startTimeMs2 + durationMs2) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Adjust the duration transitions.
- */
- protected void adjustTransitions() {
- /**
- * Check if the duration of transitions need to be adjusted
- */
- if (mBeginTransition != null) {
- final long maxDurationMs = mBeginTransition.getMaximumDuration();
- if (mBeginTransition.getDuration() > maxDurationMs) {
- mBeginTransition.setDuration(maxDurationMs);
- }
- }
-
- if (mEndTransition != null) {
- final long maxDurationMs = mEndTransition.getMaximumDuration();
- if (mEndTransition.getDuration() > maxDurationMs) {
- mEndTransition.setDuration(maxDurationMs);
- }
- }
- }
-
- /**
- * @return MediaArtistNativeHleper context
- */
- MediaArtistNativeHelper getNativeContext() {
- return mMANativeHelper;
- }
-
- /**
- * Initialises ClipSettings fields to default value
- *
- * @param ClipSettings object
- *{@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
- */
- void initClipSettings(ClipSettings clipSettings) {
- clipSettings.clipPath = null;
- clipSettings.clipDecodedPath = null;
- clipSettings.clipOriginalPath = null;
- clipSettings.fileType = 0;
- clipSettings.endCutTime = 0;
- clipSettings.beginCutTime = 0;
- clipSettings.beginCutPercent = 0;
- clipSettings.endCutPercent = 0;
- clipSettings.panZoomEnabled = false;
- clipSettings.panZoomPercentStart = 0;
- clipSettings.panZoomTopLeftXStart = 0;
- clipSettings.panZoomTopLeftYStart = 0;
- clipSettings.panZoomPercentEnd = 0;
- clipSettings.panZoomTopLeftXEnd = 0;
- clipSettings.panZoomTopLeftYEnd = 0;
- clipSettings.mediaRendering = 0;
- clipSettings.rgbWidth = 0;
- clipSettings.rgbHeight = 0;
- }
-
- /**
- * @return ClipSettings object with populated data
- *{@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
- */
- ClipSettings getClipSettings() {
- MediaVideoItem mVI = null;
- MediaImageItem mII = null;
- ClipSettings clipSettings = new ClipSettings();
- initClipSettings(clipSettings);
- if (this instanceof MediaVideoItem) {
- mVI = (MediaVideoItem)this;
- clipSettings.clipPath = mVI.getFilename();
- clipSettings.fileType = mMANativeHelper.getMediaItemFileType(mVI.
- getFileType());
- clipSettings.beginCutTime = (int)mVI.getBoundaryBeginTime();
- clipSettings.endCutTime = (int)mVI.getBoundaryEndTime();
- clipSettings.mediaRendering = mMANativeHelper.
- getMediaItemRenderingMode(mVI
- .getRenderingMode());
- } else if (this instanceof MediaImageItem) {
- mII = (MediaImageItem)this;
- clipSettings = mII.getImageClipProperties();
- }
- return clipSettings;
- }
-
- /**
- * Generates a black frame to be used for generating
- * begin transition at first media item in storyboard
- * or end transition at last media item in storyboard
- *
- * @param ClipSettings object
- *{@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
- */
- void generateBlankFrame(ClipSettings clipSettings) {
- if (!mBlankFrameGenerated) {
- int mWidth = 64;
- int mHeight = 64;
- mBlankFrameFilename = String.format(mProjectPath + "/" + "ghost.rgb");
- FileOutputStream fl = null;
- try {
- fl = new FileOutputStream(mBlankFrameFilename);
- } catch (IOException e) {
- /* catch IO exception */
- }
- final DataOutputStream dos = new DataOutputStream(fl);
-
- final int [] framingBuffer = new int[mWidth];
-
- ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
- IntBuffer intBuffer;
-
- byte[] array = byteBuffer.array();
- int tmp = 0;
- while(tmp < mHeight) {
- intBuffer = byteBuffer.asIntBuffer();
- intBuffer.put(framingBuffer,0,mWidth);
- try {
- dos.write(array);
- } catch (IOException e) {
- /* catch file write error */
- }
- tmp += 1;
- }
-
- try {
- fl.close();
- } catch (IOException e) {
- /* file close error */
- }
- mBlankFrameGenerated = true;
- }
-
- clipSettings.clipPath = mBlankFrameFilename;
- clipSettings.fileType = FileType.JPG;
- clipSettings.beginCutTime = 0;
- clipSettings.endCutTime = 0;
- clipSettings.mediaRendering = MediaRendering.RESIZING;
-
- clipSettings.rgbWidth = 64;
- clipSettings.rgbHeight = 64;
- }
-
- /**
- * Invalidates the blank frame generated
- */
- void invalidateBlankFrame() {
- if (mBlankFrameFilename != null) {
- if (new File(mBlankFrameFilename).exists()) {
- new File(mBlankFrameFilename).delete();
- mBlankFrameFilename = null;
- }
- }
- }
-
-}
diff --git a/media/java/android/media/videoeditor/MediaProperties.java b/media/java/android/media/videoeditor/MediaProperties.java
deleted file mode 100644
index cf518a5..0000000
--- a/media/java/android/media/videoeditor/MediaProperties.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.media.videoeditor;
-
-import android.media.videoeditor.VideoEditorProfile;
-import android.util.Pair;
-import java.lang.System;
-/**
- * This class defines all properties of a media file such as supported height,
- * aspect ratio, bitrate for export function.
- * {@hide}
- */
-public class MediaProperties {
- /**
- * Supported heights
- */
- public static final int HEIGHT_144 = 144;
- public static final int HEIGHT_288 = 288;
- public static final int HEIGHT_360 = 360;
- public static final int HEIGHT_480 = 480;
- public static final int HEIGHT_720 = 720;
- public static final int HEIGHT_1080 = 1080;
-
- /**
- * Supported aspect ratios
- */
- public static final int ASPECT_RATIO_UNDEFINED = 0;
- public static final int ASPECT_RATIO_3_2 = 1;
- public static final int ASPECT_RATIO_16_9 = 2;
- public static final int ASPECT_RATIO_4_3 = 3;
- public static final int ASPECT_RATIO_5_3 = 4;
- public static final int ASPECT_RATIO_11_9 = 5;
-
- /**
- * The array of supported aspect ratios
- */
- private static final int[] ASPECT_RATIOS = new int[] {
- ASPECT_RATIO_3_2,
- ASPECT_RATIO_16_9,
- ASPECT_RATIO_4_3,
- ASPECT_RATIO_5_3,
- ASPECT_RATIO_11_9
- };
-
- /**
- * Supported resolutions for specific aspect ratios
- */
- @SuppressWarnings({"unchecked"})
- private static final Pair<Integer, Integer>[] ASPECT_RATIO_3_2_RESOLUTIONS =
- new Pair[] {
- new Pair<Integer, Integer>(720, HEIGHT_480),
- new Pair<Integer, Integer>(1080, HEIGHT_720)
- };
-
- @SuppressWarnings({"unchecked"})
- private static final Pair<Integer, Integer>[] ASPECT_RATIO_4_3_RESOLUTIONS =
- new Pair[] {
- new Pair<Integer, Integer>(640, HEIGHT_480),
- new Pair<Integer, Integer>(960, HEIGHT_720)
- };
-
- @SuppressWarnings({"unchecked"})
- private static final Pair<Integer, Integer>[] ASPECT_RATIO_5_3_RESOLUTIONS =
- new Pair[] {
- new Pair<Integer, Integer>(800, HEIGHT_480)
- };
-
- @SuppressWarnings({"unchecked"})
- private static final Pair<Integer, Integer>[] ASPECT_RATIO_11_9_RESOLUTIONS =
- new Pair[] {
- new Pair<Integer, Integer>(176, HEIGHT_144),
- new Pair<Integer, Integer>(352, HEIGHT_288)
- };
-
- @SuppressWarnings({"unchecked"})
- private static final Pair<Integer, Integer>[] ASPECT_RATIO_16_9_RESOLUTIONS =
- new Pair[] {
- new Pair<Integer, Integer>(848, HEIGHT_480),
- new Pair<Integer, Integer>(1280, HEIGHT_720),
- new Pair<Integer, Integer>(1920, HEIGHT_1080),
- };
-
- /**
- * Bitrate values (in bits per second)
- */
- public static final int BITRATE_28K = 28000;
- public static final int BITRATE_40K = 40000;
- public static final int BITRATE_64K = 64000;
- public static final int BITRATE_96K = 96000;
- public static final int BITRATE_128K = 128000;
- public static final int BITRATE_192K = 192000;
- public static final int BITRATE_256K = 256000;
- public static final int BITRATE_384K = 384000;
- public static final int BITRATE_512K = 512000;
- public static final int BITRATE_800K = 800000;
- public static final int BITRATE_2M = 2000000;
- public static final int BITRATE_5M = 5000000;
- public static final int BITRATE_8M = 8000000;
-
- /**
- * The array of supported bitrates
- */
- private static final int[] SUPPORTED_BITRATES = new int[] {
- BITRATE_28K,
- BITRATE_40K,
- BITRATE_64K,
- BITRATE_96K,
- BITRATE_128K,
- BITRATE_192K,
- BITRATE_256K,
- BITRATE_384K,
- BITRATE_512K,
- BITRATE_800K,
- BITRATE_2M,
- BITRATE_5M,
- BITRATE_8M
- };
-
- /**
- * Video codec types
- */
- public static final int VCODEC_H263 = 1;
- public static final int VCODEC_H264 = 2;
- public static final int VCODEC_MPEG4 = 3;
-
- /**
- * The array of supported video codecs
- */
- private static final int[] SUPPORTED_VCODECS = new int[] {
- VCODEC_H264,
- VCODEC_H263,
- VCODEC_MPEG4,
- };
-
- /**
- * The H264 profile, the values are same as the one in OMX_Video.h
- */
- public final class H264Profile {
- public static final int H264ProfileBaseline = 0x01; /**< Baseline profile */
- public static final int H264ProfileMain = 0x02; /**< Main profile */
- public static final int H264ProfileExtended = 0x04; /**< Extended profile */
- public static final int H264ProfileHigh = 0x08; /**< High profile */
- public static final int H264ProfileHigh10 = 0x10; /**< High 10 profile */
- public static final int H264ProfileHigh422 = 0x20; /**< High 4:2:2 profile */
- public static final int H264ProfileHigh444 = 0x40; /**< High 4:4:4 profile */
- public static final int H264ProfileUnknown = 0x7FFFFFFF;
- }
- /**
- * The H264 level, the values are same as the one in OMX_Video.h
- */
- public final class H264Level {
- public static final int H264Level1 = 0x01; /**< Level 1 */
- public static final int H264Level1b = 0x02; /**< Level 1b */
- public static final int H264Level11 = 0x04; /**< Level 1.1 */
- public static final int H264Level12 = 0x08; /**< Level 1.2 */
- public static final int H264Level13 = 0x10; /**< Level 1.3 */
- public static final int H264Level2 = 0x20; /**< Level 2 */
- public static final int H264Level21 = 0x40; /**< Level 2.1 */
- public static final int H264Level22 = 0x80; /**< Level 2.2 */
- public static final int H264Level3 = 0x100; /**< Level 3 */
- public static final int H264Level31 = 0x200; /**< Level 3.1 */
- public static final int H264Level32 = 0x400; /**< Level 3.2 */
- public static final int H264Level4 = 0x800; /**< Level 4 */
- public static final int H264Level41 = 0x1000; /**< Level 4.1 */
- public static final int H264Level42 = 0x2000; /**< Level 4.2 */
- public static final int H264Level5 = 0x4000; /**< Level 5 */
- public static final int H264Level51 = 0x8000; /**< Level 5.1 */
- public static final int H264LevelUnknown = 0x7FFFFFFF;
- }
- /**
- * The H263 profile, the values are same as the one in OMX_Video.h
- */
- public final class H263Profile {
- public static final int H263ProfileBaseline = 0x01;
- public static final int H263ProfileH320Coding = 0x02;
- public static final int H263ProfileBackwardCompatible = 0x04;
- public static final int H263ProfileISWV2 = 0x08;
- public static final int H263ProfileISWV3 = 0x10;
- public static final int H263ProfileHighCompression = 0x20;
- public static final int H263ProfileInternet = 0x40;
- public static final int H263ProfileInterlace = 0x80;
- public static final int H263ProfileHighLatency = 0x100;
- public static final int H263ProfileUnknown = 0x7FFFFFFF;
- }
- /**
- * The H263 level, the values are same as the one in OMX_Video.h
- */
- public final class H263Level {
- public static final int H263Level10 = 0x01;
- public static final int H263Level20 = 0x02;
- public static final int H263Level30 = 0x04;
- public static final int H263Level40 = 0x08;
- public static final int H263Level45 = 0x10;
- public static final int H263Level50 = 0x20;
- public static final int H263Level60 = 0x40;
- public static final int H263Level70 = 0x80;
- public static final int H263LevelUnknown = 0x7FFFFFFF;
- }
- /**
- * The mpeg4 profile, the values are same as the one in OMX_Video.h
- */
- public final class MPEG4Profile {
- public static final int MPEG4ProfileSimple = 0x01;
- public static final int MPEG4ProfileSimpleScalable = 0x02;
- public static final int MPEG4ProfileCore = 0x04;
- public static final int MPEG4ProfileMain = 0x08;
- public static final int MPEG4ProfileNbit = 0x10;
- public static final int MPEG4ProfileScalableTexture = 0x20;
- public static final int MPEG4ProfileSimpleFace = 0x40;
- public static final int MPEG4ProfileSimpleFBA = 0x80;
- public static final int MPEG4ProfileBasicAnimated = 0x100;
- public static final int MPEG4ProfileHybrid = 0x200;
- public static final int MPEG4ProfileAdvancedRealTime = 0x400;
- public static final int MPEG4ProfileCoreScalable = 0x800;
- public static final int MPEG4ProfileAdvancedCoding = 0x1000;
- public static final int MPEG4ProfileAdvancedCore = 0x2000;
- public static final int MPEG4ProfileAdvancedScalable = 0x4000;
- public static final int MPEG4ProfileAdvancedSimple = 0x8000;
- public static final int MPEG4ProfileUnknown = 0x7FFFFFFF;
- }
- /**
- * The mpeg4 level, the values are same as the one in OMX_Video.h
- */
- public final class MPEG4Level {
- public static final int MPEG4Level0 = 0x01; /**< Level 0 */
- public static final int MPEG4Level0b = 0x02; /**< Level 0b */
- public static final int MPEG4Level1 = 0x04; /**< Level 1 */
- public static final int MPEG4Level2 = 0x08; /**< Level 2 */
- public static final int MPEG4Level3 = 0x10; /**< Level 3 */
- public static final int MPEG4Level4 = 0x20; /**< Level 4 */
- public static final int MPEG4Level4a = 0x40; /**< Level 4a */
- public static final int MPEG4Level5 = 0x80; /**< Level 5 */
- public static final int MPEG4LevelUnknown = 0x7FFFFFFF;
- }
- /**
- * Audio codec types
- */
- public static final int ACODEC_NO_AUDIO = 0;
- public static final int ACODEC_AMRNB = 1;
- public static final int ACODEC_AAC_LC = 2;
- public static final int ACODEC_AAC_PLUS = 3;
- public static final int ACODEC_ENHANCED_AAC_PLUS = 4;
- public static final int ACODEC_MP3 = 5;
- public static final int ACODEC_EVRC = 6;
- // 7 value is used for PCM
- public static final int ACODEC_AMRWB = 8;
- public static final int ACODEC_OGG = 9;
-
- /**
- * The array of supported audio codecs
- */
- private static final int[] SUPPORTED_ACODECS = new int[] {
- ACODEC_AAC_LC,
- ACODEC_AMRNB,
- ACODEC_AMRWB
- };
-
- /**
- * Samples per frame for each audio codec
- */
- public static final int SAMPLES_PER_FRAME_AAC = 1024;
- public static final int SAMPLES_PER_FRAME_MP3 = 1152;
- public static final int SAMPLES_PER_FRAME_AMRNB = 160;
- public static final int SAMPLES_PER_FRAME_AMRWB = 320;
-
- public static final int DEFAULT_SAMPLING_FREQUENCY = 32000;
- public static final int DEFAULT_CHANNEL_COUNT = 2;
-
- /**
- * File format types
- */
- public static final int FILE_3GP = 0;
- public static final int FILE_MP4 = 1;
- public static final int FILE_AMR = 2;
- public static final int FILE_MP3 = 3;
- // 4 is for PCM
- public static final int FILE_JPEG = 5;
- // 6 is for BMP
- // 7 is for GIF
- public static final int FILE_PNG = 8;
- // 9 is for ARGB8888
- public static final int FILE_M4V = 10;
- public static final int FILE_UNSUPPORTED = 255;
-
- /**
- * Undefined video codec profiles
- */
- public static final int UNDEFINED_VIDEO_PROFILE = 255;
-
- /**
- * The array of the supported file formats
- */
- private static final int[] SUPPORTED_VIDEO_FILE_FORMATS = new int[] {
- FILE_3GP,
- FILE_MP4,
- FILE_M4V
- };
-
- /**
- * The maximum count of audio tracks supported
- */
- public static final int AUDIO_MAX_TRACK_COUNT = 1;
-
- /** The maximum volume supported (100 means that no amplification is
- * supported, i.e. attenuation only)
- */
- public static final int AUDIO_MAX_VOLUME_PERCENT = 100;
-
- /**
- * This class cannot be instantiated
- */
- private MediaProperties() {
- }
-
- /**
- * @return The array of supported aspect ratios
- */
- public static int[] getAllSupportedAspectRatios() {
- return ASPECT_RATIOS;
- }
-
- /**
- * Get the supported resolutions for the specified aspect ratio.
- *
- * @param aspectRatio The aspect ratio for which the resolutions are
- * requested
- * @return The array of width and height pairs
- */
- public static Pair<Integer, Integer>[] getSupportedResolutions(int aspectRatio) {
- final Pair<Integer, Integer>[] resolutions;
- switch (aspectRatio) {
- case ASPECT_RATIO_3_2: {
- resolutions = ASPECT_RATIO_3_2_RESOLUTIONS;
- break;
- }
-
- case ASPECT_RATIO_4_3: {
- resolutions = ASPECT_RATIO_4_3_RESOLUTIONS;
- break;
- }
-
- case ASPECT_RATIO_5_3: {
- resolutions = ASPECT_RATIO_5_3_RESOLUTIONS;
- break;
- }
-
- case ASPECT_RATIO_11_9: {
- resolutions = ASPECT_RATIO_11_9_RESOLUTIONS;
- break;
- }
-
- case ASPECT_RATIO_16_9: {
- resolutions = ASPECT_RATIO_16_9_RESOLUTIONS;
- break;
- }
-
- default: {
- throw new IllegalArgumentException("Unknown aspect ratio: " + aspectRatio);
- }
- }
-
- /** Check the platform specific maximum export resolution */
- VideoEditorProfile veProfile = VideoEditorProfile.get();
- if (veProfile == null) {
- throw new RuntimeException("Can't get the video editor profile");
- }
- final int maxWidth = veProfile.maxOutputVideoFrameWidth;
- final int maxHeight = veProfile.maxOutputVideoFrameHeight;
- Pair<Integer, Integer>[] tmpResolutions = new Pair[resolutions.length];
- int numSupportedResolution = 0;
- int i = 0;
-
- /** Get supported resolution list */
- for (i = 0; i < resolutions.length; i++) {
- if ((resolutions[i].first <= maxWidth) &&
- (resolutions[i].second <= maxHeight)) {
- tmpResolutions[numSupportedResolution] = resolutions[i];
- numSupportedResolution++;
- }
- }
- final Pair<Integer, Integer>[] supportedResolutions =
- new Pair[numSupportedResolution];
- System.arraycopy(tmpResolutions, 0,
- supportedResolutions, 0, numSupportedResolution);
-
- return supportedResolutions;
- }
-
- /**
- * @return The array of supported video codecs
- */
- public static int[] getSupportedVideoCodecs() {
- return SUPPORTED_VCODECS;
- }
-
- /**
- * @return The array of supported audio codecs
- */
- public static int[] getSupportedAudioCodecs() {
- return SUPPORTED_ACODECS;
- }
-
- /**
- * @return The array of supported file formats
- */
- public static int[] getSupportedVideoFileFormat() {
- return SUPPORTED_VIDEO_FILE_FORMATS;
- }
-
- /**
- * @return The array of supported video bitrates
- */
- public static int[] getSupportedVideoBitrates() {
- return SUPPORTED_BITRATES;
- }
-
- /**
- * @return The maximum value for the audio volume
- */
- public static int getSupportedMaxVolume() {
- return MediaProperties.AUDIO_MAX_VOLUME_PERCENT;
- }
-
- /**
- * @return The maximum number of audio tracks supported
- */
- public static int getSupportedAudioTrackCount() {
- return MediaProperties.AUDIO_MAX_TRACK_COUNT;
- }
-}
diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java
deleted file mode 100644
index bbcdf57..0000000
--- a/media/java/android/media/videoeditor/MediaVideoItem.java
+++ /dev/null
@@ -1,758 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.ref.SoftReference;
-import android.graphics.Bitmap;
-import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.Properties;
-import android.media.videoeditor.VideoEditorProfile;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-
-/**
- * This class represents a video clip item on the storyboard
- * {@hide}
- */
-public class MediaVideoItem extends MediaItem {
-
- /**
- * Instance variables
- */
- private final int mWidth;
- private final int mHeight;
- private final int mAspectRatio;
- private final int mFileType;
- private final int mVideoType;
- private final int mVideoProfile;
- private final int mVideoLevel;
- private final int mVideoBitrate;
- private final long mDurationMs;
- private final int mAudioBitrate;
- private final int mFps;
- private final int mAudioType;
- private final int mAudioChannels;
- private final int mAudioSamplingFrequency;
- private long mBeginBoundaryTimeMs;
- private long mEndBoundaryTimeMs;
- private int mVolumePercentage;
- private boolean mMuted;
- private String mAudioWaveformFilename;
- private MediaArtistNativeHelper mMANativeHelper;
- private VideoEditorImpl mVideoEditor;
- private final int mVideoRotationDegree;
- /**
- * The audio waveform data
- */
- private SoftReference<WaveformData> mWaveformData;
-
- /**
- * An object of this type cannot be instantiated with a default constructor
- */
- @SuppressWarnings("unused")
- private MediaVideoItem() throws IOException {
- this(null, null, null, RENDERING_MODE_BLACK_BORDER);
- }
-
- /**
- * Constructor
- *
- * @param editor The video editor reference
- * @param mediaItemId The MediaItem id
- * @param filename The image file name
- * @param renderingMode The rendering mode
- *
- * @throws IOException if the file cannot be opened for reading
- */
- public MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
- int renderingMode) throws IOException {
- this(editor, mediaItemId, filename, renderingMode, 0, END_OF_FILE, 100, false, null);
- }
-
- /**
- * Constructor
- *
- * @param editor The video editor reference
- * @param mediaItemId The MediaItem id
- * @param filename The image file name
- * @param renderingMode The rendering mode
- * @param beginMs Start time in milliseconds. Set to 0 to extract from the
- * beginning
- * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to
- * extract until the end
- * @param volumePercent in %/. 100% means no change; 50% means half value, 200%
- * means double, 0% means silent.
- * @param muted true if the audio is muted
- * @param audioWaveformFilename The name of the audio waveform file
- *
- * @throws IOException if the file cannot be opened for reading
- */
- MediaVideoItem(VideoEditor editor, String mediaItemId, String filename,
- int renderingMode, long beginMs, long endMs, int volumePercent, boolean muted,
- String audioWaveformFilename) throws IOException {
- super(editor, mediaItemId, filename, renderingMode);
-
- if (editor instanceof VideoEditorImpl) {
- mMANativeHelper = ((VideoEditorImpl)editor).getNativeContext();
- mVideoEditor = ((VideoEditorImpl)editor);
- }
-
- final Properties properties;
- try {
- properties = mMANativeHelper.getMediaProperties(filename);
- } catch ( Exception e) {
- throw new IllegalArgumentException(e.getMessage() + " : " + filename);
- }
-
- /** Check the platform specific maximum import resolution */
- VideoEditorProfile veProfile = VideoEditorProfile.get();
- if (veProfile == null) {
- throw new RuntimeException("Can't get the video editor profile");
- }
- final int maxInputWidth = veProfile.maxInputVideoFrameWidth;
- final int maxInputHeight = veProfile.maxInputVideoFrameHeight;
- if ((properties.width > maxInputWidth) ||
- (properties.height > maxInputHeight)) {
- throw new IllegalArgumentException(
- "Unsupported import resolution. Supported maximum width:" +
- maxInputWidth + " height:" + maxInputHeight +
- ", current width:" + properties.width +
- " height:" + properties.height);
- }
- /** Check the platform specific maximum video profile and level */
- if (!properties.profileSupported) {
- throw new IllegalArgumentException(
- "Unsupported video profile " + properties.profile);
- }
- if (!properties.levelSupported) {
- throw new IllegalArgumentException(
- "Unsupported video level " + properties.level);
- }
- switch (mMANativeHelper.getFileType(properties.fileType)) {
- case MediaProperties.FILE_3GP:
- case MediaProperties.FILE_MP4:
- case MediaProperties.FILE_M4V:
- break;
-
- default:
- throw new IllegalArgumentException("Unsupported Input File Type");
- }
-
- switch (mMANativeHelper.getVideoCodecType(properties.videoFormat)) {
- case MediaProperties.VCODEC_H263:
- case MediaProperties.VCODEC_H264:
- case MediaProperties.VCODEC_MPEG4:
- break;
-
- default:
- throw new IllegalArgumentException("Unsupported Video Codec Format in Input File");
- }
-
- mWidth = properties.width;
- mHeight = properties.height;
- mAspectRatio = mMANativeHelper.getAspectRatio(properties.width,
- properties.height);
- mFileType = mMANativeHelper.getFileType(properties.fileType);
- mVideoType = mMANativeHelper.getVideoCodecType(properties.videoFormat);
- mVideoProfile = properties.profile;
- mVideoLevel = properties.level;
- mDurationMs = properties.videoDuration;
- mVideoBitrate = properties.videoBitrate;
- mAudioBitrate = properties.audioBitrate;
- mFps = (int)properties.averageFrameRate;
- mAudioType = mMANativeHelper.getAudioCodecType(properties.audioFormat);
- mAudioChannels = properties.audioChannels;
- mAudioSamplingFrequency = properties.audioSamplingFrequency;
- mBeginBoundaryTimeMs = beginMs;
- mEndBoundaryTimeMs = endMs == END_OF_FILE ? mDurationMs : endMs;
- mVolumePercentage = volumePercent;
- mMuted = muted;
- mAudioWaveformFilename = audioWaveformFilename;
- if (audioWaveformFilename != null) {
- mWaveformData = new SoftReference<WaveformData>(
- new WaveformData(audioWaveformFilename));
- } else {
- mWaveformData = null;
- }
- mVideoRotationDegree = properties.videoRotation;
- }
-
- /**
- * Sets the start and end marks for trimming a video media item.
- * This method will adjust the duration of bounding transitions, effects
- * and overlays if the current duration of the transactions become greater
- * than the maximum allowable duration.
- *
- * @param beginMs Start time in milliseconds. Set to 0 to extract from the
- * beginning
- * @param endMs End time in milliseconds. Set to {@link #END_OF_FILE} to
- * extract until the end
- *
- * @throws IllegalArgumentException if the start time is greater or equal than
- * end time, the end time is beyond the file duration, the start time
- * is negative
- */
- public void setExtractBoundaries(long beginMs, long endMs) {
- if (beginMs > mDurationMs) {
- throw new IllegalArgumentException("setExtractBoundaries: Invalid start time");
- }
-
- if (endMs > mDurationMs) {
- throw new IllegalArgumentException("setExtractBoundaries: Invalid end time");
- }
-
- if ((endMs != -1) && (beginMs >= endMs) ) {
- throw new IllegalArgumentException("setExtractBoundaries: Start time is greater than end time");
- }
-
- if ((beginMs < 0) || ((endMs != -1) && (endMs < 0))) {
- throw new IllegalArgumentException("setExtractBoundaries: Start time or end time is negative");
- }
-
- mMANativeHelper.setGeneratePreview(true);
-
- if (beginMs != mBeginBoundaryTimeMs) {
- if (mBeginTransition != null) {
- mBeginTransition.invalidate();
- }
- }
-
- if (endMs != mEndBoundaryTimeMs) {
- if (mEndTransition != null) {
- mEndTransition.invalidate();
- }
- }
-
- mBeginBoundaryTimeMs = beginMs;
- mEndBoundaryTimeMs = endMs;
- adjustTransitions();
- mVideoEditor.updateTimelineDuration();
- /**
- * Note that the start and duration of any effects and overlays are
- * not adjusted nor are they automatically removed if they fall
- * outside the new boundaries.
- */
- }
-
- /**
- * @return The boundary begin time
- */
- public long getBoundaryBeginTime() {
- return mBeginBoundaryTimeMs;
- }
-
- /**
- * @return The boundary end time
- */
- public long getBoundaryEndTime() {
- return mEndBoundaryTimeMs;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public void addEffect(Effect effect) {
- if (effect instanceof EffectKenBurns) {
- throw new IllegalArgumentException("Ken Burns effects cannot be applied to MediaVideoItem");
- }
- super.addEffect(effect);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public Bitmap getThumbnail(int width, int height, long timeMs) {
- if (timeMs > mDurationMs) {
- throw new IllegalArgumentException("Time Exceeds duration");
- }
-
- if (timeMs < 0) {
- throw new IllegalArgumentException("Invalid Time duration");
- }
-
- if ((width <= 0) || (height <= 0)) {
- throw new IllegalArgumentException("Invalid Dimensions");
- }
-
- if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
- int temp = width;
- width = height;
- height = temp;
- }
-
- return mMANativeHelper.getPixels(
- getFilename(), width, height, timeMs, mVideoRotationDegree);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public void getThumbnailList(int width, int height,
- long startMs, long endMs,
- int thumbnailCount,
- int[] indices,
- GetThumbnailListCallback callback)
- throws IOException {
- if (startMs > endMs) {
- throw new IllegalArgumentException("Start time is greater than end time");
- }
-
- if (endMs > mDurationMs) {
- throw new IllegalArgumentException("End time is greater than file duration");
- }
-
- if ((height <= 0) || (width <= 0)) {
- throw new IllegalArgumentException("Invalid dimension");
- }
-
- if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
- int temp = width;
- width = height;
- height = temp;
- }
-
- mMANativeHelper.getPixelsList(getFilename(), width, height,
- startMs, endMs, thumbnailCount, indices, callback,
- mVideoRotationDegree);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- void invalidateTransitions(long startTimeMs, long durationMs) {
- /**
- * Check if the item overlaps with the beginning and end transitions
- */
- if (mBeginTransition != null) {
- if (isOverlapping(startTimeMs, durationMs,
- mBeginBoundaryTimeMs, mBeginTransition.getDuration())) {
- mBeginTransition.invalidate();
- }
- }
-
- if (mEndTransition != null) {
- final long transitionDurationMs = mEndTransition.getDuration();
- if (isOverlapping(startTimeMs, durationMs,
- mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs)) {
- mEndTransition.invalidate();
- }
- }
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- void invalidateTransitions(long oldStartTimeMs, long oldDurationMs, long newStartTimeMs,
- long newDurationMs) {
- /**
- * Check if the item overlaps with the beginning and end transitions
- */
- if (mBeginTransition != null) {
- final long transitionDurationMs = mBeginTransition.getDuration();
- final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
- mBeginBoundaryTimeMs, transitionDurationMs);
- final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
- mBeginBoundaryTimeMs, transitionDurationMs);
- /**
- * Invalidate transition if:
- *
- * 1. New item overlaps the transition, the old one did not
- * 2. New item does not overlap the transition, the old one did
- * 3. New and old item overlap the transition if begin or end
- * time changed
- */
- if (newOverlap != oldOverlap) { // Overlap has changed
- mBeginTransition.invalidate();
- } else if (newOverlap) { // Both old and new overlap
- if ((oldStartTimeMs != newStartTimeMs) ||
- !(oldStartTimeMs + oldDurationMs > transitionDurationMs &&
- newStartTimeMs + newDurationMs > transitionDurationMs)) {
- mBeginTransition.invalidate();
- }
- }
- }
-
- if (mEndTransition != null) {
- final long transitionDurationMs = mEndTransition.getDuration();
- final boolean oldOverlap = isOverlapping(oldStartTimeMs, oldDurationMs,
- mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
- final boolean newOverlap = isOverlapping(newStartTimeMs, newDurationMs,
- mEndBoundaryTimeMs - transitionDurationMs, transitionDurationMs);
- /**
- * Invalidate transition if:
- *
- * 1. New item overlaps the transition, the old one did not
- * 2. New item does not overlap the transition, the old one did
- * 3. New and old item overlap the transition if begin or end
- * time changed
- */
- if (newOverlap != oldOverlap) { // Overlap has changed
- mEndTransition.invalidate();
- } else if (newOverlap) { // Both old and new overlap
- if ((oldStartTimeMs + oldDurationMs != newStartTimeMs + newDurationMs) ||
- ((oldStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs) ||
- newStartTimeMs > mEndBoundaryTimeMs - transitionDurationMs)) {
- mEndTransition.invalidate();
- }
- }
- }
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int getAspectRatio() {
- return mAspectRatio;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int getFileType() {
- return mFileType;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int getWidth() {
- if (mVideoRotationDegree == 90 ||
- mVideoRotationDegree == 270) {
- return mHeight;
- } else {
- return mWidth;
- }
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int getHeight() {
- if (mVideoRotationDegree == 90 ||
- mVideoRotationDegree == 270) {
- return mWidth;
- } else {
- return mHeight;
- }
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public long getDuration() {
- return mDurationMs;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public long getTimelineDuration() {
- return mEndBoundaryTimeMs - mBeginBoundaryTimeMs;
- }
-
- /**
- * Render a frame according to the playback (in the native aspect ratio) for
- * the specified media item. All effects and overlays applied to the media
- * item are ignored. The extract boundaries are also ignored. This method
- * can be used to playback frames when implementing trimming functionality.
- *
- * @param surfaceHolder SurfaceHolder used by the application
- * @param timeMs time corresponding to the frame to display (relative to the
- * the beginning of the media item).
- * @return The accurate time stamp of the frame that is rendered .
- * @throws IllegalStateException if a playback, preview or an export is
- * already in progress
- * @throws IllegalArgumentException if time is negative or greater than the
- * media item duration
- */
- public long renderFrame(SurfaceHolder surfaceHolder, long timeMs) {
- if (surfaceHolder == null) {
- throw new IllegalArgumentException("Surface Holder is null");
- }
-
- if (timeMs > mDurationMs || timeMs < 0) {
- throw new IllegalArgumentException("requested time not correct");
- }
-
- final Surface surface = surfaceHolder.getSurface();
- if (surface == null) {
- throw new RuntimeException("Surface could not be retrieved from Surface holder");
- }
-
- if (mFilename != null) {
- return mMANativeHelper.renderMediaItemPreviewFrame(surface,
- mFilename,timeMs,mWidth,mHeight);
- } else {
- return 0;
- }
- }
-
-
- /**
- * This API allows to generate a file containing the sample volume levels of
- * the Audio track of this media item. This function may take significant
- * time and is blocking. The file can be retrieved using
- * getAudioWaveformFilename().
- *
- * @param listener The progress listener
- *
- * @throws IOException if the output file cannot be created
- * @throws IllegalArgumentException if the mediaItem does not have a valid
- * Audio track
- */
- public void extractAudioWaveform(ExtractAudioWaveformProgressListener listener)
- throws IOException {
- int frameDuration = 0;
- int sampleCount = 0;
- final String projectPath = mMANativeHelper.getProjectPath();
- /**
- * Waveform file does not exist
- */
- if (mAudioWaveformFilename == null ) {
- /**
- * Since audioWaveformFilename will not be supplied,it is generated
- */
- String mAudioWaveFileName = null;
-
- mAudioWaveFileName =
- String.format(projectPath + "/" + "audioWaveformFile-"+ getId() + ".dat");
- /**
- * Logic to get frame duration = (no. of frames per sample * 1000)/
- * sampling frequency
- */
- if (mMANativeHelper.getAudioCodecType(mAudioType) ==
- MediaProperties.ACODEC_AMRNB ) {
- frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRNB*1000)/
- MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
- sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRNB;
- } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
- MediaProperties.ACODEC_AMRWB ) {
- frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AMRWB * 1000)/
- MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
- sampleCount = MediaProperties.SAMPLES_PER_FRAME_AMRWB;
- } else if (mMANativeHelper.getAudioCodecType(mAudioType) ==
- MediaProperties.ACODEC_AAC_LC ) {
- frameDuration = (MediaProperties.SAMPLES_PER_FRAME_AAC * 1000)/
- MediaProperties.DEFAULT_SAMPLING_FREQUENCY;
- sampleCount = MediaProperties.SAMPLES_PER_FRAME_AAC;
- }
-
- mMANativeHelper.generateAudioGraph( getId(),
- mFilename,
- mAudioWaveFileName,
- frameDuration,
- MediaProperties.DEFAULT_CHANNEL_COUNT,
- sampleCount,
- listener,
- true);
- /**
- * Record the generated file name
- */
- mAudioWaveformFilename = mAudioWaveFileName;
- }
- mWaveformData =
- new SoftReference<WaveformData>(new WaveformData(mAudioWaveformFilename));
- }
-
- /**
- * Get the audio waveform file name if {@link #extractAudioWaveform()} was
- * successful. The file format is as following:
- * <ul>
- * <li>first 4 bytes provide the number of samples for each value, as big-endian signed</li>
- * <li>4 following bytes is the total number of values in the file, as big-endian signed</li>
- * <li>all values follow as bytes Name is unique.</li>
- *</ul>
- * @return the name of the file, null if the file has not been computed or
- * if there is no Audio track in the mediaItem
- */
- String getAudioWaveformFilename() {
- return mAudioWaveformFilename;
- }
-
- /**
- * Invalidate the AudioWaveform File
- */
- void invalidate() {
- if (mAudioWaveformFilename != null) {
- new File(mAudioWaveformFilename).delete();
- mAudioWaveformFilename = null;
- }
- }
-
- /**
- * @return The waveform data
- */
- public WaveformData getWaveformData() throws IOException {
- if (mWaveformData == null) {
- return null;
- }
-
- WaveformData waveformData = mWaveformData.get();
- if (waveformData != null) {
- return waveformData;
- } else if (mAudioWaveformFilename != null) {
- try {
- waveformData = new WaveformData(mAudioWaveformFilename);
- } catch(IOException e) {
- throw e;
- }
- mWaveformData = new SoftReference<WaveformData>(waveformData);
- return waveformData;
- } else {
- return null;
- }
- }
-
- /**
- * Set volume of the Audio track of this mediaItem
- *
- * @param volumePercent in %/. 100% means no change; 50% means half value, 200%
- * means double, 0% means silent.
- * @throws UsupportedOperationException if volume value is not supported
- */
- public void setVolume(int volumePercent) {
- if ((volumePercent <0) || (volumePercent >100)) {
- throw new IllegalArgumentException("Invalid volume");
- }
-
- mVolumePercentage = volumePercent;
- }
-
- /**
- * Get the volume value of the audio track as percentage. Call of this
- * method before calling setVolume will always return 100%
- *
- * @return the volume in percentage
- */
- public int getVolume() {
- return mVolumePercentage;
- }
-
- /**
- * @param muted true to mute the media item
- */
- public void setMute(boolean muted) {
- mMANativeHelper.setGeneratePreview(true);
- mMuted = muted;
- if (mBeginTransition != null) {
- mBeginTransition.invalidate();
- }
- if (mEndTransition != null) {
- mEndTransition.invalidate();
- }
- }
-
- /**
- * @return true if the media item is muted
- */
- public boolean isMuted() {
- return mMuted;
- }
-
- /**
- * @return The video type
- */
- public int getVideoType() {
- return mVideoType;
- }
-
- /**
- * @return The video profile
- */
- public int getVideoProfile() {
- return mVideoProfile;
- }
-
- /**
- * @return The video profile
- */
- public int getVideoLevel() {
- return mVideoLevel;
- }
-
- /**
- * @return The video bitrate
- */
- public int getVideoBitrate() {
- return mVideoBitrate;
- }
-
- /**
- * @return The audio bitrate
- */
- public int getAudioBitrate() {
- return mAudioBitrate;
- }
-
- /**
- * @return The number of frames per second
- */
- public int getFps() {
- return mFps;
- }
-
- /**
- * @return The audio codec
- */
- public int getAudioType() {
- return mAudioType;
- }
-
- /**
- * @return The number of audio channels
- */
- public int getAudioChannels() {
- return mAudioChannels;
- }
-
- /**
- * @return The audio sample frequency
- */
- public int getAudioSamplingFrequency() {
- return mAudioSamplingFrequency;
- }
-
- /**
- * @return The Video media item properties in ClipSettings class object
- * {@link android.media.videoeditor.MediaArtistNativeHelper.ClipSettings}
- */
- ClipSettings getVideoClipProperties() {
- ClipSettings clipSettings = new ClipSettings();
- clipSettings.clipPath = getFilename();
- clipSettings.fileType = mMANativeHelper.getMediaItemFileType(getFileType());
- clipSettings.beginCutTime = (int)getBoundaryBeginTime();
- clipSettings.endCutTime = (int)getBoundaryEndTime();
- clipSettings.mediaRendering = mMANativeHelper.getMediaItemRenderingMode(getRenderingMode());
- clipSettings.rotationDegree = mVideoRotationDegree;
-
- return clipSettings;
- }
-}
diff --git a/media/java/android/media/videoeditor/Overlay.java b/media/java/android/media/videoeditor/Overlay.java
deleted file mode 100644
index a070eb4..0000000
--- a/media/java/android/media/videoeditor/Overlay.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * This is the super class for all Overlay classes.
- * {@hide}
- */
-public abstract class Overlay {
- /**
- * Instance variables
- */
- private final String mUniqueId;
- /**
- * The overlay owner
- */
- private final MediaItem mMediaItem;
- /**
- * user attributes
- */
- private final Map<String, String> mUserAttributes;
-
- protected long mStartTimeMs;
- protected long mDurationMs;
-
- /**
- * Default constructor
- */
- @SuppressWarnings("unused")
- private Overlay() {
- this(null, null, 0, 0);
- }
-
- /**
- * Constructor
- *
- * @param mediaItem The media item owner
- * @param overlayId The overlay id
- * @param startTimeMs The start time relative to the media item start time
- * @param durationMs The duration
- *
- * @throws IllegalArgumentException if the file type is not PNG or the
- * startTimeMs and durationMs are incorrect.
- */
- public Overlay(MediaItem mediaItem, String overlayId, long startTimeMs,
- long durationMs) {
- if (mediaItem == null) {
- throw new IllegalArgumentException("Media item cannot be null");
- }
-
- if ((startTimeMs<0) || (durationMs<0) ) {
- throw new IllegalArgumentException("Invalid start time and/OR duration");
- }
-
- if (startTimeMs + durationMs > mediaItem.getDuration()) {
- throw new IllegalArgumentException("Invalid start time and duration");
- }
-
- mMediaItem = mediaItem;
- mUniqueId = overlayId;
- mStartTimeMs = startTimeMs;
- mDurationMs = durationMs;
- mUserAttributes = new HashMap<String, String>();
- }
-
- /**
- * Get the overlay ID.
- *
- * @return The of the overlay
- */
- public String getId() {
- return mUniqueId;
- }
-
- /**
- * Get the duration of overlay.
- *
- * @return The duration of the overlay effect
- */
- public long getDuration() {
- return mDurationMs;
- }
-
- /**
- * If a preview or export is in progress, then this change is effective for
- * next preview or export session.
- *
- * @param durationMs The duration in milliseconds
- */
- public void setDuration(long durationMs) {
- if (durationMs < 0) {
- throw new IllegalArgumentException("Invalid duration");
- }
-
- if (mStartTimeMs + durationMs > mMediaItem.getDuration()) {
- throw new IllegalArgumentException("Duration is too large");
- }
-
- getMediaItem().getNativeContext().setGeneratePreview(true);
-
- final long oldDurationMs = mDurationMs;
- mDurationMs = durationMs;
-
- mMediaItem.invalidateTransitions(mStartTimeMs, oldDurationMs, mStartTimeMs, mDurationMs);
- }
-
- /**
- * Get the start time of overlay.
- *
- * @return the start time of the overlay
- */
- public long getStartTime() {
- return mStartTimeMs;
- }
-
- /**
- * Set the start time for the overlay. If a preview or export is in
- * progress, then this change is effective for next preview or export
- * session.
- *
- * @param startTimeMs start time in milliseconds
- */
- public void setStartTime(long startTimeMs) {
- if (startTimeMs + mDurationMs > mMediaItem.getDuration()) {
- throw new IllegalArgumentException("Start time is too large");
- }
-
- getMediaItem().getNativeContext().setGeneratePreview(true);
-
- final long oldStartTimeMs = mStartTimeMs;
- mStartTimeMs = startTimeMs;
-
- mMediaItem.invalidateTransitions(oldStartTimeMs, mDurationMs, mStartTimeMs, mDurationMs);
- }
-
- /**
- * Set the start time and duration
- *
- * @param startTimeMs start time in milliseconds
- * @param durationMs The duration in milliseconds
- */
- public void setStartTimeAndDuration(long startTimeMs, long durationMs) {
- if (startTimeMs + durationMs > mMediaItem.getDuration()) {
- throw new IllegalArgumentException("Invalid start time or duration");
- }
-
- getMediaItem().getNativeContext().setGeneratePreview(true);
-
- final long oldStartTimeMs = mStartTimeMs;
- final long oldDurationMs = mDurationMs;
-
- mStartTimeMs = startTimeMs;
- mDurationMs = durationMs;
-
- mMediaItem.invalidateTransitions(oldStartTimeMs, oldDurationMs, mStartTimeMs, mDurationMs);
- }
-
- /**
- * Get the media item owner.
- *
- * @return The media item owner.
- */
- public MediaItem getMediaItem() {
- return mMediaItem;
- }
-
- /**
- * Set a user attribute
- *
- * @param name The attribute name
- * @param value The attribute value
- */
- public void setUserAttribute(String name, String value) {
- mUserAttributes.put(name, value);
- }
-
- /**
- * Get the current user attributes set.
- *
- * @return The user attributes
- */
- public Map<String, String> getUserAttributes() {
- return mUserAttributes;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof Overlay)) {
- return false;
- }
- return mUniqueId.equals(((Overlay)object).mUniqueId);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return mUniqueId.hashCode();
- }
-}
diff --git a/media/java/android/media/videoeditor/OverlayFrame.java b/media/java/android/media/videoeditor/OverlayFrame.java
deleted file mode 100644
index d159df2..0000000
--- a/media/java/android/media/videoeditor/OverlayFrame.java
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.DataOutputStream;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap.CompressFormat;
-import android.util.Pair;
-
-
-/**
- * This class is used to overlay an image on top of a media item.
- * {@hide}
- */
-public class OverlayFrame extends Overlay {
- /**
- * Instance variables
- */
- private Bitmap mBitmap;
- private String mFilename;
- private String mBitmapFileName;
-
- private int mOFWidth;
- private int mOFHeight;
-
- /**
- * resized RGB Image dimensions
- */
- private int mResizedRGBWidth;
- private int mResizedRGBHeight;
-
- /**
- * The resize paint
- */
- private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-
- /**
- * An object of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private OverlayFrame() {
- this(null, null, (String)null, 0, 0);
- }
-
- /**
- * Constructor for an OverlayFrame
- *
- * @param mediaItem The media item owner
- * @param overlayId The overlay id
- * @param bitmap The bitmap to be used as an overlay. The size of the
- * bitmap must equal to the size of the media item to which it is
- * added. The bitmap is typically a decoded PNG file.
- * @param startTimeMs The overlay start time in milliseconds
- * @param durationMs The overlay duration in milliseconds
- *
- * @throws IllegalArgumentException if the file type is not PNG or the
- * startTimeMs and durationMs are incorrect.
- */
- public OverlayFrame(MediaItem mediaItem, String overlayId, Bitmap bitmap,
- long startTimeMs,long durationMs) {
- super(mediaItem, overlayId, startTimeMs, durationMs);
- mBitmap = bitmap;
- mFilename = null;
- mBitmapFileName = null;
- mResizedRGBWidth = 0;
- mResizedRGBHeight = 0;
- }
-
- /**
- * Constructor for an OverlayFrame. This constructor can be used to
- * restore the overlay after it was saved internally by the video editor.
- *
- * @param mediaItem The media item owner
- * @param overlayId The overlay id
- * @param filename The file name that contains the overlay.
- * @param startTimeMs The overlay start time in milliseconds
- * @param durationMs The overlay duration in milliseconds
- *
- * @throws IllegalArgumentException if the file type is not PNG or the
- * startTimeMs and durationMs are incorrect.
- */
- OverlayFrame(MediaItem mediaItem, String overlayId, String filename,
- long startTimeMs,long durationMs) {
- super(mediaItem, overlayId, startTimeMs, durationMs);
- mBitmapFileName = filename;
- mBitmap = BitmapFactory.decodeFile(mBitmapFileName);
- mFilename = null;
- mResizedRGBWidth = 0;
- mResizedRGBHeight = 0;
- }
-
- /**
- * Get the overlay bitmap.
- *
- * @return Get the overlay bitmap
- */
- public Bitmap getBitmap() {
- return mBitmap;
- }
-
- /**
- * Get the overlay bitmap.
- *
- * @return Get the overlay bitmap as png file.
- */
- String getBitmapImageFileName() {
- return mBitmapFileName;
- }
- /**
- * Set the overlay bitmap.
- *
- * @param bitmap The overlay bitmap.
- */
- public void setBitmap(Bitmap bitmap) {
- getMediaItem().getNativeContext().setGeneratePreview(true);
-
- invalidate();
-
- mBitmap = bitmap;
- if (mFilename != null) {
- /**
- * Delete the file
- */
- new File(mFilename).delete();
- /**
- * Invalidate the filename
- */
- mFilename = null;
- }
-
- /**
- * Invalidate the transitions if necessary
- */
- getMediaItem().invalidateTransitions(mStartTimeMs, mDurationMs);
- }
-
- /**
- * Get the file name of this overlay
- */
- String getFilename() {
- return mFilename;
- }
-
- /*
- * Set the file name of this overlay
- */
- void setFilename(String filename) {
- mFilename = filename;
- }
- /**
- * Save the overlay to the project folder
- *
- * @param path The path where the overlay will be saved
- *
- * @return The filename
- * @throws FileNotFoundException if the bitmap cannot be saved
- * @throws IOException if the bitmap file cannot be saved
- */
- String save(String path) throws FileNotFoundException, IOException {
- if (mFilename != null) {
- return mFilename;
- }
-
- // Create the compressed PNG file
- mBitmapFileName = path + "/" + "Overlay" + getId() + ".png";
- if (!(new File(mBitmapFileName).exists())) {
- final FileOutputStream out = new FileOutputStream (mBitmapFileName);
- mBitmap.compress(CompressFormat.PNG, 100, out);
- out.flush();
- out.close();
- }
-
- mOFWidth = mBitmap.getWidth();
- mOFHeight = mBitmap.getHeight();
-
- mFilename = path + "/" + "Overlay" + getId() + ".rgb";
-
- /* resize and save rgb as per project aspect ratio */
- MediaArtistNativeHelper nativeHelper = (super.getMediaItem()).getNativeContext();
-
- /* get height and width for story board aspect ratio */
- final Pair<Integer, Integer> maxResolution;
- final Pair<Integer, Integer>[] resolutions;
- resolutions = MediaProperties.getSupportedResolutions(nativeHelper.nativeHelperGetAspectRatio());
-
- // Get the highest resolution
- maxResolution = resolutions[resolutions.length - 1];
-
- /* Generate the rgb file with rendering mode */
- generateOverlayWithRenderingMode (super.getMediaItem(), this,
- maxResolution.second /* max Height */ ,
- maxResolution.first /* max Width */);
-
- return mFilename;
- }
-
- /**
- * Get the OverlayFrame Height
- */
- int getOverlayFrameHeight() {
- return mOFHeight;
- }
-
- /**
- * Get the OverlayFrame Width
- */
- int getOverlayFrameWidth() {
- return mOFWidth;
- }
-
- /*
- * Set the OverlayFrame Height
- */
- void setOverlayFrameHeight(int height) {
- mOFHeight = height;
- }
-
- /*
- * Set the OverlayFrame Width
- */
- void setOverlayFrameWidth(int width) {
- mOFWidth = width;
- }
-
- /*
- * Set the resized RGB widht and height
- */
- void setResizedRGBSize(int width, int height) {
- mResizedRGBWidth = width;
- mResizedRGBHeight = height;
- }
-
- /*
- * Get the resized RGB Height
- */
- int getResizedRGBSizeHeight() {
- return mResizedRGBHeight;
- }
-
- /*
- * Get the resized RGB Width
- */
- int getResizedRGBSizeWidth() {
- return mResizedRGBWidth;
- }
-
-
- /**
- * Delete the overlay files
- */
- void invalidate() {
- if (mBitmap != null) {
- mBitmap.recycle();
- mBitmap = null;
- }
-
- if (mFilename != null) {
- new File(mFilename).delete();
- mFilename = null;
- }
-
- if (mBitmapFileName != null) {
- new File(mBitmapFileName).delete();
- mBitmapFileName = null;
- }
- }
-
- /**
- * Delete the overlay related files
- */
- void invalidateGeneratedFiles() {
- if (mFilename != null) {
- new File(mFilename).delete();
- mFilename = null;
- }
-
- if (mBitmapFileName != null) {
- new File(mBitmapFileName).delete();
- mBitmapFileName = null;
- }
- }
-
- void generateOverlayWithRenderingMode (MediaItem mediaItemsList, OverlayFrame overlay, int height , int width)
- throws FileNotFoundException, IOException {
-
- final MediaItem t = mediaItemsList;
-
- /* get the rendering mode */
- int renderMode = t.getRenderingMode();
-
- Bitmap overlayBitmap = ((OverlayFrame)overlay).getBitmap();
-
- /*
- * Check if the resize of Overlay is needed with rendering mode applied
- * because of change in export dimensions
- */
- int resizedRGBFileHeight = ((OverlayFrame)overlay).getResizedRGBSizeHeight();
- int resizedRGBFileWidth = ((OverlayFrame)overlay).getResizedRGBSizeWidth();
-
- /* Get original bitmap width if it is not resized */
- if(resizedRGBFileWidth == 0) {
- resizedRGBFileWidth = overlayBitmap.getWidth();
- }
- /* Get original bitmap height if it is not resized */
- if(resizedRGBFileHeight == 0) {
- resizedRGBFileHeight = overlayBitmap.getHeight();
- }
-
- if (resizedRGBFileWidth != width || resizedRGBFileHeight != height
- || (!(new File(((OverlayFrame)overlay).getFilename()).exists()))) {
- /*
- * Create the canvas bitmap
- */
- final Bitmap destBitmap = Bitmap.createBitmap((int)width,
- (int)height,
- Bitmap.Config.ARGB_8888);
- final Canvas overlayCanvas = new Canvas(destBitmap);
- final Rect destRect;
- final Rect srcRect;
-
- switch (renderMode) {
- case MediaItem.RENDERING_MODE_STRETCH: {
- destRect = new Rect(0, 0, overlayCanvas.getWidth(),
- overlayCanvas.getHeight());
- srcRect = new Rect(0, 0, overlayBitmap.getWidth(),
- overlayBitmap.getHeight());
- break;
- }
-
- case MediaItem.RENDERING_MODE_BLACK_BORDER: {
- int left, right, top, bottom;
- float aROverlayImage, aRCanvas;
- aROverlayImage = (float)(overlayBitmap.getWidth()) /
- (float)(overlayBitmap.getHeight());
-
- aRCanvas = (float)(overlayCanvas.getWidth()) /
- (float)(overlayCanvas.getHeight());
-
- if (aROverlayImage > aRCanvas) {
- int newHeight = ((overlayCanvas.getWidth() * overlayBitmap.getHeight())
- / overlayBitmap.getWidth());
- left = 0;
- top = (overlayCanvas.getHeight() - newHeight) / 2;
- right = overlayCanvas.getWidth();
- bottom = top + newHeight;
- } else {
- int newWidth = ((overlayCanvas.getHeight() * overlayBitmap.getWidth())
- / overlayBitmap.getHeight());
- left = (overlayCanvas.getWidth() - newWidth) / 2;
- top = 0;
- right = left + newWidth;
- bottom = overlayCanvas.getHeight();
- }
-
- destRect = new Rect(left, top, right, bottom);
- srcRect = new Rect(0, 0, overlayBitmap.getWidth(), overlayBitmap.getHeight());
- break;
- }
-
- case MediaItem.RENDERING_MODE_CROPPING: {
- // Calculate the source rect
- int left, right, top, bottom;
- float aROverlayImage, aRCanvas;
- aROverlayImage = (float)(overlayBitmap.getWidth()) /
- (float)(overlayBitmap.getHeight());
- aRCanvas = (float)(overlayCanvas.getWidth()) /
- (float)(overlayCanvas.getHeight());
- if (aROverlayImage < aRCanvas) {
- int newHeight = ((overlayBitmap.getWidth() * overlayCanvas.getHeight())
- / overlayCanvas.getWidth());
-
- left = 0;
- top = (overlayBitmap.getHeight() - newHeight) / 2;
- right = overlayBitmap.getWidth();
- bottom = top + newHeight;
- } else {
- int newWidth = ((overlayBitmap.getHeight() * overlayCanvas.getWidth())
- / overlayCanvas.getHeight());
- left = (overlayBitmap.getWidth() - newWidth) / 2;
- top = 0;
- right = left + newWidth;
- bottom = overlayBitmap.getHeight();
- }
-
- srcRect = new Rect(left, top, right, bottom);
- destRect = new Rect(0, 0, overlayCanvas.getWidth(), overlayCanvas.getHeight());
- break;
- }
-
- default: {
- throw new IllegalStateException("Rendering mode: " + renderMode);
- }
- }
-
- overlayCanvas.drawBitmap(overlayBitmap, srcRect, destRect, sResizePaint);
- overlayCanvas.setBitmap(null);
-
- /*
- * Write to the dest file
- */
- String outFileName = ((OverlayFrame)overlay).getFilename();
-
- /*
- * Save the image to same rgb file
- */
- if (outFileName != null) {
- new File(outFileName).delete();
- }
-
- final FileOutputStream fl = new FileOutputStream(outFileName);
- final DataOutputStream dos = new DataOutputStream(fl);
-
- /*
- * Populate the rgb file with bitmap data
- */
- final int [] framingBuffer = new int[width];
- ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
- IntBuffer intBuffer;
-
- byte[] array = byteBuffer.array();
- int tmp = 0;
- while(tmp < height) {
- destBitmap.getPixels(framingBuffer,0,width,0,tmp,width,1);
- intBuffer = byteBuffer.asIntBuffer();
- intBuffer.put(framingBuffer,0,width);
- dos.write(array);
- tmp += 1;
- }
- fl.flush();
- fl.close();
-
- /*
- * Set the resized RGB width and height
- */
- ((OverlayFrame)overlay).setResizedRGBSize(width, height);
- }
- }
-}
diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java
deleted file mode 100644
index fa9d26d..0000000
--- a/media/java/android/media/videoeditor/Transition.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import android.media.videoeditor.MediaArtistNativeHelper.AlphaMagicSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.AudioTransition;
-import android.media.videoeditor.MediaArtistNativeHelper.ClipSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.EditSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.EffectSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.SlideTransitionSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.TransitionSettings;
-import android.media.videoeditor.MediaArtistNativeHelper.VideoTransition;
-
-/**
- * This class is super class for all transitions. Transitions (with the
- * exception of TransitionAtStart and TransitioAtEnd) can only be inserted
- * between media items.
- *
- * Adding a transition between MediaItems makes the
- * duration of the storyboard shorter by the duration of the Transition itself.
- * As a result, if the duration of the transition is larger than the smaller
- * duration of the two MediaItems associated with the Transition, an exception
- * will be thrown.
- *
- * During a transition, the audio track are cross-fading
- * automatically. {@hide}
- */
-public abstract class Transition {
- /**
- * The transition behavior
- */
- private static final int BEHAVIOR_MIN_VALUE = 0;
-
- /** The transition starts slowly and speed up */
- public static final int BEHAVIOR_SPEED_UP = 0;
- /** The transition start fast and speed down */
- public static final int BEHAVIOR_SPEED_DOWN = 1;
- /** The transition speed is constant */
- public static final int BEHAVIOR_LINEAR = 2;
- /** The transition starts fast and ends fast with a slow middle */
- public static final int BEHAVIOR_MIDDLE_SLOW = 3;
- /** The transition starts slowly and ends slowly with a fast middle */
- public static final int BEHAVIOR_MIDDLE_FAST = 4;
-
- private static final int BEHAVIOR_MAX_VALUE = 4;
-
- /**
- * The unique id of the transition
- */
- private final String mUniqueId;
-
- /**
- * The transition is applied at the end of this media item
- */
- private final MediaItem mAfterMediaItem;
- /**
- * The transition is applied at the beginning of this media item
- */
- private final MediaItem mBeforeMediaItem;
-
- /**
- * The transition behavior
- */
- protected final int mBehavior;
-
- /**
- * The transition duration
- */
- protected long mDurationMs;
-
- /**
- * The transition filename
- */
- protected String mFilename;
-
- protected MediaArtistNativeHelper mNativeHelper;
- /**
- * An object of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private Transition() {
- this(null, null, null, 0, 0);
- }
-
- /**
- * Constructor
- *
- * @param transitionId The transition id
- * @param afterMediaItem The transition is applied to the end of this
- * media item
- * @param beforeMediaItem The transition is applied to the beginning of
- * this media item
- * @param durationMs The duration of the transition in milliseconds
- * @param behavior The transition behavior
- */
- protected Transition(String transitionId, MediaItem afterMediaItem,
- MediaItem beforeMediaItem,long durationMs,
- int behavior) {
- if (behavior < BEHAVIOR_MIN_VALUE || behavior > BEHAVIOR_MAX_VALUE) {
- throw new IllegalArgumentException("Invalid behavior: " + behavior);
- }
- if ((afterMediaItem == null) && (beforeMediaItem == null)) {
- throw new IllegalArgumentException("Null media items");
- }
- mUniqueId = transitionId;
- mAfterMediaItem = afterMediaItem;
- mBeforeMediaItem = beforeMediaItem;
- mDurationMs = durationMs;
- mBehavior = behavior;
- mNativeHelper = null;
- if (durationMs > getMaximumDuration()) {
- throw new IllegalArgumentException("The duration is too large");
- }
- if (afterMediaItem != null) {
- mNativeHelper = afterMediaItem.getNativeContext();
- }else {
- mNativeHelper = beforeMediaItem.getNativeContext();
- }
- }
-
- /**
- * Get the ID of the transition.
- *
- * @return The ID of the transition
- */
- public String getId() {
- return mUniqueId;
- }
-
- /**
- * Get the media item at the end of which the transition is applied.
- *
- * @return The media item at the end of which the transition is applied
- */
- public MediaItem getAfterMediaItem() {
- return mAfterMediaItem;
- }
-
- /**
- * Get the media item at the beginning of which the transition is applied.
- *
- * @return The media item at the beginning of which the transition is
- * applied
- */
- public MediaItem getBeforeMediaItem() {
- return mBeforeMediaItem;
- }
-
- /**
- * Set the duration of the transition.
- *
- * @param durationMs the duration of the transition in milliseconds
- */
- public void setDuration(long durationMs) {
- if (durationMs > getMaximumDuration()) {
- throw new IllegalArgumentException("The duration is too large");
- }
-
- mDurationMs = durationMs;
- invalidate();
- mNativeHelper.setGeneratePreview(true);
- }
-
- /**
- * Get the duration of the transition.
- *
- * @return the duration of the transition in milliseconds
- */
- public long getDuration() {
- return mDurationMs;
- }
-
- /**
- * The duration of a transition cannot be greater than half of the minimum
- * duration of the bounding media items.
- *
- * @return The maximum duration of this transition
- */
- public long getMaximumDuration() {
- if (mAfterMediaItem == null) {
- return mBeforeMediaItem.getTimelineDuration() / 2;
- } else if (mBeforeMediaItem == null) {
- return mAfterMediaItem.getTimelineDuration() / 2;
- } else {
- return (Math.min(mAfterMediaItem.getTimelineDuration(),
- mBeforeMediaItem.getTimelineDuration()) / 2);
- }
- }
-
- /**
- * Get the behavior of the transition.
- *
- * @return The behavior
- */
- public int getBehavior() {
- return mBehavior;
- }
-
- /**
- * Get the transition data.
- *
- * @return The transition data in TransitionSettings object
- * {@link android.media.videoeditor.MediaArtistNativeHelper.TransitionSettings}
- */
- TransitionSettings getTransitionSettings() {
- TransitionAlpha transitionAlpha = null;
- TransitionSliding transitionSliding = null;
- TransitionCrossfade transitionCrossfade = null;
- TransitionFadeBlack transitionFadeBlack = null;
- TransitionSettings transitionSetting = null;
- transitionSetting = new TransitionSettings();
- transitionSetting.duration = (int)getDuration();
- if (this instanceof TransitionAlpha) {
- transitionAlpha = (TransitionAlpha)this;
- transitionSetting.videoTransitionType = VideoTransition.ALPHA_MAGIC;
- transitionSetting.audioTransitionType = AudioTransition.CROSS_FADE;
- transitionSetting.transitionBehaviour = mNativeHelper
- .getVideoTransitionBehaviour(transitionAlpha.getBehavior());
- transitionSetting.alphaSettings = new AlphaMagicSettings();
- transitionSetting.slideSettings = null;
- transitionSetting.alphaSettings.file = transitionAlpha.getPNGMaskFilename();
- transitionSetting.alphaSettings.blendingPercent = transitionAlpha.getBlendingPercent();
- transitionSetting.alphaSettings.invertRotation = transitionAlpha.isInvert();
- transitionSetting.alphaSettings.rgbWidth = transitionAlpha.getRGBFileWidth();
- transitionSetting.alphaSettings.rgbHeight = transitionAlpha.getRGBFileHeight();
-
- } else if (this instanceof TransitionSliding) {
- transitionSliding = (TransitionSliding)this;
- transitionSetting.videoTransitionType = VideoTransition.SLIDE_TRANSITION;
- transitionSetting.audioTransitionType = AudioTransition.CROSS_FADE;
- transitionSetting.transitionBehaviour = mNativeHelper
- .getVideoTransitionBehaviour(transitionSliding.getBehavior());
- transitionSetting.alphaSettings = null;
- transitionSetting.slideSettings = new SlideTransitionSettings();
- transitionSetting.slideSettings.direction = mNativeHelper
- .getSlideSettingsDirection(transitionSliding.getDirection());
- } else if (this instanceof TransitionCrossfade) {
- transitionCrossfade = (TransitionCrossfade)this;
- transitionSetting.videoTransitionType = VideoTransition.CROSS_FADE;
- transitionSetting.audioTransitionType = AudioTransition.CROSS_FADE;
- transitionSetting.transitionBehaviour = mNativeHelper
- .getVideoTransitionBehaviour(transitionCrossfade.getBehavior());
- transitionSetting.alphaSettings = null;
- transitionSetting.slideSettings = null;
- } else if (this instanceof TransitionFadeBlack) {
- transitionFadeBlack = (TransitionFadeBlack)this;
- transitionSetting.videoTransitionType = VideoTransition.FADE_BLACK;
- transitionSetting.audioTransitionType = AudioTransition.CROSS_FADE;
- transitionSetting.transitionBehaviour = mNativeHelper
- .getVideoTransitionBehaviour(transitionFadeBlack.getBehavior());
- transitionSetting.alphaSettings = null;
- transitionSetting.slideSettings = null;
- }
-
- return transitionSetting;
- }
-
- /**
- * Checks if the effect and overlay applied on a media item
- * overlaps with the transition on media item.
- *
- * @param m The media item
- * @param clipSettings The ClipSettings object
- * @param clipNo The clip no.(out of the two media items
- * associated with current transition)for which the effect
- * clip should be generated
- * @return List of effects that overlap with the transition
- */
-
- List<EffectSettings> isEffectandOverlayOverlapping(MediaItem m, ClipSettings clipSettings,
- int clipNo) {
- List<Effect> effects;
- List<Overlay> overlays;
- List<EffectSettings> effectSettings = new ArrayList<EffectSettings>();
- EffectSettings tmpEffectSettings;
-
- overlays = m.getAllOverlays();
- for (Overlay overlay : overlays) {
- tmpEffectSettings = mNativeHelper.getOverlaySettings((OverlayFrame)overlay);
- mNativeHelper.adjustEffectsStartTimeAndDuration(tmpEffectSettings,
- clipSettings.beginCutTime, clipSettings.endCutTime);
- if (tmpEffectSettings.duration != 0) {
- effectSettings.add(tmpEffectSettings);
- }
- }
-
- effects = m.getAllEffects();
- for (Effect effect : effects) {
- if (effect instanceof EffectColor) {
- tmpEffectSettings = mNativeHelper.getEffectSettings((EffectColor)effect);
- mNativeHelper.adjustEffectsStartTimeAndDuration(tmpEffectSettings,
- clipSettings.beginCutTime, clipSettings.endCutTime);
- if (tmpEffectSettings.duration != 0) {
- if (m instanceof MediaVideoItem) {
- tmpEffectSettings.fiftiesFrameRate = mNativeHelper
- .GetClosestVideoFrameRate(((MediaVideoItem)m).getFps());
- }
- effectSettings.add(tmpEffectSettings);
- }
- }
- }
-
- return effectSettings;
- }
-
- /**
- * Generate the video clip for the specified transition. This method may
- * block for a significant amount of time. Before the method completes
- * execution it sets the mFilename to the name of the newly generated
- * transition video clip file.
- */
- void generate() {
- MediaItem m1 = this.getAfterMediaItem();
- MediaItem m2 = this.getBeforeMediaItem();
- ClipSettings clipSettings1 = new ClipSettings();
- ClipSettings clipSettings2 = new ClipSettings();
- TransitionSettings transitionSetting = null;
- EditSettings editSettings = new EditSettings();
- List<EffectSettings> effectSettings_clip1;
- List<EffectSettings> effectSettings_clip2;
-
- String output = null;
-
- if (mNativeHelper == null) {
- if (m1 != null)
- mNativeHelper = m1.getNativeContext();
- else if (m2 != null)
- mNativeHelper = m2.getNativeContext();
- }
- transitionSetting = getTransitionSettings();
- if (m1 != null && m2 != null) {
- /* transition between media items */
- clipSettings1 = m1.getClipSettings();
- clipSettings2 = m2.getClipSettings();
- clipSettings1.beginCutTime = (int)(clipSettings1.endCutTime -
- this.mDurationMs);
- clipSettings2.endCutTime = (int)(clipSettings2.beginCutTime +
- this.mDurationMs);
- /*
- * Check how many effects and overlays overlap with transition and
- * generate effect clip first if there is any overlap
- */
- effectSettings_clip1 = isEffectandOverlayOverlapping(m1, clipSettings1,1);
- effectSettings_clip2 = isEffectandOverlayOverlapping(m2, clipSettings2,2);
- for (int index = 0; index < effectSettings_clip2.size(); index++ ) {
- effectSettings_clip2.get(index).startTime += this.mDurationMs;
- }
- editSettings.effectSettingsArray =
- new EffectSettings[effectSettings_clip1.size()
- + effectSettings_clip2.size()];
- int i=0,j=0;
- while (i < effectSettings_clip1.size()) {
- editSettings.effectSettingsArray[j] = effectSettings_clip1.get(i);
- i++;
- j++;
- }
- i=0;
- while (i < effectSettings_clip2.size()) {
- editSettings.effectSettingsArray[j] = effectSettings_clip2.get(i);
- i++;
- j++;
- }
- } else if (m1 == null && m2 != null) {
- /* begin transition at first media item */
- m2.generateBlankFrame(clipSettings1);
- clipSettings2 = m2.getClipSettings();
- clipSettings1.endCutTime = (int)(this.mDurationMs + 50);
- clipSettings2.endCutTime = (int)(clipSettings2.beginCutTime +
- this.mDurationMs);
- /*
- * Check how many effects and overlays overlap with transition and
- * generate effect clip first if there is any overlap
- */
- effectSettings_clip2 = isEffectandOverlayOverlapping(m2, clipSettings2,2);
- for (int index = 0; index < effectSettings_clip2.size(); index++ ) {
- effectSettings_clip2.get(index).startTime += this.mDurationMs;
- }
- editSettings.effectSettingsArray = new EffectSettings[effectSettings_clip2.size()];
- int i=0, j=0;
- while (i < effectSettings_clip2.size()) {
- editSettings.effectSettingsArray[j] = effectSettings_clip2.get(i);
- i++;
- j++;
- }
- } else if (m1 != null && m2 == null) {
- /* end transition at last media item */
- clipSettings1 = m1.getClipSettings();
- m1.generateBlankFrame(clipSettings2);
- clipSettings1.beginCutTime = (int)(clipSettings1.endCutTime -
- this.mDurationMs);
- clipSettings2.endCutTime = (int)(this.mDurationMs + 50);
- /*
- * Check how many effects and overlays overlap with transition and
- * generate effect clip first if there is any overlap
- */
- effectSettings_clip1 = isEffectandOverlayOverlapping(m1, clipSettings1,1);
- editSettings.effectSettingsArray = new EffectSettings[effectSettings_clip1.size()];
- int i=0,j=0;
- while (i < effectSettings_clip1.size()) {
- editSettings.effectSettingsArray[j] = effectSettings_clip1.get(i);
- i++;
- j++;
- }
- }
-
- editSettings.clipSettingsArray = new ClipSettings[2];
- editSettings.clipSettingsArray[0] = clipSettings1;
- editSettings.clipSettingsArray[1] = clipSettings2;
- editSettings.backgroundMusicSettings = null;
- editSettings.transitionSettingsArray = new TransitionSettings[1];
- editSettings.transitionSettingsArray[0] = transitionSetting;
- output = mNativeHelper.generateTransitionClip(editSettings, mUniqueId,
- m1, m2,this);
- setFilename(output);
- }
-
-
- /**
- * Set the transition filename.
- */
- void setFilename(String filename) {
- mFilename = filename;
- }
-
- /**
- * Get the transition filename.
- */
- String getFilename() {
- return mFilename;
- }
-
- /**
- * Remove any resources associated with this transition
- */
- void invalidate() {
- if (mFilename != null) {
- new File(mFilename).delete();
- mFilename = null;
- }
- }
-
- /**
- * Check if the transition is generated.
- *
- * @return true if the transition is generated
- */
- boolean isGenerated() {
- return (mFilename != null);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof Transition)) {
- return false;
- }
- return mUniqueId.equals(((Transition)object).mUniqueId);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return mUniqueId.hashCode();
- }
-}
diff --git a/media/java/android/media/videoeditor/TransitionAlpha.java b/media/java/android/media/videoeditor/TransitionAlpha.java
deleted file mode 100644
index 22788d4..0000000
--- a/media/java/android/media/videoeditor/TransitionAlpha.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
-
-/**
- * This class allows to render an "alpha blending" transition according to a
- * bitmap mask. The mask shows the shape of the transition all along the
- * duration of the transition: just before the transition, video 1 is fully
- * displayed. When the transition starts, as the time goes on, pixels of video 2
- * replace pixels of video 1 according to the gray scale pixel value of the
- * mask.
- * {@hide}
- */
-public class TransitionAlpha extends Transition {
- /** This is the input JPEG file for the mask */
- private final String mMaskFilename;
-
- /**
- * This is percentage (between 0 and 100) of blending between video 1 and
- * video 2 if this value equals 0, then the mask is strictly applied if this
- * value equals 100, then the mask is not at all applied (no transition
- * effect)
- */
- private final int mBlendingPercent;
-
- /**
- * If true, this value inverts the direction of the mask: white pixels of
- * the mask show video 2 pixels first black pixels of the mask show video 2
- * pixels last.
- */
- private final boolean mIsInvert;
-
-
- private int mWidth;
- private int mHeight;
- private String mRGBMaskFile;
-
- /**
- * An object of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private TransitionAlpha() {
- this(null, null, null, 0, 0, null, 0, false);
- }
-
- /**
- * Constructor
- *
- * @param transitionId The transition id
- * @param afterMediaItem The transition is applied to the end of this media
- * item
- * @param beforeMediaItem The transition is applied to the beginning of this
- * media item
- * @param durationMs duration of the transition in milliseconds
- * @param behavior behavior is one of the behavior defined in Transition
- * class
- * @param maskFilename JPEG file name. The dimension of the image
- * corresponds to 720p (16:9 aspect ratio). Mask files are
- * shared between video editors and can be created in the
- * projects folder (the parent folder for all projects).
- * @param blendingPercent The blending percent applied
- * @param invert true to invert the direction of the alpha blending
- * @throws IllegalArgumentException if behavior is not supported, or if
- * direction are not supported.
- */
- public TransitionAlpha(String transitionId, MediaItem afterMediaItem,
- MediaItem beforeMediaItem, long durationMs, int behavior,
- String maskFilename, int blendingPercent, boolean invert) {
- super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);
-
- /**
- * Generate a RGB file for the supplied mask file
- */
- final BitmapFactory.Options dbo = new BitmapFactory.Options();
- dbo.inJustDecodeBounds = true;
- if (!new File(maskFilename).exists())
- throw new IllegalArgumentException("File not Found " + maskFilename);
- BitmapFactory.decodeFile(maskFilename, dbo);
-
- mWidth = dbo.outWidth;
- mHeight = dbo.outHeight;
-
- mRGBMaskFile = String.format(mNativeHelper.getProjectPath() +
- "/" + "mask" + transitionId+ ".rgb");
-
-
- FileOutputStream fl = null;
-
- try{
- fl = new FileOutputStream(mRGBMaskFile);
- } catch (IOException e) {
- /* catch IO exception */
- }
- final DataOutputStream dos = new DataOutputStream(fl);
-
- if (fl != null) {
- /**
- * Write to rgb file
- */
- Bitmap imageBitmap = BitmapFactory.decodeFile(maskFilename);
- final int [] framingBuffer = new int[mWidth];
- ByteBuffer byteBuffer = ByteBuffer.allocate(framingBuffer.length * 4);
- IntBuffer intBuffer;
-
- byte[] array = byteBuffer.array();
- int tmp = 0;
- while (tmp < mHeight) {
- imageBitmap.getPixels(framingBuffer, 0, mWidth, 0, tmp,mWidth, 1);
- intBuffer = byteBuffer.asIntBuffer();
- intBuffer.put(framingBuffer,0,mWidth);
- try {
- dos.write(array);
- } catch (IOException e) {
- /* catch file write error */
- }
- tmp += 1;
- }
-
- imageBitmap.recycle();
- try{
- fl.close();
- }catch (IOException e) {
- /* file close error */
- }
- }
-
- /**
- * Capture the details
- */
- mMaskFilename = maskFilename;
- mBlendingPercent = blendingPercent;
- mIsInvert = invert;
- }
-
- public int getRGBFileWidth() {
- return mWidth;
- }
-
- public int getRGBFileHeight() {
- return mHeight;
- }
-
- public String getPNGMaskFilename() {
- return mRGBMaskFile;
- }
-
- /**
- * Get the blending percentage
- *
- * @return The blending percentage
- */
- public int getBlendingPercent() {
- return mBlendingPercent;
- }
-
- /**
- * Get the filename of the mask.
- *
- * @return The mask filename
- */
- public String getMaskFilename() {
- return mMaskFilename;
- }
-
- /**
- * Check if the alpha blending direction is inverted.
- *
- * @return true if the direction of the alpha blending is inverted
- */
- public boolean isInvert() {
- return mIsInvert;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- public void generate() {
- super.generate();
- }
-}
diff --git a/media/java/android/media/videoeditor/TransitionCrossfade.java b/media/java/android/media/videoeditor/TransitionCrossfade.java
deleted file mode 100644
index 417c64e..0000000
--- a/media/java/android/media/videoeditor/TransitionCrossfade.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-
-/**
- * This class allows to render a crossfade (dissolve) effect transition between
- * two videos
- * {@hide}
- */
-public class TransitionCrossfade extends Transition {
- /**
- * An object of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private TransitionCrossfade() {
- this(null, null, null, 0, 0);
- }
-
- /**
- * Constructor
- *
- * @param transitionId The transition id
- * @param afterMediaItem The transition is applied to the end of this
- * media item
- * @param beforeMediaItem The transition is applied to the beginning of
- * this media item
- * @param durationMs duration of the transition in milliseconds
- * @param behavior behavior is one of the behavior defined in Transition
- * class
- *
- * @throws IllegalArgumentException if behavior is not supported.
- */
- public TransitionCrossfade(String transitionId, MediaItem afterMediaItem,
- MediaItem beforeMediaItem, long durationMs, int behavior) {
- super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- void generate() {
- super.generate();
- }
-}
diff --git a/media/java/android/media/videoeditor/TransitionFadeBlack.java b/media/java/android/media/videoeditor/TransitionFadeBlack.java
deleted file mode 100644
index da07cf0..0000000
--- a/media/java/android/media/videoeditor/TransitionFadeBlack.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-
-/**
- * This class is used to render a fade to black and fade from black transition
- * between two media items.
- * {@hide}
- */
-public class TransitionFadeBlack extends Transition {
- /**
- * An object of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private TransitionFadeBlack() {
- this(null, null, null, 0, 0);
- }
-
- /**
- * Constructor
- *
- * @param transitionId The transition id
- * @param afterMediaItem The transition is applied to the end of this
- * media item
- * @param beforeMediaItem The transition is applied to the beginning of
- * this media item
- * @param durationMs duration of the transition
- * @param behavior behavior is one of the behavior defined in Transition
- * class
- *
- * @throws IllegalArgumentException if behavior is not supported.
- */
- public TransitionFadeBlack(String transitionId, MediaItem afterMediaItem,
- MediaItem beforeMediaItem, long durationMs, int behavior) {
- super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- void generate() {
- super.generate();
- }
-}
diff --git a/media/java/android/media/videoeditor/TransitionSliding.java b/media/java/android/media/videoeditor/TransitionSliding.java
deleted file mode 100644
index 57610ab..0000000
--- a/media/java/android/media/videoeditor/TransitionSliding.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-/**
- * This class allows to create sliding transitions
- * {@hide}
- */
-public class TransitionSliding extends Transition {
-
- /** Video 1 is pushed to the right while video 2 is coming from left */
- public final static int DIRECTION_RIGHT_OUT_LEFT_IN = 0;
- /** Video 1 is pushed to the left while video 2 is coming from right */
- public static final int DIRECTION_LEFT_OUT_RIGHT_IN = 1;
- /** Video 1 is pushed to the top while video 2 is coming from bottom */
- public static final int DIRECTION_TOP_OUT_BOTTOM_IN = 2;
- /** Video 1 is pushed to the bottom while video 2 is coming from top */
- public static final int DIRECTION_BOTTOM_OUT_TOP_IN = 3;
-
- // The sliding transitions
- private final int mSlidingDirection;
-
- /**
- * An object of this type cannot be instantiated by using the default
- * constructor
- */
- @SuppressWarnings("unused")
- private TransitionSliding() {
- this(null, null, null, 0, 0, 0);
- }
-
- /**
- * Constructor
- *
- * @param transitionId The transition id
- * @param afterMediaItem The transition is applied to the end of this
- * media item
- * @param beforeMediaItem The transition is applied to the beginning of
- * this media item
- * @param durationMs duration of the transition in milliseconds
- * @param behavior behavior is one of the behavior defined in Transition
- * class
- * @param direction direction shall be one of the supported directions like
- * RIGHT_OUT_LEFT_IN
- *
- * @throws IllegalArgumentException if behavior is not supported.
- */
- public TransitionSliding(String transitionId, MediaItem afterMediaItem,
- MediaItem beforeMediaItem, long durationMs, int behavior,
- int direction) {
- super(transitionId, afterMediaItem, beforeMediaItem, durationMs, behavior);
- switch (direction) {
- case DIRECTION_RIGHT_OUT_LEFT_IN:
- case DIRECTION_LEFT_OUT_RIGHT_IN:
- case DIRECTION_TOP_OUT_BOTTOM_IN:
- case DIRECTION_BOTTOM_OUT_TOP_IN:
- break;
-
- default:
- throw new IllegalArgumentException("Invalid direction");
- }
- mSlidingDirection = direction;
- }
-
- /**
- * Get the sliding direction.
- *
- * @return The sliding direction
- */
- public int getDirection() {
- return mSlidingDirection;
- }
-
- /*
- * {@inheritDoc}
- */
- @Override
- void generate() {
- super.generate();
- }
-}
diff --git a/media/java/android/media/videoeditor/VideoEditor.java b/media/java/android/media/videoeditor/VideoEditor.java
deleted file mode 100644
index 08d27d4..0000000
--- a/media/java/android/media/videoeditor/VideoEditor.java
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.CancellationException;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.view.SurfaceHolder;
-
-/**
- * This is the interface implemented by classes which provide video editing
- * functionality. The VideoEditor implementation class manages all input and
- * output files. Unless specifically mentioned, methods are blocking. A typical
- * editing session may consist of the following sequence of operations:
- *
- * <ul>
- * <li>Add a set of MediaItems</li>
- * <li>Apply a set of Transitions between MediaItems</li>
- * <li>Add Effects and Overlays to media items</li>
- * <li>Preview the movie at any time</li>
- * <li>Save the VideoEditor implementation class internal state</li>
- * <li>Release the VideoEditor implementation class instance by invoking
- * {@link #release()}
- * </ul>
- * The internal VideoEditor state consists of the following elements:
- * <ul>
- * <li>Ordered & trimmed MediaItems</li>
- * <li>Transition video clips</li>
- * <li>Overlays</li>
- * <li>Effects</li>
- * <li>Audio waveform for the background audio and MediaItems</li>
- * <li>Project thumbnail</li>
- * <li>Last exported movie.</li>
- * <li>Other project specific data such as the current aspect ratio.</li>
- * </ul>
- * {@hide}
- */
-public interface VideoEditor {
- /**
- * The file name of the project thumbnail
- */
- public static final String THUMBNAIL_FILENAME = "thumbnail.jpg";
-
- /**
- * Use this value instead of the specific end of the storyboard timeline
- * value.
- */
- public final static int DURATION_OF_STORYBOARD = -1;
-
- /**
- * Maximum supported file size
- */
- public static final long MAX_SUPPORTED_FILE_SIZE = 2147483648L;
-
- /**
- * This listener interface is used by the VideoEditor to emit preview
- * progress notifications. This callback should be invoked after the number
- * of frames specified by
- * {@link #startPreview(SurfaceHolder surfaceHolder, long fromMs,
- * int callbackAfterFrameCount, PreviewProgressListener listener)}
- */
- public interface PreviewProgressListener {
- /**
- * This method notifies the listener of the current time position while
- * previewing a project.
- *
- * @param videoEditor The VideoEditor instance
- * @param timeMs The current preview position (expressed in milliseconds
- * since the beginning of the storyboard timeline).
- * @param overlayData The overlay data (null if the overlay data
- * is unchanged)
- */
- public void onProgress(VideoEditor videoEditor, long timeMs,
- OverlayData overlayData);
- /**
- * This method notifies the listener when the preview is started
- * previewing a project.
- *
- * @param videoEditor The VideoEditor instance
- */
- public void onStart(VideoEditor videoEditor);
-
- /**
- * This method notifies the listener when the preview is stopped
- * previewing a project.
- *
- * @param videoEditor The VideoEditor instance
- */
- public void onStop(VideoEditor videoEditor);
-
- /**
- * This method notifies the listener when error has occurred during
- * previewing a project.
- *
- * @param videoEditor The VideoEditor instance
- * @param error The error that has occurred
- * FIXME: We should pass well-defined error code to the application;
- * but for now, we just pass whatever error code reported by the native layer.
- */
- public void onError(VideoEditor videoEditor, int error);
- }
-
- /**
- * This listener interface is used by the VideoEditor to emit export status
- * notifications.
- * {@link #export(String filename, ExportProgressListener listener,
- * int height, int bitrate)}
- */
- public interface ExportProgressListener {
- /**
- * This method notifies the listener of the progress status of a export
- * operation.
- *
- * @param videoEditor The VideoEditor instance
- * @param filename The name of the file which is in the process of being
- * exported.
- * @param progress The progress in %. At the beginning of the export,
- * this value is set to 0; at the end, the value is set to 100.
- */
- public void onProgress(VideoEditor videoEditor, String filename,
- int progress);
- }
-
- public interface MediaProcessingProgressListener {
- /**
- * Values used for the action parameter
- */
- public static final int ACTION_ENCODE = 1;
- public static final int ACTION_DECODE = 2;
-
- /**
- * This method notifies the listener of the progress status of
- * processing a media object such as a Transition, AudioTrack & Kenburns
- * This method may be called maximum 100 times for one operation.
- *
- * @param object The object that is being processed such as a Transition
- * or AudioTrack
- * @param action The type of processing being performed
- * @param progress The progress in %. At the beginning of the operation,
- * this value is set to 0; at the end, the value is set to 100.
- */
- public void onProgress(Object item, int action, int progress);
- }
-
- /**
- * The overlay data
- */
- public static final class OverlayData {
- // Instance variables
- private Bitmap mOverlayBitmap;
- private int mRenderingMode;
- private boolean mClear;
- private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-
- /**
- * Default constructor
- */
- public OverlayData() {
- mOverlayBitmap = null;
- mRenderingMode = MediaArtistNativeHelper.MediaRendering.BLACK_BORDERS;
- mClear = false;
- }
-
- /**
- * Releases the bitmap
- */
- public void release() {
- if (mOverlayBitmap != null) {
- mOverlayBitmap.recycle();
- mOverlayBitmap = null;
- }
- }
-
- /**
- * Check if the overlay needs to be rendered
- *
- * @return true if rendering is needed
- */
- public boolean needsRendering() {
- return (mClear || mOverlayBitmap != null);
- }
-
- /**
- * Store the overlay data
- *
- * @param overlayBitmap The overlay bitmap
- * @param renderingMode The rendering mode
- */
- void set(Bitmap overlayBitmap, int renderingMode) {
- mOverlayBitmap = overlayBitmap;
- mRenderingMode = renderingMode;
- mClear = false;
- }
-
- /**
- * Clear the overlay
- */
- void setClear() {
- mClear = true;
- }
-
- /**
- * Render the overlay by either clearing it or by
- * rendering the overlay bitmap with the specified
- * rendering mode
- *
- * @param destBitmap The destination bitmap
- */
- public void renderOverlay(Bitmap destBitmap) {
- if (mClear) {
- destBitmap.eraseColor(Color.TRANSPARENT);
- } else if (mOverlayBitmap != null) {
- final Canvas overlayCanvas = new Canvas(destBitmap);
- final Rect destRect;
- final Rect srcRect;
- switch (mRenderingMode) {
- case MediaArtistNativeHelper.MediaRendering.RESIZING: {
- destRect = new Rect(0, 0, overlayCanvas.getWidth(),
- overlayCanvas.getHeight());
- srcRect = new Rect(0, 0, mOverlayBitmap.getWidth(),
- mOverlayBitmap.getHeight());
- break;
- }
-
- case MediaArtistNativeHelper.MediaRendering.BLACK_BORDERS: {
- int left, right, top, bottom;
- float aROverlayImage, aRCanvas;
- aROverlayImage = (float)(mOverlayBitmap.getWidth()) /
- (float)(mOverlayBitmap.getHeight());
-
- aRCanvas = (float)(overlayCanvas.getWidth()) /
- (float)(overlayCanvas.getHeight());
-
- if (aROverlayImage > aRCanvas) {
- int newHeight = ((overlayCanvas.getWidth() * mOverlayBitmap.getHeight())
- / mOverlayBitmap.getWidth());
- left = 0;
- top = (overlayCanvas.getHeight() - newHeight) / 2;
- right = overlayCanvas.getWidth();
- bottom = top + newHeight;
- } else {
- int newWidth = ((overlayCanvas.getHeight() * mOverlayBitmap.getWidth())
- / mOverlayBitmap.getHeight());
- left = (overlayCanvas.getWidth() - newWidth) / 2;
- top = 0;
- right = left + newWidth;
- bottom = overlayCanvas.getHeight();
- }
-
- destRect = new Rect(left, top, right, bottom);
- srcRect = new Rect(0, 0, mOverlayBitmap.getWidth(), mOverlayBitmap.getHeight());
- break;
- }
-
- case MediaArtistNativeHelper.MediaRendering.CROPPING: {
- // Calculate the source rect
- int left, right, top, bottom;
- float aROverlayImage, aRCanvas;
- aROverlayImage = (float)(mOverlayBitmap.getWidth()) /
- (float)(mOverlayBitmap.getHeight());
- aRCanvas = (float)(overlayCanvas.getWidth()) /
- (float)(overlayCanvas.getHeight());
- if (aROverlayImage < aRCanvas) {
- int newHeight = ((mOverlayBitmap.getWidth() * overlayCanvas.getHeight())
- / overlayCanvas.getWidth());
-
- left = 0;
- top = (mOverlayBitmap.getHeight() - newHeight) / 2;
- right = mOverlayBitmap.getWidth();
- bottom = top + newHeight;
- } else {
- int newWidth = ((mOverlayBitmap.getHeight() * overlayCanvas.getWidth())
- / overlayCanvas.getHeight());
- left = (mOverlayBitmap.getWidth() - newWidth) / 2;
- top = 0;
- right = left + newWidth;
- bottom = mOverlayBitmap.getHeight();
- }
-
- srcRect = new Rect(left, top, right, bottom);
- destRect = new Rect(0, 0, overlayCanvas.getWidth(), overlayCanvas.getHeight());
- break;
- }
-
- default: {
- throw new IllegalStateException("Rendering mode: " + mRenderingMode);
- }
- }
-
- destBitmap.eraseColor(Color.TRANSPARENT);
- overlayCanvas.drawBitmap(mOverlayBitmap, srcRect, destRect, sResizePaint);
-
- mOverlayBitmap.recycle();
- }
- }
- }
-
- /**
- * @return The path where the VideoEditor stores all files related to the
- * project
- */
- public String getPath();
-
- /**
- * This method releases all in-memory resources used by the VideoEditor
- * instance. All pending operations such as preview, export and extract
- * audio waveform must be canceled.
- */
- public void release();
-
- /**
- * Persist the current internal state of VideoEditor to the project path.
- * The VideoEditor state may be restored by invoking the
- * {@link VideoEditorFactory#load(String)} method. This method does not
- * release the internal in-memory state of the VideoEditor. To release
- * the in-memory state of the VideoEditor the {@link #release()} method
- * must be invoked.
- *
- * Pending transition generations must be allowed to complete before the
- * state is saved.
- * Pending audio waveform generations must be allowed to complete.
- * Pending export operations must be allowed to continue.
- *
- * @throws IOException if the internal state cannot be saved to project file
- */
- public void save() throws IOException;
-
- /**
- * Create the output movie based on all media items added and the applied
- * storyboard items. This method can take a long time to execute and is
- * blocking. The application will receive progress notifications via the
- * ExportProgressListener. Specific implementations may not support multiple
- * simultaneous export operations. Note that invoking methods which would
- * change the contents of the output movie throw an IllegalStateException
- * while an export operation is pending.
- *
- * The audio and video codecs are automatically selected by the underlying
- * implementation.
- *
- * @param filename The output file name (including the full path)
- * @param height The height of the output video file. The supported values
- * for height are described in the MediaProperties class, for
- * example: HEIGHT_480. The width will be automatically computed
- * according to the aspect ratio provided by
- * {@link #setAspectRatio(int)}
- * @param bitrate The bitrate of the output video file. This is approximate
- * value for the output movie. Supported bitrate values are
- * described in the MediaProperties class for example: BITRATE_384K
- * @param listener The listener for progress notifications. Use null if
- * export progress notifications are not needed.
- *
- * @throws IllegalArgumentException if height or bitrate are not supported
- * or if the audio or video codecs are not supported
- * @throws IOException if output file cannot be created
- * @throws IllegalStateException if a preview or an export is in progress or
- * if no MediaItem has been added
- * @throws CancellationException if export is canceled by calling
- * {@link #cancelExport()}
- * @throws UnsupportOperationException if multiple simultaneous export() are
- * not allowed
- */
- public void export(String filename, int height, int bitrate,
- ExportProgressListener listener)
- throws IOException;
-
- /**
- * Create the output movie based on all media items added and the applied
- * storyboard items. This method can take a long time to execute and is
- * blocking. The application will receive progress notifications via the
- * ExportProgressListener. Specific implementations may not support multiple
- * simultaneous export operations. Note that invoking methods which would
- * change the contents of the output movie throw an IllegalStateException
- * while an export operation is pending.
- *
- * @param filename The output file name (including the full path)
- * @param height The height of the output video file. The supported values
- * for height are described in the MediaProperties class, for
- * example: HEIGHT_480. The width will be automatically computed
- * according to the aspect ratio provided by
- * {@link #setAspectRatio(int)}
- * @param bitrate The bitrate of the output video file. This is approximate
- * value for the output movie. Supported bitrate values are
- * described in the MediaProperties class for example: BITRATE_384K
- * @param audioCodec The audio codec to be used for the export. The audio
- * codec values are defined in the MediaProperties class (e.g.
- * ACODEC_AAC_LC). Note that not all audio codec types are
- * supported for export purposes.
- * @param videoCodec The video codec to be used for the export. The video
- * codec values are defined in the MediaProperties class (e.g.
- * VCODEC_H264). Note that not all video codec types are
- * supported for export purposes.
- * @param listener The listener for progress notifications. Use null if
- * export progress notifications are not needed.
- *
- * @throws IllegalArgumentException if height or bitrate are not supported
- * or if the audio or video codecs are not supported
- * @throws IOException if output file cannot be created
- * @throws IllegalStateException if a preview or an export is in progress or
- * if no MediaItem has been added
- * @throws CancellationException if export is cancelled by calling
- * {@link #cancelExport()}
- * @throws UnsupportOperationException if multiple simultaneous export() are
- * not allowed
- */
- public void export(String filename, int height, int bitrate, int audioCodec,
- int videoCodec, ExportProgressListener listener)
- throws IOException;
-
- /**
- * Cancel the running export operation. This method blocks until the export
- * is cancelled and the exported file (if any) is deleted. If the export
- * completed by the time this method is invoked, the export file will be
- * deleted.
- *
- * @param filename The filename which identifies the export operation to be
- * canceled.
- **/
- public void cancelExport(String filename);
-
- /**
- * Add a media item at the end of the storyboard.
- *
- * @param mediaItem The media item object to add
- *
- * @throws IllegalStateException if a preview or an export is in progress or
- * if the media item id is not unique across all the media items
- * added.
- */
- public void addMediaItem(MediaItem mediaItem);
-
- /**
- * Insert a media item after the media item with the specified id.
- *
- * @param mediaItem The media item object to insert
- * @param afterMediaItemId Insert the mediaItem after the media item
- * identified by this id. If this parameter is null, the media
- * item is inserted at the beginning of the timeline.
- *
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if media item with the specified id does
- * not exist (null is a valid value) or if the media item id is
- * not unique across all the media items added.
- */
- public void insertMediaItem(MediaItem mediaItem, String afterMediaItemId);
-
- /**
- * Move a media item after the media item with the specified id.
- *
- * Note: The project thumbnail is regenerated if the media item is or
- * becomes the first media item in the storyboard timeline.
- *
- * @param mediaItemId The id of the media item to move
- * @param afterMediaItemId Move the media item identified by mediaItemId
- * after the media item identified by this parameter. If this
- * parameter is null, the media item is moved at the beginning of
- * the timeline.
- *
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if one of media item ids is invalid
- * (null is a valid value)
- */
- public void moveMediaItem(String mediaItemId, String afterMediaItemId);
-
- /**
- * Remove the media item with the specified id. If there are transitions
- * before or after this media item, then this/these transition(s) are
- * removed from the storyboard. If the extraction of the audio waveform is
- * in progress, the extraction is canceled and the file is deleted.
- *
- * Effects and overlays associated with the media item will also be removed.
- *
- * Note: The project thumbnail is regenerated if the media item which is
- * removed is the first media item in the storyboard or if the media item is
- * the only one in the storyboard. If the media item is the only one in the
- * storyboard, the project thumbnail will be set to a black frame and the
- * aspect ratio will revert to the default aspect ratio and this method is
- * equivalent to removeAllMediaItems() in this case.
- *
- * @param mediaItemId The unique id of the media item to be removed
- *
- * @return The media item that was removed
- *
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if media item with the specified id does
- * not exist
- */
- public MediaItem removeMediaItem(String mediaItemId);
-
- /**
- * Remove all media items in the storyboard. All effects, overlays and all
- * transitions are also removed.
- *
- * Note: The project thumbnail will be set to a black frame and the aspect
- * ratio will revert to the default aspect ratio.
- *
- * @throws IllegalStateException if a preview or an export is in progress
- */
- public void removeAllMediaItems();
-
- /**
- * Get the list of media items in the order in which it they appear in the
- * storyboard timeline.
- *
- * Note that if any media item source files are no longer
- * accessible, this method will still provide the full list of media items.
- *
- * @return The list of media items. If no media item exist an empty list
- * will be returned.
- */
- public List<MediaItem> getAllMediaItems();
-
- /**
- * Find the media item with the specified id
- *
- * @param mediaItemId The media item id
- *
- * @return The media item with the specified id (null if it does not exist)
- */
- public MediaItem getMediaItem(String mediaItemId);
-
- /**
- * Add a transition between the media items specified by the transition.
- * If a transition existed at the same position it is invalidated and then
- * the transition is replaced. Note that the new transition video clip is
- * not automatically generated by this method. The
- * {@link Transition#generate()} method must be invoked to generate
- * the transition video clip.
- *
- * Note that the TransitionAtEnd and TransitionAtStart are special kinds
- * that can not be applied between two media items.
- *
- * A crossfade audio transition will be automatically applied regardless of
- * the video transition.
- *
- * @param transition The transition to apply
- *
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if the transition duration is larger
- * than the smallest duration of the two media item files or if
- * the two media items specified in the transition are not
- * adjacent
- */
- public void addTransition(Transition transition);
-
- /**
- * Remove the transition with the specified id.
- *
- * @param transitionId The id of the transition to be removed
- *
- * @return The transition that was removed
- *
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if transition with the specified id does
- * not exist
- */
- public Transition removeTransition(String transitionId);
-
- /**
- * Get the list of transitions
- *
- * @return The list of transitions. If no transitions exist an empty list
- * will be returned.
- */
- public List<Transition> getAllTransitions();
-
- /**
- * Find the transition with the specified transition id.
- *
- * @param transitionId The transition id
- *
- * @return The transition
- */
- public Transition getTransition(String transitionId);
-
- /**
- * Add the specified AudioTrack to the storyboard. Note: Specific
- * implementations may support a limited number of audio tracks (e.g. only
- * one audio track)
- *
- * @param audioTrack The AudioTrack to add
- *
- * @throws UnsupportedOperationException if the implementation supports a
- * limited number of audio tracks.
- * @throws IllegalArgumentException if media item is not unique across all
- * the audio tracks already added.
- */
- public void addAudioTrack(AudioTrack audioTrack);
-
- /**
- * Insert an audio track after the audio track with the specified id. Use
- * addAudioTrack to add an audio track at the end of the storyboard
- * timeline.
- *
- * @param audioTrack The audio track object to insert
- * @param afterAudioTrackId Insert the audio track after the audio track
- * identified by this parameter. If this parameter is null the
- * audio track is added at the beginning of the timeline.
- *
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if media item with the specified id does
- * not exist (null is a valid value). if media item is not unique
- * across all the audio tracks already added.
- * @throws UnsupportedOperationException if the implementation supports a
- * limited number of audio tracks
- */
- public void insertAudioTrack(AudioTrack audioTrack, String afterAudioTrackId);
-
- /**
- * Move an AudioTrack after the AudioTrack with the specified id.
- *
- * @param audioTrackId The id of the AudioTrack to move
- * @param afterAudioTrackId Move the AudioTrack identified by audioTrackId
- * after the AudioTrack identified by this parameter. If this
- * parameter is null the audio track is added at the beginning of
- * the timeline.
- *
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if one of media item ids is invalid
- * (null is a valid value)
- */
- public void moveAudioTrack(String audioTrackId, String afterAudioTrackId);
-
- /**
- * Remove the audio track with the specified id. If the extraction of the
- * audio waveform is in progress, the extraction is canceled and the file is
- * deleted.
- *
- * @param audioTrackId The id of the audio track to be removed
- *
- * @return The audio track that was removed
- * @throws IllegalStateException if a preview or an export is in progress
- */
- public AudioTrack removeAudioTrack(String audioTrackId);
-
- /**
- * Get the list of AudioTracks in order in which they appear in the
- * storyboard.
- *
- * Note that if any AudioTrack source files are not accessible anymore,
- * this method will still provide the full list of audio tracks.
- *
- * @return The list of AudioTracks. If no audio tracks exist an empty list
- * will be returned.
- */
- public List<AudioTrack> getAllAudioTracks();
-
- /**
- * Find the AudioTrack with the specified id
- *
- * @param audioTrackId The AudioTrack id
- *
- * @return The AudioTrack with the specified id (null if it does not exist)
- */
- public AudioTrack getAudioTrack(String audioTrackId);
-
- /**
- * Set the aspect ratio used in the preview and the export movie.
- *
- * The default aspect ratio is ASPECTRATIO_16_9 (16:9).
- *
- * @param aspectRatio to apply. If aspectRatio is the same as the current
- * aspect ratio, then this function just returns. The supported
- * aspect ratio are defined in the MediaProperties class for
- * example: ASPECTRATIO_16_9
- *
- * @throws IllegalStateException if a preview or an export is in progress
- * @throws IllegalArgumentException if aspect ratio is not supported
- */
- public void setAspectRatio(int aspectRatio);
-
- /**
- * Get current aspect ratio.
- *
- * @return The aspect ratio as described in MediaProperties
- */
- public int getAspectRatio();
-
- /**
- * Get the preview (and output movie) duration.
- *
- * @return The duration of the preview (and output movie)
- */
- public long getDuration();
-
- /**
- * Render a frame according to the preview aspect ratio and activating all
- * storyboard items relative to the specified time.
- *
- * @param surfaceHolder SurfaceHolder used by the application
- * @param timeMs time corresponding to the frame to display
- * @param overlayData The overlay data
- *
- * @return The accurate time stamp of the frame that is rendered.
- *
- * @throws IllegalStateException if a preview or an export is already in
- * progress
- * @throws IllegalArgumentException if time is negative or beyond the
- * preview duration
- */
- public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs,
- OverlayData overlayData);
-
- /**
- * This method must be called after any changes made to the storyboard
- * and before startPreview is called. Note that this method may block for an
- * extensive period of time.
- */
- public void generatePreview(MediaProcessingProgressListener listener);
-
- /**
- * Start the preview of all the storyboard items applied on all MediaItems
- * This method does not block (does not wait for the preview to complete).
- * The PreviewProgressListener allows to track the progress at the time
- * interval determined by the callbackAfterFrameCount parameter. The
- * SurfaceHolder has to be created and ready for use before calling this
- * method. The method is a no-op if there are no MediaItems in the
- * storyboard.
- *
- * @param surfaceHolder SurfaceHolder where the preview is rendered.
- * @param fromMs The time (relative to the timeline) at which the preview
- * will start
- * @param toMs The time (relative to the timeline) at which the preview will
- * stop. Use -1 to play to the end of the timeline
- * @param loop true if the preview should be looped once it reaches the end
- * @param callbackAfterFrameCount The listener interface should be invoked
- * after the number of frames specified by this parameter.
- * @param listener The listener which will be notified of the preview
- * progress
- *
- * @throws IllegalArgumentException if fromMs is beyond the preview duration
- * @throws IllegalStateException if a preview or an export is already in
- * progress
- */
- public void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs,
- boolean loop,int callbackAfterFrameCount,
- PreviewProgressListener listener);
-
- /**
- * Stop the current preview. This method blocks until ongoing preview is
- * stopped. Ignored if there is no preview running.
- *
- * @return The accurate current time when stop is effective expressed in
- * milliseconds
- */
- public long stopPreview();
-
- /**
- * Clears the preview surface
- *
- * @param surfaceHolder SurfaceHolder where the preview is rendered
- * and needs to be cleared.
- */
- public void clearSurface(SurfaceHolder surfaceHolder);
-}
diff --git a/media/java/android/media/videoeditor/VideoEditorFactory.java b/media/java/android/media/videoeditor/VideoEditorFactory.java
deleted file mode 100644
index 85c329f..0000000
--- a/media/java/android/media/videoeditor/VideoEditorFactory.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
-
-/**
- * The VideoEditorFactory class must be used to instantiate VideoEditor objects
- * by creating a new project {@link #create(String)} or by loading an
- * existing project {@link #load(String)}.
- * {@hide}
- */
-public class VideoEditorFactory {
- /**
- * This is the factory method for creating a new VideoEditor instance.
- *
- * @param projectPath The path where all VideoEditor internal
- * files are stored. When a project is deleted the application is
- * responsible for deleting the path and its contents.
- *
- * @return The VideoEditor instance
- *
- * @throws IOException if path does not exist or if the path can
- * not be accessed in read/write mode
- */
- public static VideoEditor create(String projectPath) throws IOException {
- /*
- * If the project path does not exist create it
- */
- final File dir = new File(projectPath);
- if (!dir.exists()) {
- if (!dir.mkdirs()) {
- throw new FileNotFoundException("Cannot create project path: "
- + projectPath);
- } else {
- /*
- * Create the file which hides the media files
- * from the media scanner
- */
- if (!new File(dir, ".nomedia").createNewFile()) {
- throw new FileNotFoundException("Cannot create file .nomedia");
- }
- }
- }
-
- return new VideoEditorImpl(projectPath);
- }
-
- /**
- * This is the factory method for instantiating a VideoEditor from the
- * internal state previously saved with the
- * {@link VideoEditor#save(String)} method.
- *
- * @param projectPath The path where all VideoEditor internal files
- * are stored. When a project is deleted the application is
- * responsible for deleting the path and its contents.
- * @param generatePreview if set to true the
- * {@link MediaEditor#generatePreview(MediaProcessingProgressListener
- * listener)}
- * will be called internally to generate any needed transitions.
- *
- * @return The VideoEditor instance
- *
- * @throws IOException if path does not exist or if the path can
- * not be accessed in read/write mode or if one of the resource
- * media files cannot be retrieved
- */
- public static VideoEditor load(String projectPath, boolean generatePreview)
- throws IOException {
- final VideoEditor videoEditor = new VideoEditorImpl(projectPath);
- if (generatePreview) {
- videoEditor.generatePreview(null);
- }
- return videoEditor;
- }
-}
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
deleted file mode 100644
index fbf2eab..0000000
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ /dev/null
@@ -1,1978 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.MediaMetadataRetriever;
-import android.util.Log;
-import android.util.Xml;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.os.Debug;
-import android.os.SystemProperties;
-import android.os.Environment;
-
-import libcore.io.IoUtils;
-
-/**
- * The VideoEditor implementation {@hide}
- */
-public class VideoEditorImpl implements VideoEditor {
- /*
- * Logging
- */
- private static final String TAG = "VideoEditorImpl";
-
- /*
- * The project filename
- */
- private static final String PROJECT_FILENAME = "videoeditor.xml";
-
- /*
- * XML tags
- */
- private static final String TAG_PROJECT = "project";
- private static final String TAG_MEDIA_ITEMS = "media_items";
- private static final String TAG_MEDIA_ITEM = "media_item";
- private static final String TAG_TRANSITIONS = "transitions";
- private static final String TAG_TRANSITION = "transition";
- private static final String TAG_OVERLAYS = "overlays";
- private static final String TAG_OVERLAY = "overlay";
- private static final String TAG_OVERLAY_USER_ATTRIBUTES = "overlay_user_attributes";
- private static final String TAG_EFFECTS = "effects";
- private static final String TAG_EFFECT = "effect";
- private static final String TAG_AUDIO_TRACKS = "audio_tracks";
- private static final String TAG_AUDIO_TRACK = "audio_track";
-
- private static final String ATTR_ID = "id";
- private static final String ATTR_FILENAME = "filename";
- private static final String ATTR_AUDIO_WAVEFORM_FILENAME = "waveform";
- private static final String ATTR_RENDERING_MODE = "rendering_mode";
- private static final String ATTR_ASPECT_RATIO = "aspect_ratio";
- private static final String ATTR_REGENERATE_PCM = "regeneratePCMFlag";
- private static final String ATTR_TYPE = "type";
- private static final String ATTR_DURATION = "duration";
- private static final String ATTR_START_TIME = "start_time";
- private static final String ATTR_BEGIN_TIME = "begin_time";
- private static final String ATTR_END_TIME = "end_time";
- private static final String ATTR_VOLUME = "volume";
- private static final String ATTR_BEHAVIOR = "behavior";
- private static final String ATTR_DIRECTION = "direction";
- private static final String ATTR_BLENDING = "blending";
- private static final String ATTR_INVERT = "invert";
- private static final String ATTR_MASK = "mask";
- private static final String ATTR_BEFORE_MEDIA_ITEM_ID = "before_media_item";
- private static final String ATTR_AFTER_MEDIA_ITEM_ID = "after_media_item";
- private static final String ATTR_COLOR_EFFECT_TYPE = "color_type";
- private static final String ATTR_COLOR_EFFECT_VALUE = "color_value";
- private static final String ATTR_START_RECT_LEFT = "start_l";
- private static final String ATTR_START_RECT_TOP = "start_t";
- private static final String ATTR_START_RECT_RIGHT = "start_r";
- private static final String ATTR_START_RECT_BOTTOM = "start_b";
- private static final String ATTR_END_RECT_LEFT = "end_l";
- private static final String ATTR_END_RECT_TOP = "end_t";
- private static final String ATTR_END_RECT_RIGHT = "end_r";
- private static final String ATTR_END_RECT_BOTTOM = "end_b";
- private static final String ATTR_LOOP = "loop";
- private static final String ATTR_MUTED = "muted";
- private static final String ATTR_DUCK_ENABLED = "ducking_enabled";
- private static final String ATTR_DUCK_THRESHOLD = "ducking_threshold";
- private static final String ATTR_DUCKED_TRACK_VOLUME = "ducking_volume";
- private static final String ATTR_GENERATED_IMAGE_CLIP = "generated_image_clip";
- private static final String ATTR_IS_IMAGE_CLIP_GENERATED = "is_image_clip_generated";
- private static final String ATTR_GENERATED_TRANSITION_CLIP = "generated_transition_clip";
- private static final String ATTR_IS_TRANSITION_GENERATED = "is_transition_generated";
- private static final String ATTR_OVERLAY_RGB_FILENAME = "overlay_rgb_filename";
- private static final String ATTR_OVERLAY_FRAME_WIDTH = "overlay_frame_width";
- private static final String ATTR_OVERLAY_FRAME_HEIGHT = "overlay_frame_height";
- private static final String ATTR_OVERLAY_RESIZED_RGB_FRAME_WIDTH = "resized_RGBframe_width";
- private static final String ATTR_OVERLAY_RESIZED_RGB_FRAME_HEIGHT = "resized_RGBframe_height";
- private static final int ENGINE_ACCESS_MAX_TIMEOUT_MS = 500;
- /*
- * Instance variables
- */
- private final Semaphore mLock;
- private final String mProjectPath;
- private final List<MediaItem> mMediaItems = new ArrayList<MediaItem>();
- private final List<AudioTrack> mAudioTracks = new ArrayList<AudioTrack>();
- private final List<Transition> mTransitions = new ArrayList<Transition>();
- private long mDurationMs;
- private int mAspectRatio;
-
- /*
- * Private Object for calling native Methods via MediaArtistNativeHelper
- */
- private MediaArtistNativeHelper mMANativeHelper;
- private boolean mPreviewInProgress = false;
- private final boolean mMallocDebug;
-
- /**
- * Constructor
- *
- * @param projectPath - The path where the VideoEditor stores all files
- * related to the project
- */
- public VideoEditorImpl(String projectPath) throws IOException {
- String s;
- s = SystemProperties.get("libc.debug.malloc");
- if (s.equals("1")) {
- mMallocDebug = true;
- try {
- dumpHeap("HeapAtStart");
- } catch (Exception ex) {
- Log.e(TAG, "dumpHeap returned error in constructor");
- }
- } else {
- mMallocDebug = false;
- }
- mLock = new Semaphore(1, true);
- mMANativeHelper = new MediaArtistNativeHelper(projectPath, mLock, this);
- mProjectPath = projectPath;
- final File projectXml = new File(projectPath, PROJECT_FILENAME);
- if (projectXml.exists()) {
- try {
- load();
- } catch (Exception ex) {
- ex.printStackTrace();
- throw new IOException(ex.toString());
- }
- } else {
- mAspectRatio = MediaProperties.ASPECT_RATIO_16_9;
- mDurationMs = 0;
- }
- }
-
- /*
- * @return The MediaArtistNativeHelper object
- */
- MediaArtistNativeHelper getNativeContext() {
- return mMANativeHelper;
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized void addAudioTrack(AudioTrack audioTrack) {
- if (audioTrack == null) {
- throw new IllegalArgumentException("Audio Track is null");
- }
-
- if (mAudioTracks.size() == 1) {
- throw new IllegalArgumentException("No more tracks can be added");
- }
-
- mMANativeHelper.setGeneratePreview(true);
-
- /*
- * Add the audio track to AudioTrack list
- */
- mAudioTracks.add(audioTrack);
-
- /*
- * Form the audio PCM file path
- */
- final String audioTrackPCMFilePath = String.format(mProjectPath + "/"
- + "AudioPcm" + audioTrack.getId() + ".pcm");
-
- /*
- * Create PCM only if not generated in previous session
- */
- if (new File(audioTrackPCMFilePath).exists()) {
- mMANativeHelper.setAudioflag(false);
- }
-
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized void addMediaItem(MediaItem mediaItem) {
- /*
- * Validate Media Item
- */
- if (mediaItem == null) {
- throw new IllegalArgumentException("Media item is null");
- }
- /*
- * Add the Media item to MediaItem list
- */
- if (mMediaItems.contains(mediaItem)) {
- throw new IllegalArgumentException("Media item already exists: " + mediaItem.getId());
- }
-
- mMANativeHelper.setGeneratePreview(true);
-
- /*
- * Invalidate the end transition if necessary
- */
- final int mediaItemsCount = mMediaItems.size();
- if (mediaItemsCount > 0) {
- removeTransitionAfter(mediaItemsCount - 1);
- }
-
- /*
- * Add the new media item
- */
- mMediaItems.add(mediaItem);
-
- computeTimelineDuration();
-
- /*
- * Generate project thumbnail only from first media Item on storyboard
- */
- if (mMediaItems.size() == 1) {
- generateProjectThumbnail();
- }
- }
-
-
- /*
- * {@inheritDoc}
- */
- public synchronized void addTransition(Transition transition) {
- if (transition == null) {
- throw new IllegalArgumentException("Null Transition");
- }
-
- final MediaItem beforeMediaItem = transition.getBeforeMediaItem();
- final MediaItem afterMediaItem = transition.getAfterMediaItem();
- /*
- * Check if the MediaItems are in sequence
- */
- if (mMediaItems == null) {
- throw new IllegalArgumentException("No media items are added");
- }
-
- if ((afterMediaItem != null) && (beforeMediaItem != null)) {
- final int afterMediaItemIndex = mMediaItems.indexOf(afterMediaItem);
- final int beforeMediaItemIndex = mMediaItems.indexOf(beforeMediaItem);
-
- if ((afterMediaItemIndex == -1) || (beforeMediaItemIndex == -1)) {
- throw new IllegalArgumentException
- ("Either of the mediaItem is not found in the list");
- }
-
- if (afterMediaItemIndex != (beforeMediaItemIndex - 1) ) {
- throw new IllegalArgumentException("MediaItems are not in sequence");
- }
- }
-
- mMANativeHelper.setGeneratePreview(true);
-
- mTransitions.add(transition);
- /*
- * Cross reference the transitions
- */
- if (afterMediaItem != null) {
- /*
- * If a transition already exists at the specified position then
- * invalidate it.
- */
- if (afterMediaItem.getEndTransition() != null) {
- afterMediaItem.getEndTransition().invalidate();
- mTransitions.remove(afterMediaItem.getEndTransition());
- }
- afterMediaItem.setEndTransition(transition);
- }
-
- if (beforeMediaItem != null) {
- /*
- * If a transition already exists at the specified position then
- * invalidate it.
- */
- if (beforeMediaItem.getBeginTransition() != null) {
- beforeMediaItem.getBeginTransition().invalidate();
- mTransitions.remove(beforeMediaItem.getBeginTransition());
- }
- beforeMediaItem.setBeginTransition(transition);
- }
-
- computeTimelineDuration();
- }
-
- /*
- * {@inheritDoc}
- */
- public void cancelExport(String filename) {
- if (mMANativeHelper != null && filename != null) {
- mMANativeHelper.stop(filename);
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public void export(String filename, int height, int bitrate,
- int audioCodec, int videoCodec,
- ExportProgressListener listener)
- throws IOException {
- int audcodec = 0;
- int vidcodec = 0;
- if (filename == null) {
- throw new IllegalArgumentException("export: filename is null");
- }
-
- final File tempPathFile = new File(filename);
- if (tempPathFile == null) {
- throw new IOException(filename + "can not be created");
- }
-
- if (mMediaItems.size() == 0) {
- throw new IllegalStateException("No MediaItems added");
- }
-
- switch (height) {
- case MediaProperties.HEIGHT_144:
- break;
- case MediaProperties.HEIGHT_288:
- break;
- case MediaProperties.HEIGHT_360:
- break;
- case MediaProperties.HEIGHT_480:
- break;
- case MediaProperties.HEIGHT_720:
- break;
- case MediaProperties.HEIGHT_1080:
- break;
-
- default: {
- String message = "Unsupported height value " + height;
- throw new IllegalArgumentException(message);
- }
- }
-
- switch (bitrate) {
- case MediaProperties.BITRATE_28K:
- break;
- case MediaProperties.BITRATE_40K:
- break;
- case MediaProperties.BITRATE_64K:
- break;
- case MediaProperties.BITRATE_96K:
- break;
- case MediaProperties.BITRATE_128K:
- break;
- case MediaProperties.BITRATE_192K:
- break;
- case MediaProperties.BITRATE_256K:
- break;
- case MediaProperties.BITRATE_384K:
- break;
- case MediaProperties.BITRATE_512K:
- break;
- case MediaProperties.BITRATE_800K:
- break;
- case MediaProperties.BITRATE_2M:
- break;
- case MediaProperties.BITRATE_5M:
- break;
- case MediaProperties.BITRATE_8M:
- break;
-
- default: {
- final String message = "Unsupported bitrate value " + bitrate;
- throw new IllegalArgumentException(message);
- }
- }
- computeTimelineDuration();
- final long audioBitrate = MediaArtistNativeHelper.Bitrate.BR_96_KBPS;
- final long fileSize = (mDurationMs * (bitrate + audioBitrate)) / 8000;
- if (MAX_SUPPORTED_FILE_SIZE <= fileSize) {
- throw new IllegalStateException("Export Size is more than 2GB");
- }
- switch (audioCodec) {
- case MediaProperties.ACODEC_AAC_LC:
- audcodec = MediaArtistNativeHelper.AudioFormat.AAC;
- break;
- case MediaProperties.ACODEC_AMRNB:
- audcodec = MediaArtistNativeHelper.AudioFormat.AMR_NB;
- break;
-
- default: {
- String message = "Unsupported audio codec type " + audioCodec;
- throw new IllegalArgumentException(message);
- }
- }
-
- switch (videoCodec) {
- case MediaProperties.VCODEC_H263:
- vidcodec = MediaArtistNativeHelper.VideoFormat.H263;
- break;
- case MediaProperties.VCODEC_H264:
- vidcodec = MediaArtistNativeHelper.VideoFormat.H264;
- break;
- case MediaProperties.VCODEC_MPEG4:
- vidcodec = MediaArtistNativeHelper.VideoFormat.MPEG4;
- break;
-
- default: {
- String message = "Unsupported video codec type " + videoCodec;
- throw new IllegalArgumentException(message);
- }
- }
-
- boolean semAcquireDone = false;
- try {
- lock();
- semAcquireDone = true;
-
- if (mMANativeHelper == null) {
- throw new IllegalStateException("The video editor is not initialized");
- }
- mMANativeHelper.setAudioCodec(audcodec);
- mMANativeHelper.setVideoCodec(vidcodec);
- mMANativeHelper.export(filename, mProjectPath, height,bitrate,
- mMediaItems, mTransitions, mAudioTracks, listener);
- } catch (InterruptedException ex) {
- Log.e(TAG, "Sem acquire NOT successful in export");
- } finally {
- if (semAcquireDone) {
- unlock();
- }
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public void export(String filename, int height, int bitrate,
- ExportProgressListener listener)
- throws IOException {
- int defaultAudiocodec = MediaArtistNativeHelper.AudioFormat.AAC;
- int defaultVideocodec = MediaArtistNativeHelper.VideoFormat.H264;
-
- export(filename, height, bitrate, defaultAudiocodec,
- defaultVideocodec, listener);
- }
-
- /*
- * {@inheritDoc}
- */
- public void generatePreview(MediaProcessingProgressListener listener) {
- boolean semAcquireDone = false;
- try {
- lock();
- semAcquireDone = true;
-
- if (mMANativeHelper == null) {
- throw new IllegalStateException("The video editor is not initialized");
- }
-
- if ((mMediaItems.size() > 0) || (mAudioTracks.size() > 0)) {
- mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions, mAudioTracks,
- listener);
- }
- } catch (InterruptedException ex) {
- Log.e(TAG, "Sem acquire NOT successful in previewStoryBoard");
- } finally {
- if (semAcquireDone) {
- unlock();
- }
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public List<AudioTrack> getAllAudioTracks() {
- return mAudioTracks;
- }
-
- /*
- * {@inheritDoc}
- */
- public List<MediaItem> getAllMediaItems() {
- return mMediaItems;
- }
-
- /*
- * {@inheritDoc}
- */
- public List<Transition> getAllTransitions() {
- return mTransitions;
- }
-
- /*
- * {@inheritDoc}
- */
- public int getAspectRatio() {
- return mAspectRatio;
- }
-
- /*
- * {@inheritDoc}
- */
- public AudioTrack getAudioTrack(String audioTrackId) {
- for (AudioTrack at : mAudioTracks) {
- if (at.getId().equals(audioTrackId)) {
- return at;
- }
- }
- return null;
- }
-
- /*
- * {@inheritDoc}
- */
- public long getDuration() {
- /**
- * Since MediaImageItem can change duration we need to compute the
- * duration here
- */
- computeTimelineDuration();
- return mDurationMs;
- }
-
- /*
- * Force updates the timeline duration
- */
- void updateTimelineDuration() {
- computeTimelineDuration();
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized MediaItem getMediaItem(String mediaItemId) {
- for (MediaItem mediaItem : mMediaItems) {
- if (mediaItem.getId().equals(mediaItemId)) {
- return mediaItem;
- }
- }
- return null;
- }
-
- /*
- * {@inheritDoc}
- */
- public String getPath() {
- return mProjectPath;
- }
-
- /*
- * {@inheritDoc}
- */
- public Transition getTransition(String transitionId) {
- for (Transition transition : mTransitions) {
- if (transition.getId().equals(transitionId)) {
- return transition;
- }
- }
- return null;
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized void insertAudioTrack(AudioTrack audioTrack,
- String afterAudioTrackId) {
- if (mAudioTracks.size() == 1) {
- throw new IllegalArgumentException("No more tracks can be added");
- }
-
- if (afterAudioTrackId == null) {
- mMANativeHelper.setGeneratePreview(true);
- mAudioTracks.add(0, audioTrack);
- } else {
- final int audioTrackCount = mAudioTracks.size();
- for (int i = 0; i < audioTrackCount; i++) {
- AudioTrack at = mAudioTracks.get(i);
- if (at.getId().equals(afterAudioTrackId)) {
- mMANativeHelper.setGeneratePreview(true);
- mAudioTracks.add(i + 1, audioTrack);
- return;
- }
- }
-
- throw new IllegalArgumentException("AudioTrack not found: " + afterAudioTrackId);
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized void insertMediaItem(MediaItem mediaItem, String afterMediaItemId) {
- if (mMediaItems.contains(mediaItem)) {
- throw new IllegalArgumentException("Media item already exists: " + mediaItem.getId());
- }
-
- if (afterMediaItemId == null) {
- mMANativeHelper.setGeneratePreview(true);
- if (mMediaItems.size() > 0) {
- /**
- * Invalidate the transition at the beginning of the timeline
- */
- removeTransitionBefore(0);
- }
-
- mMediaItems.add(0, mediaItem);
- computeTimelineDuration();
- generateProjectThumbnail();
- } else {
- final int mediaItemCount = mMediaItems.size();
- for (int i = 0; i < mediaItemCount; i++) {
- final MediaItem mi = mMediaItems.get(i);
- if (mi.getId().equals(afterMediaItemId)) {
- mMANativeHelper.setGeneratePreview(true);
- /**
- * Invalidate the transition at this position
- */
- removeTransitionAfter(i);
- /**
- * Insert the new media item
- */
- mMediaItems.add(i + 1, mediaItem);
- computeTimelineDuration();
- return;
- }
- }
-
- throw new IllegalArgumentException("MediaItem not found: " + afterMediaItemId);
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized void moveAudioTrack(String audioTrackId, String afterAudioTrackId) {
- throw new IllegalStateException("Not supported");
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized void moveMediaItem(String mediaItemId, String afterMediaItemId) {
- final MediaItem moveMediaItem = removeMediaItem(mediaItemId,true);
- if (moveMediaItem == null) {
- throw new IllegalArgumentException("Target MediaItem not found: " + mediaItemId);
- }
-
- if (afterMediaItemId == null) {
- if (mMediaItems.size() > 0) {
- mMANativeHelper.setGeneratePreview(true);
-
- /**
- * Invalidate adjacent transitions at the insertion point
- */
- removeTransitionBefore(0);
-
- /**
- * Insert the media item at the new position
- */
- mMediaItems.add(0, moveMediaItem);
- computeTimelineDuration();
-
- generateProjectThumbnail();
- } else {
- throw new IllegalStateException("Cannot move media item (it is the only item)");
- }
- } else {
- final int mediaItemCount = mMediaItems.size();
- for (int i = 0; i < mediaItemCount; i++) {
- final MediaItem mi = mMediaItems.get(i);
- if (mi.getId().equals(afterMediaItemId)) {
- mMANativeHelper.setGeneratePreview(true);
- /**
- * Invalidate adjacent transitions at the insertion point
- */
- removeTransitionAfter(i);
- /**
- * Insert the media item at the new position
- */
- mMediaItems.add(i + 1, moveMediaItem);
- computeTimelineDuration();
- return;
- }
- }
-
- throw new IllegalArgumentException("MediaItem not found: " + afterMediaItemId);
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public void release() {
- stopPreview();
-
- boolean semAcquireDone = false;
- try {
- lock();
- semAcquireDone = true;
-
- if (mMANativeHelper != null) {
- mMediaItems.clear();
- mAudioTracks.clear();
- mTransitions.clear();
- mMANativeHelper.releaseNativeHelper();
- mMANativeHelper = null;
- }
- } catch (Exception ex) {
- Log.e(TAG, "Sem acquire NOT successful in export", ex);
- } finally {
- if (semAcquireDone) {
- unlock();
- }
- }
- if (mMallocDebug) {
- try {
- dumpHeap("HeapAtEnd");
- } catch (Exception ex) {
- Log.e(TAG, "dumpHeap returned error in release");
- }
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized void removeAllMediaItems() {
- mMANativeHelper.setGeneratePreview(true);
-
- mMediaItems.clear();
-
- /**
- * Invalidate all transitions
- */
- for (Transition transition : mTransitions) {
- transition.invalidate();
- }
- mTransitions.clear();
-
- mDurationMs = 0;
- /**
- * If a thumbnail already exists, then delete it
- */
- if ((new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).exists()) {
- (new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).delete();
- }
-
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized AudioTrack removeAudioTrack(String audioTrackId) {
- final AudioTrack audioTrack = getAudioTrack(audioTrackId);
- if (audioTrack != null) {
- mMANativeHelper.setGeneratePreview(true);
- mAudioTracks.remove(audioTrack);
- audioTrack.invalidate();
- mMANativeHelper.invalidatePcmFile();
- mMANativeHelper.setAudioflag(true);
- } else {
- throw new IllegalArgumentException(" No more audio tracks");
- }
- return audioTrack;
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized MediaItem removeMediaItem(String mediaItemId) {
- final String firstItemString = mMediaItems.get(0).getId();
- final MediaItem mediaItem = getMediaItem(mediaItemId);
- if (mediaItem != null) {
- mMANativeHelper.setGeneratePreview(true);
- /**
- * Remove the media item
- */
- mMediaItems.remove(mediaItem);
- if (mediaItem instanceof MediaImageItem) {
- ((MediaImageItem)mediaItem).invalidate();
- }
- final List<Overlay> overlays = mediaItem.getAllOverlays();
- if (overlays.size() > 0) {
- for (Overlay overlay : overlays) {
- if (overlay instanceof OverlayFrame) {
- final OverlayFrame overlayFrame = (OverlayFrame)overlay;
- overlayFrame.invalidate();
- }
- }
- }
-
- /**
- * Remove the adjacent transitions
- */
- removeAdjacentTransitions(mediaItem);
- computeTimelineDuration();
- }
-
- /**
- * If string equals first mediaItem, then
- * generate Project thumbnail
- */
- if (firstItemString.equals(mediaItemId)) {
- generateProjectThumbnail();
- }
-
- if (mediaItem instanceof MediaVideoItem) {
- /**
- * Delete the graph file
- */
- ((MediaVideoItem)mediaItem).invalidate();
- }
- return mediaItem;
- }
-
- private synchronized MediaItem removeMediaItem(String mediaItemId, boolean flag) {
- final String firstItemString = mMediaItems.get(0).getId();
-
- final MediaItem mediaItem = getMediaItem(mediaItemId);
- if (mediaItem != null) {
- mMANativeHelper.setGeneratePreview(true);
- /**
- * Remove the media item
- */
- mMediaItems.remove(mediaItem);
- /**
- * Remove the adjacent transitions
- */
- removeAdjacentTransitions(mediaItem);
- computeTimelineDuration();
- }
-
- /**
- * If string equals first mediaItem, then
- * generate Project thumbail
- */
- if (firstItemString.equals(mediaItemId)) {
- generateProjectThumbnail();
- }
- return mediaItem;
- }
-
- /*
- * {@inheritDoc}
- */
- public synchronized Transition removeTransition(String transitionId) {
- final Transition transition = getTransition(transitionId);
- if (transition == null) {
- throw new IllegalStateException("Transition not found: " + transitionId);
- }
-
- mMANativeHelper.setGeneratePreview(true);
-
- /**
- * Remove the transition references
- */
- final MediaItem afterMediaItem = transition.getAfterMediaItem();
- if (afterMediaItem != null) {
- afterMediaItem.setEndTransition(null);
- }
-
- final MediaItem beforeMediaItem = transition.getBeforeMediaItem();
- if (beforeMediaItem != null) {
- beforeMediaItem.setBeginTransition(null);
- }
-
- mTransitions.remove(transition);
- transition.invalidate();
- computeTimelineDuration();
- return transition;
- }
-
- /*
- * {@inheritDoc}
- */
- public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs,
- OverlayData overlayData) {
- if (surfaceHolder == null) {
- throw new IllegalArgumentException("Surface Holder is null");
- }
-
- final Surface surface = surfaceHolder.getSurface();
- if (surface == null) {
- throw new IllegalArgumentException("Surface could not be retrieved from Surface holder");
- }
-
- if (surface.isValid() == false) {
- throw new IllegalStateException("Surface is not valid");
- }
-
- if (timeMs < 0) {
- throw new IllegalArgumentException("requested time not correct");
- } else if (timeMs > mDurationMs) {
- throw new IllegalArgumentException("requested time more than duration");
- }
- long result = 0;
-
- boolean semAcquireDone = false;
- try {
- semAcquireDone = lock(ENGINE_ACCESS_MAX_TIMEOUT_MS);
- if (semAcquireDone == false) {
- throw new IllegalStateException("Timeout waiting for semaphore");
- }
-
- if (mMANativeHelper == null) {
- throw new IllegalStateException("The video editor is not initialized");
- }
-
- if (mMediaItems.size() > 0) {
- final Rect frame = surfaceHolder.getSurfaceFrame();
- result = mMANativeHelper.renderPreviewFrame(surface,
- timeMs, frame.width(), frame.height(), overlayData);
- } else {
- result = 0;
- }
- } catch (InterruptedException ex) {
- Log.w(TAG, "The thread was interrupted", new Throwable());
- throw new IllegalStateException("The thread was interrupted");
- } finally {
- if (semAcquireDone) {
- unlock();
- }
- }
- return result;
- }
-
- /**
- * the project form XML
- */
- private void load() throws FileNotFoundException, XmlPullParserException, IOException {
- final File file = new File(mProjectPath, PROJECT_FILENAME);
- /**
- * Load the metadata
- */
- final FileInputStream fis = new FileInputStream(file);
- try {
- final List<String> ignoredMediaItems = new ArrayList<String>();
-
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(fis, "UTF-8");
- int eventType = parser.getEventType();
- String name;
- MediaItem currentMediaItem = null;
- Overlay currentOverlay = null;
- boolean regenerateProjectThumbnail = false;
- while (eventType != XmlPullParser.END_DOCUMENT) {
- switch (eventType) {
- case XmlPullParser.START_TAG: {
- name = parser.getName();
- if (TAG_PROJECT.equals(name)) {
- mAspectRatio = Integer.parseInt(parser.getAttributeValue("",
- ATTR_ASPECT_RATIO));
-
- final boolean mRegenPCM =
- Boolean.parseBoolean(parser.getAttributeValue("",
- ATTR_REGENERATE_PCM));
- mMANativeHelper.setAudioflag(mRegenPCM);
- } else if (TAG_MEDIA_ITEM.equals(name)) {
- final String mediaItemId = parser.getAttributeValue("", ATTR_ID);
- try {
- currentMediaItem = parseMediaItem(parser);
- mMediaItems.add(currentMediaItem);
- } catch (Exception ex) {
- Log.w(TAG, "Cannot load media item: " + mediaItemId, ex);
- currentMediaItem = null;
-
- // First media item is invalid, mark for project thumbnail removal
- if (mMediaItems.size() == 0) {
- regenerateProjectThumbnail = true;
- }
- // Ignore the media item
- ignoredMediaItems.add(mediaItemId);
- }
- } else if (TAG_TRANSITION.equals(name)) {
- try {
- final Transition transition = parseTransition(parser,
- ignoredMediaItems);
- // The transition will be null if the bounding
- // media items are ignored
- if (transition != null) {
- mTransitions.add(transition);
- }
- } catch (Exception ex) {
- Log.w(TAG, "Cannot load transition", ex);
- }
- } else if (TAG_OVERLAY.equals(name)) {
- if (currentMediaItem != null) {
- try {
- currentOverlay = parseOverlay(parser, currentMediaItem);
- currentMediaItem.addOverlay(currentOverlay);
- } catch (Exception ex) {
- Log.w(TAG, "Cannot load overlay", ex);
- }
- }
- } else if (TAG_OVERLAY_USER_ATTRIBUTES.equals(name)) {
- if (currentOverlay != null) {
- final int attributesCount = parser.getAttributeCount();
- for (int i = 0; i < attributesCount; i++) {
- currentOverlay.setUserAttribute(parser.getAttributeName(i),
- parser.getAttributeValue(i));
- }
- }
- } else if (TAG_EFFECT.equals(name)) {
- if (currentMediaItem != null) {
- try {
- final Effect effect = parseEffect(parser, currentMediaItem);
- currentMediaItem.addEffect(effect);
-
- if (effect instanceof EffectKenBurns) {
- final boolean isImageClipGenerated =
- Boolean.parseBoolean(parser.getAttributeValue("",
- ATTR_IS_IMAGE_CLIP_GENERATED));
- if(isImageClipGenerated) {
- final String filename = parser.getAttributeValue("",
- ATTR_GENERATED_IMAGE_CLIP);
- if (new File(filename).exists() == true) {
- ((MediaImageItem)currentMediaItem).
- setGeneratedImageClip(filename);
- ((MediaImageItem)currentMediaItem).
- setRegenerateClip(false);
- } else {
- ((MediaImageItem)currentMediaItem).
- setGeneratedImageClip(null);
- ((MediaImageItem)currentMediaItem).
- setRegenerateClip(true);
- }
- } else {
- ((MediaImageItem)currentMediaItem).
- setGeneratedImageClip(null);
- ((MediaImageItem)currentMediaItem).
- setRegenerateClip(true);
- }
- }
- } catch (Exception ex) {
- Log.w(TAG, "Cannot load effect", ex);
- }
- }
- } else if (TAG_AUDIO_TRACK.equals(name)) {
- try {
- final AudioTrack audioTrack = parseAudioTrack(parser);
- addAudioTrack(audioTrack);
- } catch (Exception ex) {
- Log.w(TAG, "Cannot load audio track", ex);
- }
- }
- break;
- }
-
- case XmlPullParser.END_TAG: {
- name = parser.getName();
- if (TAG_MEDIA_ITEM.equals(name)) {
- currentMediaItem = null;
- } else if (TAG_OVERLAY.equals(name)) {
- currentOverlay = null;
- }
- break;
- }
-
- default: {
- break;
- }
- }
- eventType = parser.next();
- }
- computeTimelineDuration();
- // Regenerate project thumbnail
- if (regenerateProjectThumbnail) {
- generateProjectThumbnail();
- regenerateProjectThumbnail = false;
- }
- } finally {
- if (fis != null) {
- fis.close();
- }
- }
- }
-
- /**
- * Parse the media item
- *
- * @param parser The parser
- * @return The media item
- */
- private MediaItem parseMediaItem(XmlPullParser parser) throws IOException {
- final String mediaItemId = parser.getAttributeValue("", ATTR_ID);
- final String type = parser.getAttributeValue("", ATTR_TYPE);
- final String filename = parser.getAttributeValue("", ATTR_FILENAME);
- final int renderingMode = Integer.parseInt(parser.getAttributeValue("",
- ATTR_RENDERING_MODE));
-
- final MediaItem currentMediaItem;
- if (MediaImageItem.class.getSimpleName().equals(type)) {
- final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION));
- currentMediaItem = new MediaImageItem(this, mediaItemId, filename,
- durationMs, renderingMode);
- } else if (MediaVideoItem.class.getSimpleName().equals(type)) {
- final long beginMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
- final long endMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME));
- final int volume = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME));
- final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_MUTED));
- final String audioWaveformFilename = parser.getAttributeValue("",
- ATTR_AUDIO_WAVEFORM_FILENAME);
- currentMediaItem = new MediaVideoItem(this, mediaItemId, filename,
- renderingMode, beginMs, endMs, volume, muted, audioWaveformFilename);
-
- final long beginTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
- final long endTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME));
- ((MediaVideoItem)currentMediaItem).setExtractBoundaries(beginTimeMs, endTimeMs);
-
- final int volumePercent = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME));
- ((MediaVideoItem)currentMediaItem).setVolume(volumePercent);
- } else {
- throw new IllegalArgumentException("Unknown media item type: " + type);
- }
-
- return currentMediaItem;
- }
-
- /**
- * Parse the transition
- *
- * @param parser The parser
- * @param ignoredMediaItems The list of ignored media items
- *
- * @return The transition
- */
- private Transition parseTransition(XmlPullParser parser, List<String> ignoredMediaItems) {
- final String transitionId = parser.getAttributeValue("", ATTR_ID);
- final String type = parser.getAttributeValue("", ATTR_TYPE);
- final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION));
- final int behavior = Integer.parseInt(parser.getAttributeValue("", ATTR_BEHAVIOR));
-
- final String beforeMediaItemId = parser.getAttributeValue("", ATTR_BEFORE_MEDIA_ITEM_ID);
- final MediaItem beforeMediaItem;
- if (beforeMediaItemId != null) {
- if (ignoredMediaItems.contains(beforeMediaItemId)) {
- // This transition is ignored
- return null;
- }
-
- beforeMediaItem = getMediaItem(beforeMediaItemId);
- } else {
- beforeMediaItem = null;
- }
-
- final String afterMediaItemId = parser.getAttributeValue("", ATTR_AFTER_MEDIA_ITEM_ID);
- final MediaItem afterMediaItem;
- if (afterMediaItemId != null) {
- if (ignoredMediaItems.contains(afterMediaItemId)) {
- // This transition is ignored
- return null;
- }
-
- afterMediaItem = getMediaItem(afterMediaItemId);
- } else {
- afterMediaItem = null;
- }
-
- final Transition transition;
- if (TransitionAlpha.class.getSimpleName().equals(type)) {
- final int blending = Integer.parseInt(parser.getAttributeValue("", ATTR_BLENDING));
- final String maskFilename = parser.getAttributeValue("", ATTR_MASK);
- final boolean invert = Boolean.getBoolean(parser.getAttributeValue("", ATTR_INVERT));
- transition = new TransitionAlpha(transitionId, afterMediaItem, beforeMediaItem,
- durationMs, behavior, maskFilename, blending, invert);
- } else if (TransitionCrossfade.class.getSimpleName().equals(type)) {
- transition = new TransitionCrossfade(transitionId, afterMediaItem, beforeMediaItem,
- durationMs, behavior);
- } else if (TransitionSliding.class.getSimpleName().equals(type)) {
- final int direction = Integer.parseInt(parser.getAttributeValue("", ATTR_DIRECTION));
- transition = new TransitionSliding(transitionId, afterMediaItem, beforeMediaItem,
- durationMs, behavior, direction);
- } else if (TransitionFadeBlack.class.getSimpleName().equals(type)) {
- transition = new TransitionFadeBlack(transitionId, afterMediaItem, beforeMediaItem,
- durationMs, behavior);
- } else {
- throw new IllegalArgumentException("Invalid transition type: " + type);
- }
-
- final boolean isTransitionGenerated = Boolean.parseBoolean(parser.getAttributeValue("",
- ATTR_IS_TRANSITION_GENERATED));
- if (isTransitionGenerated == true) {
- final String transitionFile = parser.getAttributeValue("",
- ATTR_GENERATED_TRANSITION_CLIP);
-
- if (new File(transitionFile).exists()) {
- transition.setFilename(transitionFile);
- } else {
- transition.setFilename(null);
- }
- }
-
- // Use the transition
- if (beforeMediaItem != null) {
- beforeMediaItem.setBeginTransition(transition);
- }
-
- if (afterMediaItem != null) {
- afterMediaItem.setEndTransition(transition);
- }
-
- return transition;
- }
-
- /**
- * Parse the overlay
- *
- * @param parser The parser
- * @param mediaItem The media item owner
- *
- * @return The overlay
- */
- private Overlay parseOverlay(XmlPullParser parser, MediaItem mediaItem) {
- final String overlayId = parser.getAttributeValue("", ATTR_ID);
- final String type = parser.getAttributeValue("", ATTR_TYPE);
- final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION));
- final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
-
- final Overlay overlay;
- if (OverlayFrame.class.getSimpleName().equals(type)) {
- final String filename = parser.getAttributeValue("", ATTR_FILENAME);
- overlay = new OverlayFrame(mediaItem, overlayId, filename, startTimeMs, durationMs);
- } else {
- throw new IllegalArgumentException("Invalid overlay type: " + type);
- }
-
- final String overlayRgbFileName = parser.getAttributeValue("", ATTR_OVERLAY_RGB_FILENAME);
- if (overlayRgbFileName != null) {
- ((OverlayFrame)overlay).setFilename(overlayRgbFileName);
-
- final int overlayFrameWidth = Integer.parseInt(parser.getAttributeValue("",
- ATTR_OVERLAY_FRAME_WIDTH));
- final int overlayFrameHeight = Integer.parseInt(parser.getAttributeValue("",
- ATTR_OVERLAY_FRAME_HEIGHT));
-
- ((OverlayFrame)overlay).setOverlayFrameWidth(overlayFrameWidth);
- ((OverlayFrame)overlay).setOverlayFrameHeight(overlayFrameHeight);
-
- final int resizedRGBFrameWidth = Integer.parseInt(parser.getAttributeValue("",
- ATTR_OVERLAY_RESIZED_RGB_FRAME_WIDTH));
- final int resizedRGBFrameHeight = Integer.parseInt(parser.getAttributeValue("",
- ATTR_OVERLAY_RESIZED_RGB_FRAME_HEIGHT));
-
- ((OverlayFrame)overlay).setResizedRGBSize(resizedRGBFrameWidth, resizedRGBFrameHeight);
- }
-
- return overlay;
- }
-
- /**
- * Parse the effect
- *
- * @param parser The parser
- * @param mediaItem The media item owner
- *
- * @return The effect
- */
- private Effect parseEffect(XmlPullParser parser, MediaItem mediaItem) {
- final String effectId = parser.getAttributeValue("", ATTR_ID);
- final String type = parser.getAttributeValue("", ATTR_TYPE);
- final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION));
- final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
-
- final Effect effect;
- if (EffectColor.class.getSimpleName().equals(type)) {
- final int colorEffectType = Integer.parseInt(parser.getAttributeValue("",
- ATTR_COLOR_EFFECT_TYPE));
- final int color;
- if (colorEffectType == EffectColor.TYPE_COLOR
- || colorEffectType == EffectColor.TYPE_GRADIENT) {
- color = Integer.parseInt(parser.getAttributeValue("", ATTR_COLOR_EFFECT_VALUE));
- } else {
- color = 0;
- }
- effect = new EffectColor(mediaItem, effectId, startTimeMs,
- durationMs, colorEffectType, color);
- } else if (EffectKenBurns.class.getSimpleName().equals(type)) {
- final Rect startRect = new Rect(
- Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_LEFT)),
- Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_TOP)),
- Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_RIGHT)),
- Integer.parseInt(parser.getAttributeValue("", ATTR_START_RECT_BOTTOM)));
- final Rect endRect = new Rect(
- Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_LEFT)),
- Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_TOP)),
- Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_RIGHT)),
- Integer.parseInt(parser.getAttributeValue("", ATTR_END_RECT_BOTTOM)));
- effect = new EffectKenBurns(mediaItem, effectId, startRect, endRect,
- startTimeMs, durationMs);
- } else {
- throw new IllegalArgumentException("Invalid effect type: " + type);
- }
-
- return effect;
- }
-
- /**
- * Parse the audio track
- *
- * @param parser The parser
- *
- * @return The audio track
- */
- private AudioTrack parseAudioTrack(XmlPullParser parser) throws IOException {
- final String audioTrackId = parser.getAttributeValue("", ATTR_ID);
- final String filename = parser.getAttributeValue("", ATTR_FILENAME);
- final long startTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_START_TIME));
- final long beginMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME));
- final long endMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME));
- final int volume = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME));
- final boolean muted = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_MUTED));
- final boolean loop = Boolean.parseBoolean(parser.getAttributeValue("", ATTR_LOOP));
- final boolean duckingEnabled = Boolean.parseBoolean(
- parser.getAttributeValue("", ATTR_DUCK_ENABLED));
- final int duckThreshold = Integer.parseInt(
- parser.getAttributeValue("", ATTR_DUCK_THRESHOLD));
- final int duckedTrackVolume = Integer.parseInt(parser.getAttributeValue("",
- ATTR_DUCKED_TRACK_VOLUME));
-
- final String waveformFilename = parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME);
- final AudioTrack audioTrack = new AudioTrack(this, audioTrackId,
- filename, startTimeMs,
- beginMs, endMs, loop,
- volume, muted,
- duckingEnabled,
- duckThreshold,
- duckedTrackVolume,
- waveformFilename);
-
- return audioTrack;
- }
-
- /*
- * {@inheritDoc}
- */
- public void save() throws IOException {
- final XmlSerializer serializer = Xml.newSerializer();
- final StringWriter writer = new StringWriter();
- serializer.setOutput(writer);
- serializer.startDocument("UTF-8", true);
- serializer.startTag("", TAG_PROJECT);
- serializer.attribute("",
- ATTR_ASPECT_RATIO, Integer.toString(mAspectRatio));
-
- serializer.attribute("", ATTR_REGENERATE_PCM,
- Boolean.toString(mMANativeHelper.getAudioflag()));
-
- serializer.startTag("", TAG_MEDIA_ITEMS);
- for (MediaItem mediaItem : mMediaItems) {
- serializer.startTag("", TAG_MEDIA_ITEM);
- serializer.attribute("", ATTR_ID, mediaItem.getId());
- serializer.attribute("", ATTR_TYPE,
- mediaItem.getClass().getSimpleName());
- serializer.attribute("", ATTR_FILENAME, mediaItem.getFilename());
- serializer.attribute("", ATTR_RENDERING_MODE, Integer.toString(
- mediaItem.getRenderingMode()));
- if (mediaItem instanceof MediaVideoItem) {
- final MediaVideoItem mvi = (MediaVideoItem)mediaItem;
- serializer
- .attribute("", ATTR_BEGIN_TIME,
- Long.toString(mvi.getBoundaryBeginTime()));
- serializer.attribute("", ATTR_END_TIME,
- Long.toString(mvi.getBoundaryEndTime()));
- serializer.attribute("", ATTR_VOLUME,
- Integer.toString(mvi.getVolume()));
- serializer.attribute("", ATTR_MUTED,
- Boolean.toString(mvi.isMuted()));
- if (mvi.getAudioWaveformFilename() != null) {
- serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME,
- mvi.getAudioWaveformFilename());
- }
- } else if (mediaItem instanceof MediaImageItem) {
- serializer.attribute("", ATTR_DURATION,
- Long.toString(mediaItem.getTimelineDuration()));
- }
-
- final List<Overlay> overlays = mediaItem.getAllOverlays();
- if (overlays.size() > 0) {
- serializer.startTag("", TAG_OVERLAYS);
- for (Overlay overlay : overlays) {
- serializer.startTag("", TAG_OVERLAY);
- serializer.attribute("", ATTR_ID, overlay.getId());
- serializer.attribute("",
- ATTR_TYPE, overlay.getClass().getSimpleName());
- serializer.attribute("", ATTR_BEGIN_TIME,
- Long.toString(overlay.getStartTime()));
- serializer.attribute("", ATTR_DURATION,
- Long.toString(overlay.getDuration()));
- if (overlay instanceof OverlayFrame) {
- final OverlayFrame overlayFrame = (OverlayFrame)overlay;
- overlayFrame.save(getPath());
- if (overlayFrame.getBitmapImageFileName() != null) {
- serializer.attribute("", ATTR_FILENAME,
- overlayFrame.getBitmapImageFileName());
- }
-
- if (overlayFrame.getFilename() != null) {
- serializer.attribute("",
- ATTR_OVERLAY_RGB_FILENAME,
- overlayFrame.getFilename());
- serializer.attribute("", ATTR_OVERLAY_FRAME_WIDTH,
- Integer.toString(overlayFrame.getOverlayFrameWidth()));
- serializer.attribute("", ATTR_OVERLAY_FRAME_HEIGHT,
- Integer.toString(overlayFrame.getOverlayFrameHeight()));
- serializer.attribute("", ATTR_OVERLAY_RESIZED_RGB_FRAME_WIDTH,
- Integer.toString(overlayFrame.getResizedRGBSizeWidth()));
- serializer.attribute("", ATTR_OVERLAY_RESIZED_RGB_FRAME_HEIGHT,
- Integer.toString(overlayFrame.getResizedRGBSizeHeight()));
-
- }
-
- }
-
- /**
- * Save the user attributes
- */
- serializer.startTag("", TAG_OVERLAY_USER_ATTRIBUTES);
- final Map<String, String> userAttributes = overlay.getUserAttributes();
- for (String name : userAttributes.keySet()) {
- final String value = userAttributes.get(name);
- if (value != null) {
- serializer.attribute("", name, value);
- }
- }
- serializer.endTag("", TAG_OVERLAY_USER_ATTRIBUTES);
-
- serializer.endTag("", TAG_OVERLAY);
- }
- serializer.endTag("", TAG_OVERLAYS);
- }
-
- final List<Effect> effects = mediaItem.getAllEffects();
- if (effects.size() > 0) {
- serializer.startTag("", TAG_EFFECTS);
- for (Effect effect : effects) {
- serializer.startTag("", TAG_EFFECT);
- serializer.attribute("", ATTR_ID, effect.getId());
- serializer.attribute("",
- ATTR_TYPE, effect.getClass().getSimpleName());
- serializer.attribute("", ATTR_BEGIN_TIME,
- Long.toString(effect.getStartTime()));
- serializer.attribute("", ATTR_DURATION,
- Long.toString(effect.getDuration()));
- if (effect instanceof EffectColor) {
- final EffectColor colorEffect = (EffectColor)effect;
- serializer.attribute("", ATTR_COLOR_EFFECT_TYPE,
- Integer.toString(colorEffect.getType()));
- if (colorEffect.getType() == EffectColor.TYPE_COLOR ||
- colorEffect.getType() == EffectColor.TYPE_GRADIENT) {
- serializer.attribute("", ATTR_COLOR_EFFECT_VALUE,
- Integer.toString(colorEffect.getColor()));
- }
- } else if (effect instanceof EffectKenBurns) {
- final Rect startRect = ((EffectKenBurns)effect).getStartRect();
- serializer.attribute("", ATTR_START_RECT_LEFT,
- Integer.toString(startRect.left));
- serializer.attribute("", ATTR_START_RECT_TOP,
- Integer.toString(startRect.top));
- serializer.attribute("", ATTR_START_RECT_RIGHT,
- Integer.toString(startRect.right));
- serializer.attribute("", ATTR_START_RECT_BOTTOM,
- Integer.toString(startRect.bottom));
-
- final Rect endRect = ((EffectKenBurns)effect).getEndRect();
- serializer.attribute("", ATTR_END_RECT_LEFT,
- Integer.toString(endRect.left));
- serializer.attribute("", ATTR_END_RECT_TOP,
- Integer.toString(endRect.top));
- serializer.attribute("", ATTR_END_RECT_RIGHT,
- Integer.toString(endRect.right));
- serializer.attribute("", ATTR_END_RECT_BOTTOM,
- Integer.toString(endRect.bottom));
- final MediaItem mItem = effect.getMediaItem();
- if(((MediaImageItem)mItem).getGeneratedImageClip() != null) {
- serializer.attribute("", ATTR_IS_IMAGE_CLIP_GENERATED,
- Boolean.toString(true));
- serializer.attribute("", ATTR_GENERATED_IMAGE_CLIP,
- ((MediaImageItem)mItem).getGeneratedImageClip());
- } else {
- serializer.attribute("", ATTR_IS_IMAGE_CLIP_GENERATED,
- Boolean.toString(false));
- }
- }
-
- serializer.endTag("", TAG_EFFECT);
- }
- serializer.endTag("", TAG_EFFECTS);
- }
-
- serializer.endTag("", TAG_MEDIA_ITEM);
- }
- serializer.endTag("", TAG_MEDIA_ITEMS);
-
- serializer.startTag("", TAG_TRANSITIONS);
-
- for (Transition transition : mTransitions) {
- serializer.startTag("", TAG_TRANSITION);
- serializer.attribute("", ATTR_ID, transition.getId());
- serializer.attribute("", ATTR_TYPE, transition.getClass().getSimpleName());
- serializer.attribute("", ATTR_DURATION, Long.toString(transition.getDuration()));
- serializer.attribute("", ATTR_BEHAVIOR, Integer.toString(transition.getBehavior()));
- serializer.attribute("", ATTR_IS_TRANSITION_GENERATED,
- Boolean.toString(transition.isGenerated()));
- if (transition.isGenerated() == true) {
- serializer.attribute("", ATTR_GENERATED_TRANSITION_CLIP, transition.mFilename);
- }
- final MediaItem afterMediaItem = transition.getAfterMediaItem();
- if (afterMediaItem != null) {
- serializer.attribute("", ATTR_AFTER_MEDIA_ITEM_ID, afterMediaItem.getId());
- }
-
- final MediaItem beforeMediaItem = transition.getBeforeMediaItem();
- if (beforeMediaItem != null) {
- serializer.attribute("", ATTR_BEFORE_MEDIA_ITEM_ID, beforeMediaItem.getId());
- }
-
- if (transition instanceof TransitionSliding) {
- serializer.attribute("", ATTR_DIRECTION,
- Integer.toString(((TransitionSliding)transition).getDirection()));
- } else if (transition instanceof TransitionAlpha) {
- TransitionAlpha ta = (TransitionAlpha)transition;
- serializer.attribute("", ATTR_BLENDING,
- Integer.toString(ta.getBlendingPercent()));
- serializer.attribute("", ATTR_INVERT,
- Boolean.toString(ta.isInvert()));
- if (ta.getMaskFilename() != null) {
- serializer.attribute("", ATTR_MASK, ta.getMaskFilename());
- }
- }
- serializer.endTag("", TAG_TRANSITION);
- }
- serializer.endTag("", TAG_TRANSITIONS);
- serializer.startTag("", TAG_AUDIO_TRACKS);
- for (AudioTrack at : mAudioTracks) {
- serializer.startTag("", TAG_AUDIO_TRACK);
- serializer.attribute("", ATTR_ID, at.getId());
- serializer.attribute("", ATTR_FILENAME, at.getFilename());
- serializer.attribute("", ATTR_START_TIME, Long.toString(at.getStartTime()));
- serializer.attribute("", ATTR_BEGIN_TIME, Long.toString(at.getBoundaryBeginTime()));
- serializer.attribute("", ATTR_END_TIME, Long.toString(at.getBoundaryEndTime()));
- serializer.attribute("", ATTR_VOLUME, Integer.toString(at.getVolume()));
- serializer.attribute("", ATTR_DUCK_ENABLED,
- Boolean.toString(at.isDuckingEnabled()));
- serializer.attribute("", ATTR_DUCKED_TRACK_VOLUME,
- Integer.toString(at.getDuckedTrackVolume()));
- serializer.attribute("", ATTR_DUCK_THRESHOLD,
- Integer.toString(at.getDuckingThreshhold()));
- serializer.attribute("", ATTR_MUTED, Boolean.toString(at.isMuted()));
- serializer.attribute("", ATTR_LOOP, Boolean.toString(at.isLooping()));
- if (at.getAudioWaveformFilename() != null) {
- serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME,
- at.getAudioWaveformFilename());
- }
-
- serializer.endTag("", TAG_AUDIO_TRACK);
- }
- serializer.endTag("", TAG_AUDIO_TRACKS);
-
- serializer.endTag("", TAG_PROJECT);
- serializer.endDocument();
-
- /**
- * Save the metadata XML file
- */
- final FileOutputStream out = new FileOutputStream(new File(getPath(),
- PROJECT_FILENAME));
- out.write(writer.toString().getBytes());
- out.flush();
- out.close();
- }
-
- /*
- * {@inheritDoc}
- */
- public void setAspectRatio(int aspectRatio) {
- mAspectRatio = aspectRatio;
- /**
- * Invalidate all transitions
- */
- mMANativeHelper.setGeneratePreview(true);
-
- for (Transition transition : mTransitions) {
- transition.invalidate();
- }
-
- final Iterator<MediaItem> it = mMediaItems.iterator();
-
- while (it.hasNext()) {
- final MediaItem t = it.next();
- List<Overlay> overlayList = t.getAllOverlays();
- for (Overlay overlay : overlayList) {
-
- ((OverlayFrame)overlay).invalidateGeneratedFiles();
- }
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs,
- boolean loop, int callbackAfterFrameCount,
- PreviewProgressListener listener) {
-
- if (surfaceHolder == null) {
- throw new IllegalArgumentException();
- }
-
- final Surface surface = surfaceHolder.getSurface();
- if (surface == null) {
- throw new IllegalArgumentException("Surface could not be retrieved from surface holder");
- }
-
- if (surface.isValid() == false) {
- throw new IllegalStateException("Surface is not valid");
- }
-
- if (listener == null) {
- throw new IllegalArgumentException();
- }
-
- if (fromMs >= mDurationMs) {
- throw new IllegalArgumentException("Requested time not correct");
- }
-
- if (fromMs < 0) {
- throw new IllegalArgumentException("Requested time not correct");
- }
-
- boolean semAcquireDone = false;
- if (!mPreviewInProgress) {
- try{
- semAcquireDone = lock(ENGINE_ACCESS_MAX_TIMEOUT_MS);
- if (semAcquireDone == false) {
- throw new IllegalStateException("Timeout waiting for semaphore");
- }
-
- if (mMANativeHelper == null) {
- throw new IllegalStateException("The video editor is not initialized");
- }
-
- if (mMediaItems.size() > 0) {
- mPreviewInProgress = true;
- mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions,
- mAudioTracks, null);
- mMANativeHelper.doPreview(surface, fromMs, toMs, loop,
- callbackAfterFrameCount, listener);
- }
- /**
- * Release The lock on complete by calling stopPreview
- */
- } catch (InterruptedException ex) {
- Log.w(TAG, "The thread was interrupted", new Throwable());
- throw new IllegalStateException("The thread was interrupted");
- }
- } else {
- throw new IllegalStateException("Preview already in progress");
- }
- }
-
- /*
- * {@inheritDoc}
- */
- public long stopPreview() {
- long result = 0;
- if (mPreviewInProgress) {
- try {
- result = mMANativeHelper.stopPreview();
- /**
- * release on complete by calling stopPreview
- */
- } finally {
- mPreviewInProgress = false;
- unlock();
- }
- return result;
- }
- else {
- return 0;
- }
- }
-
- /*
- * Remove transitions associated with the specified media item
- *
- * @param mediaItem The media item
- */
- private void removeAdjacentTransitions(MediaItem mediaItem) {
- final Transition beginTransition = mediaItem.getBeginTransition();
- if (beginTransition != null) {
- if (beginTransition.getAfterMediaItem() != null) {
- beginTransition.getAfterMediaItem().setEndTransition(null);
- }
- beginTransition.invalidate();
- mTransitions.remove(beginTransition);
- }
-
- final Transition endTransition = mediaItem.getEndTransition();
- if (endTransition != null) {
- if (endTransition.getBeforeMediaItem() != null) {
- endTransition.getBeforeMediaItem().setBeginTransition(null);
- }
- endTransition.invalidate();
- mTransitions.remove(endTransition);
- }
-
- mediaItem.setBeginTransition(null);
- mediaItem.setEndTransition(null);
- }
-
- /**
- * Remove the transition before this media item
- *
- * @param index The media item index
- */
- private void removeTransitionBefore(int index) {
- final MediaItem mediaItem = mMediaItems.get(index);
- final Iterator<Transition> it = mTransitions.iterator();
- while (it.hasNext()) {
- Transition t = it.next();
- if (t.getBeforeMediaItem() == mediaItem) {
- mMANativeHelper.setGeneratePreview(true);
- it.remove();
- t.invalidate();
- mediaItem.setBeginTransition(null);
- if (index > 0) {
- mMediaItems.get(index - 1).setEndTransition(null);
- }
- break;
- }
- }
- }
-
- /**
- * Remove the transition after this media item
- *
- * @param mediaItem The media item
- */
- private void removeTransitionAfter(int index) {
- final MediaItem mediaItem = mMediaItems.get(index);
- final Iterator<Transition> it = mTransitions.iterator();
- while (it.hasNext()) {
- Transition t = it.next();
- if (t.getAfterMediaItem() == mediaItem) {
- mMANativeHelper.setGeneratePreview(true);
- it.remove();
- t.invalidate();
- mediaItem.setEndTransition(null);
- /**
- * Invalidate the reference in the next media item
- */
- if (index < mMediaItems.size() - 1) {
- mMediaItems.get(index + 1).setBeginTransition(null);
- }
- break;
- }
- }
- }
-
- /**
- * Compute the duration
- */
- private void computeTimelineDuration() {
- mDurationMs = 0;
- final int mediaItemsCount = mMediaItems.size();
- for (int i = 0; i < mediaItemsCount; i++) {
- final MediaItem mediaItem = mMediaItems.get(i);
- mDurationMs += mediaItem.getTimelineDuration();
- if (mediaItem.getEndTransition() != null) {
- if (i < mediaItemsCount - 1) {
- mDurationMs -= mediaItem.getEndTransition().getDuration();
- }
- }
- }
- }
-
- /*
- * Generate the project thumbnail
- */
- private void generateProjectThumbnail() {
- /*
- * If a thumbnail already exists, then delete it first
- */
- if ((new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).exists()) {
- (new File(mProjectPath + "/" + THUMBNAIL_FILENAME)).delete();
- }
- /*
- * Generate a new thumbnail for the project from first media Item
- */
- if (mMediaItems.size() > 0) {
- MediaItem mI = mMediaItems.get(0);
- /*
- * Keep aspect ratio of the image
- */
- int height = 480;
- int width = mI.getWidth() * height / mI.getHeight();
-
- Bitmap projectBitmap = null;
- String filename = mI.getFilename();
- if (mI instanceof MediaVideoItem) {
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setDataSource(filename);
- Bitmap bitmap = retriever.getFrameAtTime();
- retriever.release();
- retriever = null;
- if (bitmap == null) {
- String msg = "Thumbnail extraction from " +
- filename + " failed";
- throw new IllegalArgumentException(msg);
- }
- // Resize the thumbnail to the target size
- projectBitmap =
- Bitmap.createScaledBitmap(bitmap, width, height, true);
- } else {
- try {
- projectBitmap = mI.getThumbnail(width, height, 500);
- } catch (IllegalArgumentException e) {
- String msg = "Project thumbnail extraction from " +
- filename + " failed";
- throw new IllegalArgumentException(msg);
- } catch (IOException e) {
- String msg = "IO Error creating project thumbnail";
- throw new IllegalArgumentException(msg);
- }
- }
-
- FileOutputStream stream = null;
- try {
- stream = new FileOutputStream(mProjectPath + "/" + THUMBNAIL_FILENAME);
- projectBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
- stream.flush();
- } catch (IOException e) {
- throw new IllegalArgumentException ("Error creating project thumbnail");
- } finally {
- IoUtils.closeQuietly(stream);
- projectBitmap.recycle();
- }
- }
- }
-
- /**
- * Clears the preview surface
- *
- * @param surfaceHolder SurfaceHolder where the preview is rendered
- * and needs to be cleared.
- */
- public void clearSurface(SurfaceHolder surfaceHolder) {
- if (surfaceHolder == null) {
- throw new IllegalArgumentException("Invalid surface holder");
- }
-
- final Surface surface = surfaceHolder.getSurface();
- if (surface == null) {
- throw new IllegalArgumentException("Surface could not be retrieved from surface holder");
- }
-
- if (surface.isValid() == false) {
- throw new IllegalStateException("Surface is not valid");
- }
-
- if (mMANativeHelper != null) {
- mMANativeHelper.clearPreviewSurface(surface);
- } else {
- Log.w(TAG, "Native helper was not ready!");
- }
- }
-
- /**
- * Grab the semaphore which arbitrates access to the editor
- *
- * @throws InterruptedException
- */
- private void lock() throws InterruptedException {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "lock: grabbing semaphore", new Throwable());
- }
- mLock.acquire();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "lock: grabbed semaphore");
- }
- }
-
- /**
- * Tries to grab the semaphore with a specified time out which arbitrates access to the editor
- *
- * @param timeoutMs time out in ms.
- *
- * @return true if the semaphore is acquired, false otherwise
- * @throws InterruptedException
- */
- private boolean lock(long timeoutMs) throws InterruptedException {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "lock: grabbing semaphore with timeout " + timeoutMs, new Throwable());
- }
-
- boolean acquireSem = mLock.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "lock: grabbed semaphore status " + acquireSem);
- }
-
- return acquireSem;
- }
-
- /**
- * Release the semaphore which arbitrates access to the editor
- */
- private void unlock() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "unlock: releasing semaphore");
- }
- mLock.release();
- }
-
- /**
- * Dumps the heap memory usage information to file
- */
- private static void dumpHeap (String filename) throws Exception {
- /* Cleanup as much as possible before dump
- */
- System.gc();
- System.runFinalization();
- Thread.sleep(1000);
- String state = Environment.getExternalStorageState();
- if (Environment.MEDIA_MOUNTED.equals(state)) {
- String extDir =
- Environment.getExternalStorageDirectory().toString();
-
- /* If dump file already exists, then delete it first
- */
- if ((new File(extDir + "/" + filename + ".dump")).exists()) {
- (new File(extDir + "/" + filename + ".dump")).delete();
- }
- /* Dump native heap
- */
- FileOutputStream ost =
- new FileOutputStream(extDir + "/" + filename + ".dump");
- Debug.dumpNativeHeap(ost.getFD());
- ost.close();
- }
- }
-}
diff --git a/media/java/android/media/videoeditor/VideoEditorProfile.java b/media/java/android/media/videoeditor/VideoEditorProfile.java
deleted file mode 100644
index 202a2df..0000000
--- a/media/java/android/media/videoeditor/VideoEditorProfile.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media.videoeditor;
-
-/**
- * The VideoEditorProfile class is used to retrieve the
- * predefined videoeditor profile settings for videoeditor applications.
- * These settings are read-only.
- *
- * <p>The videoeditor profile specifies the following set of parameters:
- * <ul>
- * <li> max input video frame width
- * <li> max input video frame height
- * <li> max output video frame width
- * <li> max output video frame height
- * </ul>
- * {@hide}
- */
-public class VideoEditorProfile
-{
- static {
- System.loadLibrary("media_jni");
- native_init();
- }
- /**
- * The max input video frame width
- */
- public int maxInputVideoFrameWidth;
-
- /**
- * The max input video frame height
- */
- public int maxInputVideoFrameHeight;
-
- /**
- * The max ouput video frame width
- */
- public int maxOutputVideoFrameWidth;
-
- /**
- * The max ouput video frame height
- */
- public int maxOutputVideoFrameHeight;
-
- /**
- * Returns the videoeditor profile
- */
- public static VideoEditorProfile get() {
- return native_get_videoeditor_profile();
- }
-
- /**
- * Returns the supported profile by given video codec
- */
- public static int getExportProfile(int vidCodec) {
- int profile = -1;
-
- switch (vidCodec) {
- case MediaProperties.VCODEC_H263:
- case MediaProperties.VCODEC_H264:
- case MediaProperties.VCODEC_MPEG4:
- profile = native_get_videoeditor_export_profile(vidCodec);
- break;
- default :
- throw new IllegalArgumentException("Unsupported video codec" + vidCodec);
- }
-
- return profile;
- }
-
- /**
- * Returns the supported level by given video codec
- */
- public static int getExportLevel(int vidCodec) {
- int level = -1;
-
- switch (vidCodec) {
- case MediaProperties.VCODEC_H263:
- case MediaProperties.VCODEC_H264:
- case MediaProperties.VCODEC_MPEG4:
- level = native_get_videoeditor_export_level(vidCodec);
- break;
- default :
- throw new IllegalArgumentException("Unsupported video codec" + vidCodec);
- }
-
- return level;
- }
-
- // Private constructor called by JNI
- private VideoEditorProfile(int inputWidth,
- int inputHeight,
- int outputWidth,
- int outputHeight) {
-
- this.maxInputVideoFrameWidth = inputWidth;
- this.maxInputVideoFrameHeight = inputHeight;
- this.maxOutputVideoFrameWidth = outputWidth;
- this.maxOutputVideoFrameHeight = outputHeight;
- }
-
- // Methods implemented by JNI
- private static native final void native_init();
- private static native final VideoEditorProfile
- native_get_videoeditor_profile();
- private static native final int native_get_videoeditor_export_profile(int codec);
- private static native final int native_get_videoeditor_export_level(int level);
-
-}
diff --git a/media/java/android/media/videoeditor/WaveformData.java b/media/java/android/media/videoeditor/WaveformData.java
deleted file mode 100644
index 6c10e3c..0000000
--- a/media/java/android/media/videoeditor/WaveformData.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2010 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.media.videoeditor;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-
-/**
- * Class which describes the waveform data of an audio track. The gain values
- * represent the average gain for an audio frame. For audio codecs which do not
- * operate on a per frame bases (eg. ALAW, ULAW) a reasonable audio frame
- * duration will be assumed (eg. 50ms).
- * {@hide}
- */
-public class WaveformData {
- /*
- * Instance variables
- */
- private final int mFrameDurationMs;
- private final int mFramesCount;
- private final short[] mGains;
-
- /*
- * This constructor shall not be used
- */
- @SuppressWarnings("unused")
- private WaveformData() throws IOException {
- mFrameDurationMs = 0;
- mFramesCount = 0;
- mGains = null;
- }
-
- /*
- * Constructor
- *
- * @param audioWaveformFilename The name of the audio waveform file
- *
- * The file format is as following:
- * <ul>
- * <li>first 4 bytes provide the number of samples for each value, as
- * big-endian signed</li>
- * <li>4 following bytes is the total number of values in the file, as
- * big-endian signed</li>
- * <li>then, all values follow as bytes</li>
- * </ul>
- *
- * @throws IOException on failure of file input stream operations
- * @throws IllegalArgumentException if audioWaveformFilename is null
- */
- WaveformData(String audioWaveformFilename) throws IOException {
-
- if (audioWaveformFilename == null) {
- throw new IllegalArgumentException("WaveformData : filename is null");
- }
-
- FileInputStream audioGraphFileReadHandle = null;
-
- try {
- final File audioGraphFileContext = new File(audioWaveformFilename);
-
- audioGraphFileReadHandle = new FileInputStream(audioGraphFileContext);
- /*
- * Read frame duration
- */
- final byte tempFrameDuration[] = new byte[4];
-
- audioGraphFileReadHandle.read(tempFrameDuration, 0, 4);
-
- int tempFrameDurationMs = 0;
- int tempFramesCounter = 0;
- for (int i = 0; i < 4; i++) {
- tempFrameDurationMs = (tempFrameDurationMs << 8);
- tempFrameDurationMs = (tempFrameDurationMs | (tempFrameDuration[i] & 0xff));
- }
- mFrameDurationMs = tempFrameDurationMs;
-
- /*
- * Read count
- */
- final byte tempFramesCount[] = new byte[4];
-
- audioGraphFileReadHandle.read(tempFramesCount, 0, 4);
- for (int i = 0; i < 4; i++) {
- tempFramesCounter = (tempFramesCounter << 8);
- tempFramesCounter = (tempFramesCounter | (tempFramesCount[i] & 0xff));
- }
- mFramesCount = tempFramesCounter;
-
- /*
- * Capture the graph values
- */
- mGains = new short[mFramesCount];
-
- for (int i = 0; i < mFramesCount; i++) {
- mGains[i] = (short)audioGraphFileReadHandle.read();
- }
- } finally {
- if (audioGraphFileReadHandle != null) {
- audioGraphFileReadHandle.close();
- }
- }
- }
-
- /**
- * @return The duration of a frame in milliseconds
- */
- public int getFrameDuration() {
- return mFrameDurationMs;
- }
-
- /**
- * @return The number of frames within the waveform data
- */
- public int getFramesCount() {
- return mFramesCount;
- }
-
- /**
- * @return The array of frame gains. The size of the array is the frames
- * count. The values of the frame gains range from 0 to 255.
- */
- public short[] getFrameGains() {
- return mGains;
- }
-}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 716418c..7a86811 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -274,17 +274,11 @@
fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I");
jpegFormat = env->GetStaticIntField(imageFormatClazz, fid);
- fid = env->GetStaticFieldID(imageFormatClazz, "RAW_SENSOR", "I");
- rawSensorFormat = env->GetStaticIntField(imageFormatClazz, fid);
- // Translate the JPEG to BLOB for camera purpose, an add more if more mismatch is found.
+ // Translate the JPEG to BLOB for camera purpose.
if (format == jpegFormat) {
format = HAL_PIXEL_FORMAT_BLOB;
}
- // Same thing for RAW_SENSOR format
- if (format == rawSensorFormat) {
- format = HAL_PIXEL_FORMAT_RAW_SENSOR;
- }
return format;
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 7c45682..4fbd2a4 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -297,8 +297,6 @@
}
JDrm::~JDrm() {
- mDrm.clear();
-
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->DeleteWeakGlobalRef(mObject);
@@ -363,6 +361,13 @@
}
}
+void JDrm::disconnect() {
+ if (mDrm != NULL) {
+ mDrm->destroyPlugin();
+ mDrm.clear();
+ }
+}
+
// static
bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
@@ -527,6 +532,7 @@
sp<JDrm> drm = setDrm(env, thiz, NULL);
if (drm != NULL) {
drm->setListener(NULL);
+ drm->disconnect();
}
}
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index 620ad28..b7b8e5d 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -47,6 +47,8 @@
void notify(DrmPlugin::EventType, int extra, const Parcel *obj);
status_t setListener(const sp<DrmListener>& listener);
+ void disconnect();
+
protected:
virtual ~JDrm();
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index 48a9132..1e5c700 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -290,75 +290,6 @@
}
return static_cast<jint>(levels[index]);
}
-static jobject
-android_media_MediaProfiles_native_get_videoeditor_profile(JNIEnv *env, jobject thiz)
-{
- ALOGV("native_get_videoeditor_profile");
-
- int maxInputFrameWidth =
- sProfiles->getVideoEditorCapParamByName("videoeditor.input.width.max");
- int maxInputFrameHeight =
- sProfiles->getVideoEditorCapParamByName("videoeditor.input.height.max");
- int maxOutputFrameWidth =
- sProfiles->getVideoEditorCapParamByName("videoeditor.output.width.max");
- int maxOutputFrameHeight =
- sProfiles->getVideoEditorCapParamByName("videoeditor.output.height.max");
-
- // Check on the values retrieved
- if (maxInputFrameWidth == -1 || maxInputFrameHeight == -1 ||
- maxOutputFrameWidth == -1 || maxOutputFrameHeight == -1) {
-
- jniThrowException(env, "java/lang/RuntimeException",\
- "Error retrieving videoeditor profile params");
- return NULL;
- }
- ALOGV("native_get_videoeditor_profile \
- inWidth:%d inHeight:%d,outWidth:%d, outHeight:%d",\
- maxInputFrameWidth,maxInputFrameHeight,\
- maxOutputFrameWidth,maxOutputFrameHeight);
-
- jclass VideoEditorProfileClazz =
- env->FindClass("android/media/videoeditor/VideoEditorProfile");
- jmethodID VideoEditorProfileConstructorMethodID =
- env->GetMethodID(VideoEditorProfileClazz, "<init>", "(IIII)V");
- return env->NewObject(VideoEditorProfileClazz,
- VideoEditorProfileConstructorMethodID,
- maxInputFrameWidth,
- maxInputFrameHeight,
- maxOutputFrameWidth,
- maxOutputFrameHeight);
-}
-static jint
-android_media_MediaProfiles_native_get_videoeditor_export_profile(
- JNIEnv *env, jobject thiz, jint codec)
-{
- ALOGV("android_media_MediaProfiles_native_get_export_profile index ");
- int profile =0;
- profile = sProfiles->getVideoEditorExportParamByName("videoeditor.export.profile", codec);
- // Check the values retrieved
- if (profile == -1) {
- jniThrowException(env, "java/lang/RuntimeException",\
- "Error retrieving videoeditor export profile params");
- return -1;
- }
- return static_cast<jint>(profile);
-}
-
-static jint
-android_media_MediaProfiles_native_get_videoeditor_export_level(
- JNIEnv *env, jobject thiz, jint codec)
-{
- ALOGV("android_media_MediaProfiles_native_get_export_level");
- int level =0;
- level = sProfiles->getVideoEditorExportParamByName("videoeditor.export.level", codec);
- // Check the values retrieved
- if (level == -1) {
- jniThrowException(env, "java/lang/RuntimeException",\
- "Error retrieving videoeditor export level params");
- return -1;
- }
- return static_cast<jint>(level);
-}
static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
{"native_init", "()V", (void *)android_media_MediaProfiles_native_init},
{"native_get_num_file_formats", "()I", (void *)android_media_MediaProfiles_native_get_num_file_formats},
@@ -396,19 +327,10 @@
{"native_get_image_encoding_quality_level","(II)I", (void *)android_media_MediaProfiles_native_get_image_encoding_quality_level},
};
-static JNINativeMethod gMethodsForVideoEditorProfileClass[] = {
- {"native_init", "()V", (void *)android_media_MediaProfiles_native_init},
- {"native_get_videoeditor_profile", "()Landroid/media/videoeditor/VideoEditorProfile;", (void *)android_media_MediaProfiles_native_get_videoeditor_profile},
- {"native_get_videoeditor_export_profile", "(I)I", (void *)android_media_MediaProfiles_native_get_videoeditor_export_profile},
- {"native_get_videoeditor_export_level", "(I)I", (void *)android_media_MediaProfiles_native_get_videoeditor_export_level},
-};
-
static const char* const kEncoderCapabilitiesClassPathName = "android/media/EncoderCapabilities";
static const char* const kDecoderCapabilitiesClassPathName = "android/media/DecoderCapabilities";
static const char* const kCamcorderProfileClassPathName = "android/media/CamcorderProfile";
static const char* const kCameraProfileClassPathName = "android/media/CameraProfile";
-static const char* const kVideoEditorProfileClassPathName =
- "android/media/videoeditor/VideoEditorProfile";
// This function only registers the native methods, and is called from
// JNI_OnLoad in android_media_MediaPlayer.cpp
@@ -434,11 +356,6 @@
gMethodsForCameraProfileClass,
NELEM(gMethodsForCameraProfileClass));
- int ret5 = AndroidRuntime::registerNativeMethods(env,
- kVideoEditorProfileClassPathName,
- gMethodsForVideoEditorProfileClass,
- NELEM(gMethodsForVideoEditorProfileClass));
-
// Success if all return values from above are 0
- return (ret1 || ret2 || ret3 || ret4 || ret5);
+ return (ret1 || ret2 || ret3 || ret4);
}
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 0e55228..d781336 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -859,6 +859,7 @@
result = malloc(exifdata->size);
if (result) {
memcpy(result, exifdata->data, exifdata->size);
+ outThumbSize = exifdata->size;
}
}
exif_data_unref(exifdata);
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
deleted file mode 100644
index 312c366..0000000
--- a/media/jni/mediaeditor/Android.mk
+++ /dev/null
@@ -1,81 +0,0 @@
-#
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- VideoEditorMain.cpp \
- VideoEditorClasses.cpp \
- VideoEditorOsal.cpp \
- VideoEditorJava.cpp \
- VideoEditorPropertiesMain.cpp \
- VideoEditorThumbnailMain.cpp \
- VideoBrowserMain.c
-
-LOCAL_C_INCLUDES += \
- $(TOP)/frameworks/base/core/jni \
- $(TOP)/frameworks/base/include \
- $(TOP)/frameworks/base/include/media \
- $(TOP)/frameworks/base/media/libmediaplayerservice \
- $(TOP)/frameworks/base/media/libstagefright \
- $(TOP)/frameworks/base/media/libstagefright/include \
- $(TOP)/frameworks/base/media/libstagefright/rtsp \
- $(JNI_H_INCLUDE) \
- $(TOP)/frameworks/native/include/media/editor \
- $(TOP)/frameworks/base/core/jni/mediaeditor \
- $(TOP)/frameworks/av/libvideoeditor/vss/inc \
- $(TOP)/frameworks/av/libvideoeditor/vss/common/inc \
- $(TOP)/frameworks/av/libvideoeditor/vss/mcs/inc \
- $(TOP)/frameworks/av/libvideoeditor/vss/stagefrightshells/inc \
- $(TOP)/frameworks/av/libvideoeditor/lvpp \
- $(TOP)/frameworks/av/libvideoeditor/osal/inc \
- $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- libaudioutils \
- libbinder \
- libcutils \
- liblog \
- libdl \
- libgui \
- libmedia \
- libnativehelper \
- libstagefright \
- libstagefright_foundation \
- libstagefright_omx \
- libutils \
- libvideoeditor_core \
- libvideoeditor_osal \
- libvideoeditor_videofilters \
- libvideoeditorplayer \
-
-
-LOCAL_CFLAGS += \
- -DUSE_STAGEFRIGHT_CODECS \
- -DUSE_STAGEFRIGHT_AUDIODEC \
- -DUSE_STAGEFRIGHT_VIDEODEC \
- -DUSE_STAGEFRIGHT_AUDIOENC \
- -DUSE_STAGEFRIGHT_VIDEOENC \
- -DUSE_STAGEFRIGHT_READERS \
- -DUSE_STAGEFRIGHT_3GPP_READER
-
-LOCAL_MODULE:= libvideoeditor_jni
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/mediaeditor/MODULE_LICENSE_APACHE2 b/media/jni/mediaeditor/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/media/jni/mediaeditor/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/media/jni/mediaeditor/NOTICE b/media/jni/mediaeditor/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/media/jni/mediaeditor/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/media/jni/mediaeditor/VideoBrowserInternal.h b/media/jni/mediaeditor/VideoBrowserInternal.h
deleted file mode 100644
index f4eaab8..0000000
--- a/media/jni/mediaeditor/VideoBrowserInternal.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef VIDEO_BROWSER_INTERNAL_H
-#define VIDEO_BROWSER_INTERNAL_H
-
-#include "VideoBrowserMain.h"
-
-#include "M4READER_Common.h"
-#include "M4DECODER_Common.h"
-
-
-#define VIDEO_BROWSER_BGR565
-
-/*---------------------------- MACROS ----------------------------*/
-#define CHECK_PTR(fct, p, err, errValue) \
-{ \
- if (M4OSA_NULL == p) \
- { \
- err = errValue ; \
- M4OSA_TRACE1_1("" #fct "(L%d): " #p " is NULL, returning " #errValue "", __LINE__) ; \
- goto fct##_cleanUp; \
- } \
-}
-
-#define CHECK_ERR(fct, err) \
-{ \
- if (M4OSA_ERR_IS_ERROR(err)) \
- { \
- M4OSA_TRACE1_2("" #fct "(L%d): ERROR 0x%.8x returned", __LINE__,err) ; \
- goto fct##_cleanUp; \
- } \
- else if (M4OSA_ERR_IS_WARNING(err)) \
- { \
- M4OSA_TRACE2_2("" #fct "(L%d): WARNING 0x%.8x returned", __LINE__,err) ; \
- } \
-}
-
-#define CHECK_STATE(fct, state, pC) \
-{ \
- if (state != pC->m_state) \
- { \
- M4OSA_TRACE1_1("" #fct " called in bad state %d", pC->m_state) ; \
- err = M4ERR_STATE ; \
- goto fct##_cleanUp; \
- } \
-}
-
-#define SAFE_FREE(p) \
-{ \
- if (M4OSA_NULL != p) \
- { \
- free(p) ; \
- p = M4OSA_NULL ; \
- } \
-}
-
-/*--- Video Browser state ---*/
-typedef enum
-{
- VideoBrowser_kVBCreating,
- VideoBrowser_kVBOpened,
- VideoBrowser_kVBBrowsing
-} VideoBrowser_videoBrowerState;
-
-
-/*--- Video Browser execution context. ---*/
-typedef struct
-{
- VideoBrowser_videoBrowerState m_state ;
- VideoBrowser_videoBrowerDrawMode m_drawmode;
-
- M4OSA_Context g_hbmp2;
- M4OSA_Context dc;
- M4OSA_Int16* g_bmPixels2;
-
- /*--- Reader parameters ---*/
- M4OSA_FileReadPointer m_fileReadPtr;
- M4READER_GlobalInterface* m_3gpReader ;
- M4READER_DataInterface* m_3gpData ;
- M4READER_MediaType m_mediaType ;
- M4OSA_Context m_pReaderCtx ;
-
- M4_StreamHandler* m_pStreamHandler ;
- M4_AccessUnit m_accessUnit ;
-
- /*--- Decoder parameters ---*/
- M4DECODER_VideoInterface* m_pDecoder ;
- M4OSA_Context m_pDecoderCtx ;
-
- /*--- Common display parameters ---*/
- M4OSA_UInt32 m_x ;
- M4OSA_UInt32 m_y ;
- M4VIFI_ImagePlane m_outputPlane[3] ;
-
- /*--- Current browsing time ---*/
- M4OSA_UInt32 m_currentCTS ;
-
- /*--- Platform dependent display parameters ---*/
- M4OSA_Context m_pCoreContext ;
-
- /*--- Callback function settings ---*/
- videoBrowser_Callback m_pfCallback;
- M4OSA_Void* m_pCallbackUserData;
-
- /*--- Codec Loader core context ---*/
- M4OSA_Context m_pCodecLoaderContext;
-
- /*--- Required color type ---*/
- VideoBrowser_VideoColorType m_frameColorType;
-
-} VideoBrowserContext;
-
-#endif /* VIDEO_BROWSER_INTERNAL_H */
diff --git a/media/jni/mediaeditor/VideoBrowserMain.c b/media/jni/mediaeditor/VideoBrowserMain.c
deleted file mode 100644
index c6c6000..0000000
--- a/media/jni/mediaeditor/VideoBrowserMain.c
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "VideoEditorVideoDecoder.h"
-#include "VideoEditor3gpReader.h"
-
-#include <utils/Log.h>
-#include "VideoBrowserInternal.h"
-#include "LVOSA_FileReader_optim.h"
-
-//#define M4OSA_TRACE_LEVEL 1
-#if (M4OSA_TRACE_LEVEL >= 1)
-#undef M4OSA_TRACE1_0
-#undef M4OSA_TRACE1_1
-#undef M4OSA_TRACE1_2
-#undef M4OSA_TRACE1_3
-
-#define M4OSA_TRACE1_0(a) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a);
-#define M4OSA_TRACE1_1(a,b) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b);
-#define M4OSA_TRACE1_2(a,b,c) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b,c);
-#define M4OSA_TRACE1_3(a,b,c,d) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b,c,d);
-#endif
-
-/******************************************************************************
- * M4OSA_ERR videoBrowserSetWindow(
- * M4OSA_Context pContext, M4OSA_UInt32 x,
- * M4OSA_UInt32 y, M4OSA_UInt32 dx, M4OSA_UInt32 dy);
- * @brief This function sets the size and the position of the display.
- * @param pContext (IN) : Video Browser context
- * @param pPixelArray (IN) : Array to hold the video frame.
- * @param x (IN) : Horizontal position of the top left
- * corner
- * @param y (IN) : Vertical position of the top left corner
- * @param dx (IN) : Width of the display window
- * @param dy (IN) : Height of the video window
- * @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
- ******************************************************************************/
-M4OSA_ERR videoBrowserSetWindow(
- M4OSA_Context pContext,
- M4OSA_Int32 *pPixelArray,
- M4OSA_UInt32 x, M4OSA_UInt32 y,
- M4OSA_UInt32 dx, M4OSA_UInt32 dy)
-{
- VideoBrowserContext* pC = (VideoBrowserContext*)pContext;
- M4OSA_ERR err = M4NO_ERROR;
-
- M4OSA_TRACE2_5("videoBrowserSetWindow: entering with 0x%x %d %d %d %d ",
- pContext, x, y, dx, dy);
-
- /*--- Sanity checks ---*/
- CHECK_PTR(videoBrowserSetWindow, pContext, err, M4ERR_PARAMETER);
- CHECK_PTR(videoBrowserSetWindow, pPixelArray, err, M4ERR_PARAMETER);
- CHECK_STATE(videoBrowserSetWindow, VideoBrowser_kVBOpened, pC);
-
- pC->m_outputPlane[0].u_topleft = 0;
-
- pC->m_outputPlane[0].u_height = dy;
- pC->m_outputPlane[0].u_width = dx;
- pC->m_x = x;
- pC->m_y = y;
-
- if (pC->m_frameColorType == VideoBrowser_kGB565) {
- pC->m_outputPlane[0].u_stride = pC->m_outputPlane[0].u_width << 1;
- pC->m_outputPlane[0].pac_data = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(
- pC->m_outputPlane[0].u_stride * pC->m_outputPlane[0].u_height,
- VIDEOBROWSER, (M4OSA_Char *)"output plane");
-
- CHECK_PTR(videoBrowserSetWindow,
- pC->m_outputPlane[0].pac_data, err, M4ERR_ALLOC);
- }
- else if (pC->m_frameColorType == VideoBrowser_kYUV420) {
- pC->m_outputPlane[0].u_stride = pC->m_outputPlane[0].u_width;
- pC->m_outputPlane[1].u_height = pC->m_outputPlane[0].u_height >> 1;
- pC->m_outputPlane[1].u_width = pC->m_outputPlane[0].u_width >> 1;
- pC->m_outputPlane[1].u_topleft = 0;
- pC->m_outputPlane[1].u_stride = pC->m_outputPlane[1].u_width;
-
- pC->m_outputPlane[2].u_height = pC->m_outputPlane[0].u_height >> 1;
- pC->m_outputPlane[2].u_width = pC->m_outputPlane[0].u_width >> 1;
- pC->m_outputPlane[2].u_topleft = 0;
- pC->m_outputPlane[2].u_stride = pC->m_outputPlane[2].u_width;
-
- pC->m_outputPlane[0].pac_data = (M4OSA_UInt8*)pPixelArray;
-
- CHECK_PTR(videoBrowserSetWindow,
- pC->m_outputPlane[0].pac_data, err, M4ERR_ALLOC);
-
- pC->m_outputPlane[1].pac_data =
- pC->m_outputPlane[0].pac_data +
- (pC->m_outputPlane[0].u_stride * pC->m_outputPlane[0].u_height);
-
- pC->m_outputPlane[2].pac_data =
- pC->m_outputPlane[1].pac_data +
- (pC->m_outputPlane[1].u_stride * pC->m_outputPlane[1].u_height);
- }
-
-
- M4OSA_TRACE2_0("videoBrowserSetWindow returned NO ERROR");
- return M4NO_ERROR;
-
-videoBrowserSetWindow_cleanUp:
-
- M4OSA_TRACE2_1("videoBrowserSetWindow returned 0x%x", err);
- return err;
-}
-
-/******************************************************************************
-* @brief This function allocates the resources needed for browsing a video file
-* @param ppContext (OUT): Pointer on a context filled by this function.
-* @param pURL (IN) : Path of File to browse
-* @param DrawMode (IN) : Indicate which method is used to draw (Direct draw etc...)
-* @param pfCallback (IN) : Callback function to be called when a frame must be displayed
-* @param pCallbackData (IN) : User defined data that will be passed as parameter of the callback
-* @param clrType (IN) : Required color type.
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
-******************************************************************************/
-M4OSA_ERR videoBrowserCreate(
- M4OSA_Context* ppContext,
- M4OSA_Char* pURL,
- M4OSA_UInt32 DrawMode,
- M4OSA_FileReadPointer* ptrF,
- videoBrowser_Callback pfCallback,
- M4OSA_Void* pCallbackData,
- VideoBrowser_VideoColorType clrType)
-{
- VideoBrowserContext* pContext = M4OSA_NULL;
- M4READER_MediaFamily mediaFamily = M4READER_kMediaFamilyUnknown;
- M4_StreamHandler* pStreamHandler = M4OSA_NULL;
- M4_VideoStreamHandler* pVideoStreamHandler = M4OSA_NULL;
- M4DECODER_VideoType decoderType;
- M4DECODER_OutputFilter FilterOption;
-
- M4OSA_Bool deb = M4OSA_TRUE;
- M4OSA_ERR err = M4NO_ERROR;
-
- M4OSA_TRACE1_2(
- "videoBrowserCreate: entering with 0x%x 0x%x", ppContext, pURL);
-
- /*--- Sanity checks ---*/
- CHECK_PTR(videoBrowserCreate, ppContext, err, M4ERR_PARAMETER);
- *ppContext = M4OSA_NULL ;
- CHECK_PTR(videoBrowserCreate, pURL, err, M4ERR_PARAMETER);
-
- /*--- Create context ---*/
- pContext = (VideoBrowserContext*)M4OSA_32bitAlignedMalloc(
- sizeof(VideoBrowserContext),
- VIDEOBROWSER, (M4OSA_Char*)"Video browser context");
-
- CHECK_PTR(videoBrowserCreate, pContext,err, M4ERR_ALLOC);
- memset((void *)pContext, 0,sizeof(VideoBrowserContext));
-
- /*--- Initialize the context parameters ---*/
- pContext->m_state = VideoBrowser_kVBCreating ;
- pContext->m_frameColorType = clrType;
-
- /*--- Copy the file reader functions ---*/
- memcpy((void *)&pContext->m_fileReadPtr,
- (void *)ptrF,
- sizeof(M4OSA_FileReadPointer)) ;
-
- /* PR#SP00013 DGR bug 13 : first frame is not visible */
- pContext->m_drawmode = DrawMode;
-
-
- /* Retrieve the 3gp reader interface */
- VideoEditor3gpReader_getInterface(&pContext->m_mediaType,
- &pContext->m_3gpReader, &pContext->m_3gpData);
-
- CHECK_PTR(videoBrowserCreate, pContext->m_3gpReader, err, M4ERR_ALLOC);
- CHECK_PTR(videoBrowserCreate, pContext->m_3gpData, err, M4ERR_ALLOC);
-
- /*--- Create the file reader ---*/
- err = pContext->m_3gpReader->m_pFctCreate(&pContext->m_pReaderCtx);
- CHECK_ERR(videoBrowserCreate, err);
- CHECK_PTR(videoBrowserCreate, pContext->m_pReaderCtx, err, M4ERR_ALLOC);
- pContext->m_3gpData->m_readerContext = pContext->m_pReaderCtx;
-
- /*--- Set the OSAL file reader functions ---*/
- err = pContext->m_3gpReader->m_pFctSetOption(
- pContext->m_pReaderCtx,
- M4READER_kOptionID_SetOsaFileReaderFctsPtr,
- (M4OSA_DataOption)(&pContext->m_fileReadPtr));
-
- CHECK_ERR(videoBrowserCreate, err) ;
-
- /*--- Open the file ---*/
- err = pContext->m_3gpReader->m_pFctOpen(pContext->m_pReaderCtx, pURL);
- CHECK_ERR(videoBrowserCreate, err) ;
-
- /*--- Try to find a video stream ---*/
- while (err == M4NO_ERROR)
- {
- err = pContext->m_3gpReader->m_pFctGetNextStream(
- pContext->m_pReaderCtx, &mediaFamily, &pStreamHandler);
-
- /*in case we found a bifs stream or something else...*/
- if ((err == (M4OSA_UInt32)M4ERR_READER_UNKNOWN_STREAM_TYPE) ||
- (err == (M4OSA_UInt32)M4WAR_TOO_MUCH_STREAMS))
- {
- err = M4NO_ERROR;
- continue;
- }
-
- if (err != M4WAR_NO_MORE_STREAM)
- {
- if (M4READER_kMediaFamilyVideo != mediaFamily)
- {
- err = M4NO_ERROR;
- continue;
- }
-
- pContext->m_pStreamHandler = pStreamHandler;
-
- err = pContext->m_3gpReader->m_pFctReset(
- pContext->m_pReaderCtx, pContext->m_pStreamHandler);
-
- CHECK_ERR(videoBrowserCreate, err);
-
- err = pContext->m_3gpReader->m_pFctFillAuStruct(
- pContext->m_pReaderCtx,
- pContext->m_pStreamHandler,
- &pContext->m_accessUnit);
-
- CHECK_ERR(videoBrowserCreate, err);
-
- pVideoStreamHandler =
- (M4_VideoStreamHandler*)pContext->m_pStreamHandler;
-
- switch (pContext->m_pStreamHandler->m_streamType)
- {
- case M4DA_StreamTypeVideoMpeg4:
- case M4DA_StreamTypeVideoH263:
- {
- pContext->m_pCodecLoaderContext = M4OSA_NULL;
- decoderType = M4DECODER_kVideoTypeMPEG4;
-
-#ifdef USE_SOFTWARE_DECODER
- err = VideoEditorVideoDecoder_getSoftwareInterface_MPEG4(
- &decoderType, &pContext->m_pDecoder);
-#else
- err = VideoEditorVideoDecoder_getInterface_MPEG4(
- &decoderType, (void **)&pContext->m_pDecoder);
-#endif
- CHECK_ERR(videoBrowserCreate, err) ;
-
- err = pContext->m_pDecoder->m_pFctCreate(
- &pContext->m_pDecoderCtx,
- pContext->m_pStreamHandler,
- pContext->m_3gpReader,
- pContext->m_3gpData,
- &pContext->m_accessUnit,
- pContext->m_pCodecLoaderContext) ;
-
- CHECK_ERR(videoBrowserCreate, err) ;
- }
- break;
-
- case M4DA_StreamTypeVideoMpeg4Avc:
- {
- pContext->m_pCodecLoaderContext = M4OSA_NULL;
-
- decoderType = M4DECODER_kVideoTypeAVC;
-
-#ifdef USE_SOFTWARE_DECODER
- err = VideoEditorVideoDecoder_getSoftwareInterface_H264(
- &decoderType, &pContext->m_pDecoder);
-#else
- err = VideoEditorVideoDecoder_getInterface_H264(
- &decoderType, (void **)&pContext->m_pDecoder);
-#endif
- CHECK_ERR(videoBrowserCreate, err) ;
-
- err = pContext->m_pDecoder->m_pFctCreate(
- &pContext->m_pDecoderCtx,
- pContext->m_pStreamHandler,
- pContext->m_3gpReader,
- pContext->m_3gpData,
- &pContext->m_accessUnit,
- pContext->m_pCodecLoaderContext) ;
-
- CHECK_ERR(videoBrowserCreate, err) ;
- }
- break;
-
- default:
- err = M4ERR_VB_MEDIATYPE_NOT_SUPPORTED;
- goto videoBrowserCreate_cleanUp;
- }
- }
- }
-
- if (err == M4WAR_NO_MORE_STREAM)
- {
- err = M4NO_ERROR ;
- }
-
- if (M4OSA_NULL == pContext->m_pStreamHandler)
- {
- err = M4ERR_VB_NO_VIDEO ;
- goto videoBrowserCreate_cleanUp ;
- }
-
- err = pContext->m_pDecoder->m_pFctSetOption(
- pContext->m_pDecoderCtx,
- M4DECODER_kOptionID_DeblockingFilter,
- (M4OSA_DataOption)&deb);
-
- if (err == M4WAR_DEBLOCKING_FILTER_NOT_IMPLEMENTED)
- {
- err = M4NO_ERROR;
- }
- CHECK_ERR(videoBrowserCreate, err);
-
- FilterOption.m_pFilterUserData = M4OSA_NULL;
-
-
- if (pContext->m_frameColorType == VideoBrowser_kGB565) {
- FilterOption.m_pFilterFunction =
- (M4OSA_Void*)M4VIFI_ResizeBilinearYUV420toBGR565;
- }
- else if (pContext->m_frameColorType == VideoBrowser_kYUV420) {
- FilterOption.m_pFilterFunction =
- (M4OSA_Void*)M4VIFI_ResizeBilinearYUV420toYUV420;
- }
- else {
- err = M4ERR_PARAMETER;
- goto videoBrowserCreate_cleanUp;
- }
-
- err = pContext->m_pDecoder->m_pFctSetOption(
- pContext->m_pDecoderCtx,
- M4DECODER_kOptionID_OutputFilter,
- (M4OSA_DataOption)&FilterOption);
-
- CHECK_ERR(videoBrowserCreate, err);
-
- /* store the callback details */
- pContext->m_pfCallback = pfCallback;
- pContext->m_pCallbackUserData = pCallbackData;
- /* store the callback details */
-
- pContext->m_state = VideoBrowser_kVBOpened;
- *ppContext = pContext;
-
- M4OSA_TRACE1_0("videoBrowserCreate returned NO ERROR");
- return M4NO_ERROR;
-
-videoBrowserCreate_cleanUp:
-
- if (M4OSA_NULL != pContext)
- {
- if (M4OSA_NULL != pContext->m_pDecoderCtx)
- {
- pContext->m_pDecoder->m_pFctDestroy(pContext->m_pDecoderCtx);
- pContext->m_pDecoderCtx = M4OSA_NULL;
- }
-
- if (M4OSA_NULL != pContext->m_pReaderCtx)
- {
- pContext->m_3gpReader->m_pFctClose(pContext->m_pReaderCtx);
- pContext->m_3gpReader->m_pFctDestroy(pContext->m_pReaderCtx);
- pContext->m_pReaderCtx = M4OSA_NULL;
- }
- SAFE_FREE(pContext->m_pDecoder);
- SAFE_FREE(pContext->m_3gpReader);
- SAFE_FREE(pContext->m_3gpData);
- SAFE_FREE(pContext);
- }
-
- M4OSA_TRACE2_1("videoBrowserCreate returned 0x%x", err);
- return err;
-}
-
-/******************************************************************************
-* M4OSA_ERR videoBrowserCleanUp(M4OSA_Context pContext);
-* @brief This function frees the resources needed for browsing a
-* video file.
-* @param pContext (IN) : Video browser context
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE
-******************************************************************************/
-M4OSA_ERR videoBrowserCleanUp(M4OSA_Context pContext)
-{
- VideoBrowserContext* pC = (VideoBrowserContext*)pContext;
- M4OSA_ERR err = M4NO_ERROR;
-
- M4OSA_TRACE2_1("videoBrowserCleanUp: entering with 0x%x", pContext);
-
- /*--- Sanity checks ---*/
- CHECK_PTR(videoBrowserCleanUp, pContext, err, M4ERR_PARAMETER);
-
- if (M4OSA_NULL != pC->m_pDecoderCtx)
- {
- pC->m_pDecoder->m_pFctDestroy(pC->m_pDecoderCtx);
- pC->m_pDecoderCtx = M4OSA_NULL ;
- }
-
- if (M4OSA_NULL != pC->m_pReaderCtx)
- {
- pC->m_3gpReader->m_pFctClose(pC->m_pReaderCtx) ;
- pC->m_3gpReader->m_pFctDestroy(pC->m_pReaderCtx);
- pC->m_pReaderCtx = M4OSA_NULL;
- }
-
- SAFE_FREE(pC->m_pDecoder);
- SAFE_FREE(pC->m_3gpReader);
- SAFE_FREE(pC->m_3gpData);
-
- if (pC->m_frameColorType != VideoBrowser_kYUV420) {
- SAFE_FREE(pC->m_outputPlane[0].pac_data);
- }
- SAFE_FREE(pC);
-
- M4OSA_TRACE2_0("videoBrowserCleanUp returned NO ERROR");
- return M4NO_ERROR;
-
-videoBrowserCleanUp_cleanUp:
-
- M4OSA_TRACE2_1("videoBrowserCleanUp returned 0x%x", err);
- return err;
-}
-/******************************************************************************
-* M4OSA_ERR videoBrowserPrepareFrame(
-* M4OSA_Context pContext, M4OSA_UInt32* pTime);
-* @brief This function prepares the frame.
-* @param pContext (IN) : Video browser context
-* @param pTime (IN/OUT) : Pointer on the time to reach. Updated
-* by this function with the reached time
-* @param tolerance (IN) : We may decode an earlier frame within the tolerance.
-* The time difference is specified in milliseconds.
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
-******************************************************************************/
-M4OSA_ERR videoBrowserPrepareFrame(M4OSA_Context pContext, M4OSA_UInt32* pTime,
- M4OSA_UInt32 tolerance)
-{
- VideoBrowserContext* pC = (VideoBrowserContext*)pContext;
- M4OSA_ERR err = M4NO_ERROR;
- M4OSA_UInt32 targetTime = 0;
- M4_MediaTime timeMS = 0;
- M4OSA_Bool bJumpNeeded = M4OSA_FALSE;
-
- /*--- Sanity checks ---*/
- CHECK_PTR(videoBrowserPrepareFrame, pContext, err, M4ERR_PARAMETER);
- CHECK_PTR(videoBrowserPrepareFrame, pTime, err, M4ERR_PARAMETER);
-
- targetTime = *pTime ;
-
- /*--- Check the state, if this is the first call to this function
- we move to the state "browsing" ---*/
- if (VideoBrowser_kVBOpened == pC->m_state)
- {
- pC->m_state = VideoBrowser_kVBBrowsing;
- }
- else if (VideoBrowser_kVBBrowsing != pC->m_state)
- {
- err = M4ERR_STATE ;
- goto videoBrowserPrepareFrame_cleanUp;
- }
-
- // If we jump backward or forward to a time greater than current position by
- // 85ms (~ 2 frames), we want to jump.
- if (pC->m_currentCTS == 0 ||
- targetTime < pC->m_currentCTS ||
- targetTime > (pC->m_currentCTS + 85))
- {
- bJumpNeeded = M4OSA_TRUE;
- }
-
- timeMS = (M4_MediaTime)targetTime;
- err = pC->m_pDecoder->m_pFctDecode(
- pC->m_pDecoderCtx, &timeMS, bJumpNeeded, tolerance);
-
- if ((err != M4NO_ERROR) && (err != M4WAR_NO_MORE_AU))
- {
- return err;
- }
-
- err = pC->m_pDecoder->m_pFctRender(
- pC->m_pDecoderCtx, &timeMS, pC->m_outputPlane, M4OSA_TRUE);
-
- if (M4WAR_VIDEORENDERER_NO_NEW_FRAME == err)
- {
- return err;
- }
- CHECK_ERR(videoBrowserPrepareFrame, err) ;
-
- pC->m_currentCTS = (M4OSA_UInt32)timeMS;
-
- *pTime = pC->m_currentCTS;
-
- return M4NO_ERROR;
-
-videoBrowserPrepareFrame_cleanUp:
-
- if ((M4WAR_INVALID_TIME == err) || (M4WAR_NO_MORE_AU == err))
- {
- err = M4NO_ERROR;
- }
- else if (M4OSA_NULL != pC)
- {
- pC->m_currentCTS = 0;
- }
-
- M4OSA_TRACE2_1("videoBrowserPrepareFrame returned 0x%x", err);
- return err;
-}
-
-/******************************************************************************
-* M4OSA_ERR videoBrowserDisplayCurrentFrame(M4OSA_Context pContext);
-* @brief This function displays the current frame.
-* @param pContext (IN) : Video browser context
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
-******************************************************************************/
-M4OSA_ERR videoBrowserDisplayCurrentFrame(M4OSA_Context pContext)
-{
- VideoBrowserContext* pC = (VideoBrowserContext*)pContext ;
- M4OSA_ERR err = M4NO_ERROR ;
-
- /*--- Sanity checks ---*/
- CHECK_PTR(videoBrowserDisplayCurrentFrame, pContext, err, M4ERR_PARAMETER);
-
- // Request display of the frame
- pC->m_pfCallback((M4OSA_Context) pC, // VB context
- VIDEOBROWSER_DISPLAY_FRAME, // action requested
- M4NO_ERROR, // error code
- (M4OSA_Void*) &(pC->m_outputPlane[0]), // image to be displayed
- (M4OSA_Void*) pC->m_pCallbackUserData); // user-provided data
-
-#ifdef DUMPTOFILE
- {
- M4OSA_Context fileContext;
- M4OSA_Char* fileName = "/sdcard/textBuffer_RGB565.rgb";
- M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,
- M4OSA_kFileWrite | M4OSA_kFileCreate);
-
- M4OSA_fileWriteData(fileContext,
- (M4OSA_MemAddr8) pC->m_outputPlane[0].pac_data,
- pC->m_outputPlane[0].u_height*pC->m_outputPlane[0].u_width*2);
-
- M4OSA_fileWriteClose(fileContext);
- }
-#endif
-
- M4OSA_TRACE2_0("videoBrowserDisplayCurrentFrame returned NO ERROR") ;
- return M4NO_ERROR;
-
-videoBrowserDisplayCurrentFrame_cleanUp:
-
- M4OSA_TRACE2_1("videoBrowserDisplayCurrentFrame returned 0x%x", err) ;
- return err;
-}
diff --git a/media/jni/mediaeditor/VideoBrowserMain.h b/media/jni/mediaeditor/VideoBrowserMain.h
deleted file mode 100644
index 00b5e05..0000000
--- a/media/jni/mediaeditor/VideoBrowserMain.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef VIDEO_BROWSER_MAIN_H
-#define VIDEO_BROWSER_MAIN_H
-
-/**
- ************************************************************************
- * @file VideoBrowserMain.h
- * @brief Video browser Interface functions
- ************************************************************************
-*/
-
-#define VIDEOBROWSER 0x423
-
-#include "M4OSA_Memory.h"
-#include "M4OSA_CharStar.h"
-#include "M4OSA_OptionID.h"
-#include "M4OSA_Debug.h"
-#include "M4VIFI_FiltersAPI.h"
-#include "M4OSA_FileReader.h"
-
-
-/**
- ************************************************************************
- * @brief Error codes definition.
- * @note These value are the Browser engine specific error codes.
- ************************************************************************
-*/
-#define M4ERR_VB_MEDIATYPE_NOT_SUPPORTED M4OSA_ERR_CREATE(M4_ERR, VIDEOBROWSER, 0x01)
-#define M4ERR_VB_NO_VIDEO M4OSA_ERR_CREATE(M4_ERR, VIDEOBROWSER, 0x02)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Video Browser draw mode, extension for angle based bliting can be done
- */
-typedef enum
-{
- VideoBrowser_kVBNormalBliting
-} VideoBrowser_videoBrowerDrawMode;
-
-
-/*--- Video Browser output frame color type ---*/
-typedef enum
-{
- VideoBrowser_kYUV420,
- VideoBrowser_kGB565
-} VideoBrowser_VideoColorType;
-
-/**
- ************************************************************************
- * enumeration VideoBrowser_Notification
- * @brief Video Browser notification type.
- * @note This callback mechanism must be used to wait the completion of an asynchronous
- * operation, before calling another API function.
- ************************************************************************
-*/
-typedef enum
-{
- /**
- * A frame is ready to be displayed, it should be displayed in the callback function
- * pCbData type = M4VIFI_ImagePlane*
- */
- VIDEOBROWSER_DISPLAY_FRAME = 0x00000001,
- VIDEOBROWSER_NOTIFICATION_NONE = 0xffffffff
-}VideoBrowser_Notification;
-
-
-/**
- ************************************************************************
- * @brief videoBrowser_Callback type definition
- * @param pInstance (IN) Video Browser context.
- * @param notificationID (IN) Id of the callback which generated the error
- * @param errCode (IN) Error code from the core
- * @param pCbData (IN) pointer to data associated wit the callback.
- * @param pCbUserData (IN) pointer to application user data passed in init.
- * @note This callback mechanism is used to request display of an image
- ************************************************************************
-*/
-typedef M4OSA_Void (*videoBrowser_Callback) (M4OSA_Context pInstance,
- VideoBrowser_Notification notificationID,
- M4OSA_ERR errCode,
- M4OSA_Void* pCbData,
- M4OSA_Void* pCallbackUserData);
-
-
-/******************************************************************************
-* @brief This function allocates the resources needed for browsing a video file.
-* @param ppContext (OUT): Pointer on a context filled by this function.
-* @param pURL (IN) : Path of File to browse
-* @param DrawMode (IN) : Indicate which method is used to draw (Direct draw etc...)
-* @param pfCallback (IN) : Callback function to be called when a frame must be displayed
-* @param pCallbackData (IN) : User defined data that will be passed as parameter of the callback
-* @param clrType (IN) : Required color type.
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
-******************************************************************************/
-M4OSA_ERR videoBrowserCreate(M4OSA_Context* ppContext, M4OSA_Char* pURL,
- M4OSA_UInt32 DrawMode,
- M4OSA_FileReadPointer* ptrF,
- videoBrowser_Callback pfCallback,
- M4OSA_Void* pCallbackData,
- VideoBrowser_VideoColorType clrType);
-
-/******************************************************************************
-* @brief This function frees the resources needed for browsing a video file.
-* @param pContext (IN) : Video browser context
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE
-******************************************************************************/
-M4OSA_ERR videoBrowserCleanUp(M4OSA_Context pContext) ;
-
-
-/******************************************************************************
-* @brief This function allocates the resources needed for browsing a video file.
-* @param pContext (IN) : Video browser context
-* @param pTime (IN/OUT) : Pointer on the time to reach. Updated by
-* this function with the reached time
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
-******************************************************************************/
-M4OSA_ERR videoBrowserPrepareFrame(M4OSA_Context pContext, M4OSA_UInt32* pTime,
- M4OSA_UInt32 tolerance);
-
-/******************************************************************************
-* @brief This function sets the size and the position of the display.
-* @param pContext (IN) : Video Browser context
-* @param pixelArray (IN) : Array to hold the video frame.
-* @param x (IN) : Horizontal position of the top left corner
-* @param y (IN) : Vertical position of the top left corner
-* @param dx (IN) : Width of the display window
-* @param dy (IN) : Height of the video window
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
-******************************************************************************/
-M4OSA_ERR videoBrowserSetWindow(M4OSA_Context pContext, M4OSA_Int32* pixelArray,
- M4OSA_UInt32 x, M4OSA_UInt32 y,
- M4OSA_UInt32 dx, M4OSA_UInt32 dy);
-
-/******************************************************************************
-* @brief This function displays the current frame.
-* @param pContext (IN) : Video browser context
-* @return M4NO_ERROR / M4ERR_PARAMETER / M4ERR_STATE / M4ERR_ALLOC
-******************************************************************************/
-M4OSA_ERR videoBrowserDisplayCurrentFrame(M4OSA_Context pContext);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* VIDEO_BROWSER_MAIN_H */
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
deleted file mode 100644
index d29fad3..0000000
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ /dev/null
@@ -1,3146 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VideoEditorClasses"
-
-#include <VideoEditorClasses.h>
-#include <VideoEditorJava.h>
-#include <VideoEditorLogging.h>
-#include <VideoEditorOsal.h>
-
-extern "C" {
-#include <M4OSA_Clock.h>
-#include <M4OSA_CharStar.h>
-#include <M4OSA_FileCommon.h>
-#include <M4OSA_FileReader.h>
-#include <M4OSA_FileWriter.h>
-#include <M4OSA_Memory.h>
-#include <M4OSA_Debug.h>
-#include <M4OSA_Thread.h>
-#include <M4VSS3GPP_API.h>
-#include <M4xVSS_API.h>
-#include <M4VSS3GPP_ErrorCodes.h>
-#include <M4MCS_ErrorCodes.h>
-#include <M4READER_Common.h>
-#include <M4WRITER_common.h>
-#include <M4DECODER_Common.h>
-};
-
-#define VIDEOEDIT_PROP_JAVA_RESULT_STRING_MAX (128)
-
-#define VIDEOEDIT_JAVA__RESULT_STRING_MAX (128)
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(AudioEffect)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("NONE", M4VSS3GPP_kAudioEffectType_None),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_IN", M4VSS3GPP_kAudioEffectType_FadeIn),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_OUT", M4VSS3GPP_kAudioEffectType_FadeOut)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(AudioEffect, AUDIO_EFFECT_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(AudioFormat)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("NO_AUDIO", M4VIDEOEDITING_kNoneAudio),
- VIDEOEDIT_JAVA_CONSTANT_INIT("AMR_NB", M4VIDEOEDITING_kAMR_NB),
- VIDEOEDIT_JAVA_CONSTANT_INIT("AAC", M4VIDEOEDITING_kAAC),
- VIDEOEDIT_JAVA_CONSTANT_INIT("AAC_PLUS", M4VIDEOEDITING_kAACplus),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ENHANCED_AAC_PLUS", M4VIDEOEDITING_keAACplus),
- VIDEOEDIT_JAVA_CONSTANT_INIT("MP3", M4VIDEOEDITING_kMP3),
- VIDEOEDIT_JAVA_CONSTANT_INIT("EVRC", M4VIDEOEDITING_kEVRC),
- VIDEOEDIT_JAVA_CONSTANT_INIT("PCM", M4VIDEOEDITING_kPCM),
- VIDEOEDIT_JAVA_CONSTANT_INIT("NULL_AUDIO", M4VIDEOEDITING_kNullAudio),
- VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED_AUDIO", M4VIDEOEDITING_kUnsupportedAudio)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(AudioFormat, AUDIO_FORMAT_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(AudioSamplingFrequency)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_DEFAULT", M4VIDEOEDITING_kDefault_ASF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_8000", M4VIDEOEDITING_k8000_ASF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_16000", M4VIDEOEDITING_k16000_ASF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_22050", M4VIDEOEDITING_k22050_ASF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_24000", M4VIDEOEDITING_k24000_ASF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_32000", M4VIDEOEDITING_k32000_ASF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_44100", M4VIDEOEDITING_k44100_ASF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FREQ_48000", M4VIDEOEDITING_k48000_ASF)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(AudioSamplingFrequency,AUDIO_SAMPLING_FREQUENCY_CLASS_NAME,
- M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(AudioTransition)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("NONE", M4VSS3GPP_kAudioTransitionType_None),
- VIDEOEDIT_JAVA_CONSTANT_INIT("CROSS_FADE", M4VSS3GPP_kAudioTransitionType_CrossFade)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(AudioTransition, AUDIO_TRANSITION_CLASS_NAME, M4OSA_NULL,
- M4OSA_NULL)
-
-
-static const char*
-videoEditClasses_getUnknownBitrateString(int bitrate)
-{
- static char string[VIDEOEDIT_JAVA__RESULT_STRING_MAX] = "";
-
- M4OSA_chrSPrintf((M4OSA_Char *)string, sizeof(string) - 1, (M4OSA_Char*)"%d", bitrate);
-
- // Return the bitrate string.
- return(string);
-}
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(Bitrate)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("VARIABLE", M4VIDEOEDITING_kVARIABLE_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("UNDEFINED", M4VIDEOEDITING_kUndefinedBitrate),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_9_2_KBPS", M4VIDEOEDITING_k9_2_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_12_2_KBPS", M4VIDEOEDITING_k12_2_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_16_KBPS", M4VIDEOEDITING_k16_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_24_KBPS", M4VIDEOEDITING_k24_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_32_KBPS", M4VIDEOEDITING_k32_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_48_KBPS", M4VIDEOEDITING_k48_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_64_KBPS", M4VIDEOEDITING_k64_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_96_KBPS", M4VIDEOEDITING_k96_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_128_KBPS", M4VIDEOEDITING_k128_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_192_KBPS", M4VIDEOEDITING_k192_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_256_KBPS", M4VIDEOEDITING_k256_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_288_KBPS", M4VIDEOEDITING_k288_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_384_KBPS", M4VIDEOEDITING_k384_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_512_KBPS", M4VIDEOEDITING_k512_KBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_800_KBPS", M4VIDEOEDITING_k800_KBPS),
-/*+ New Encoder bitrates */
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_2_MBPS", M4VIDEOEDITING_k2_MBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_5_MBPS", M4VIDEOEDITING_k5_MBPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BR_8_MBPS", M4VIDEOEDITING_k8_MBPS)
-/*- New Encoder bitrates */
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(Bitrate, BITRATE_CLASS_NAME,
- videoEditClasses_getUnknownBitrateString, videoEditClasses_getUnknownBitrateString)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(ClipType)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("THREE_GPP", M4VIDEOEDITING_kFileType_3GPP),
- VIDEOEDIT_JAVA_CONSTANT_INIT("MP4", M4VIDEOEDITING_kFileType_MP4),
- VIDEOEDIT_JAVA_CONSTANT_INIT("AMR", M4VIDEOEDITING_kFileType_AMR),
- VIDEOEDIT_JAVA_CONSTANT_INIT("MP3", M4VIDEOEDITING_kFileType_MP3),
- VIDEOEDIT_JAVA_CONSTANT_INIT("PCM", M4VIDEOEDITING_kFileType_PCM),
- VIDEOEDIT_JAVA_CONSTANT_INIT("JPG", M4VIDEOEDITING_kFileType_JPG),
- VIDEOEDIT_JAVA_CONSTANT_INIT("PNG", M4VIDEOEDITING_kFileType_PNG),
- VIDEOEDIT_JAVA_CONSTANT_INIT("M4V", M4VIDEOEDITING_kFileType_M4V),
- VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED", M4VIDEOEDITING_kFileType_Unsupported)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(ClipType, FILE_TYPE_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(Engine)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("TASK_LOADING_SETTINGS", TASK_LOADING_SETTINGS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("TASK_ENCODING", TASK_ENCODING)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(Engine, MANUAL_EDIT_ENGINE_CLASS_NAME, M4OSA_NULL,
- M4OSA_NULL)
-
-
-static const char*
-videoEditClasses_getUnknownErrorName(int error)
-{
- static char string[VIDEOEDIT_JAVA__RESULT_STRING_MAX] = "ERR_INTERNAL";
-
- // Format the unknown error string.
- M4OSA_chrSPrintf((M4OSA_Char *)string, sizeof(string) - 1, (M4OSA_Char*)"ERR_INTERNAL(%s)",
- videoEditOsal_getResultString(error));
-
- // Return the error string.
- return(string);
-}
-
-static const char*
-videoEditClasses_getUnknownErrorString(int error)
-{
- // Return the result string.
- return(videoEditOsal_getResultString(error));
-}
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(Error)
-{
- // M4OSA_Clock.h
- VIDEOEDIT_JAVA_CONSTANT_INIT("WAR_TIMESCALE_TOO_BIG", \
- M4WAR_TIMESCALE_TOO_BIG ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_CLOCK_BAD_REF_YEAR", \
- M4ERR_CLOCK_BAD_REF_YEAR ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_FILE_NOT_FOUND", \
- M4ERR_FILE_NOT_FOUND ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("WAR_TRANSCODING_NECESSARY", \
- M4VSS3GPP_WAR_TRANSCODING_NECESSARY ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("WAR_MAX_OUTPUT_SIZE_EXCEEDED", \
- M4VSS3GPP_WAR_OUTPUTFILESIZE_EXCEED ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_BUFFER_OUT_TOO_SMALL", \
- M4xVSSWAR_BUFFER_OUT_TOO_SMALL ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_NOMORE_SPACE_FOR_FILE", \
- M4xVSSERR_NO_MORE_SPACE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_FILE_TYPE", \
- M4VSS3GPP_ERR_INVALID_FILE_TYPE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_EFFECT_KIND", \
- M4VSS3GPP_ERR_INVALID_EFFECT_KIND ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_VIDEO_EFFECT_TYPE", \
- M4VSS3GPP_ERR_INVALID_VIDEO_EFFECT_TYPE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_AUDIO_EFFECT_TYPE", \
- M4VSS3GPP_ERR_INVALID_AUDIO_EFFECT_TYPE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_VIDEO_TRANSITION_TYPE", \
- M4VSS3GPP_ERR_INVALID_VIDEO_TRANSITION_TYPE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_AUDIO_TRANSITION_TYPE", \
- M4VSS3GPP_ERR_INVALID_AUDIO_TRANSITION_TYPE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_VIDEO_ENCODING_FRAME_RATE", \
- M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EXTERNAL_EFFECT_NULL", \
- M4VSS3GPP_ERR_EXTERNAL_EFFECT_NULL ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EXTERNAL_TRANSITION_NULL", \
- M4VSS3GPP_ERR_EXTERNAL_TRANSITION_NULL ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_BEGIN_CUT_LARGER_THAN_DURATION", \
- M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_DURATION ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_BEGIN_CUT_LARGER_THAN_END_CUT", \
- M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_END_CUT ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_OVERLAPPING_TRANSITIONS", \
- M4VSS3GPP_ERR_OVERLAPPING_TRANSITIONS ),
-#ifdef M4VSS3GPP_ERR_ANALYSIS_DATA_SIZE_TOO_SMALL
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ANALYSIS_DATA_SIZE_TOO_SMALL", \
- M4VSS3GPP_ERR_ANALYSIS_DATA_SIZE_TOO_SMALL ),
-#endif
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_3GPP_FILE", \
- M4VSS3GPP_ERR_INVALID_3GPP_FILE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT", \
- M4VSS3GPP_ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT", \
- M4VSS3GPP_ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_AMR_EDITING_UNSUPPORTED", \
- M4VSS3GPP_ERR_AMR_EDITING_UNSUPPORTED ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INPUT_VIDEO_AU_TOO_LARGE", \
- M4VSS3GPP_ERR_INPUT_VIDEO_AU_TOO_LARGE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INPUT_AUDIO_AU_TOO_LARGE", \
- M4VSS3GPP_ERR_INPUT_AUDIO_AU_TOO_LARGE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INPUT_AUDIO_CORRUPTED_AU", \
- M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU ),
-#ifdef M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AMR_AU
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INPUT_AUDIO_CORRUPTED_AU", \
- M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AMR_AU ),
-#endif
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ENCODER_ACCES_UNIT_ERROR", \
- M4VSS3GPP_ERR_ENCODER_ACCES_UNIT_ERROR ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT", \
- M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_H263_PROFILE", \
- M4VSS3GPP_ERR_EDITING_UNSUPPORTED_H263_PROFILE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE", \
- M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_MPEG4_RVLC", \
- M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_RVLC ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT", \
- M4VSS3GPP_ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE", \
- M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE",\
- M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_CLIP_ANALYSIS_VERSION", \
- M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_VERSION ),
-#ifdef M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_PLATFORM
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INVALID_CLIP_ANALYSIS_PLATFORM", \
- M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_PLATFORM ),
-#endif
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INCOMPATIBLE_VIDEO_FORMAT", \
- M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FORMAT ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE", \
- M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INCOMPATIBLE_VIDEO_TIME_SCALE", \
- M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_TIME_SCALE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING", \
- M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNSUPPORTED_MP3_ASSEMBLY", \
- M4VSS3GPP_ERR_UNSUPPORTED_MP3_ASSEMBLY ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_NO_SUPPORTED_STREAM_IN_FILE", \
- M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ADDVOLUME_EQUALS_ZERO", \
- M4VSS3GPP_ERR_ADDVOLUME_EQUALS_ZERO ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION", \
- M4VSS3GPP_ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT", \
- M4VSS3GPP_ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_UNSUPPORTED_ADDED_AUDIO_STREAM", \
- M4VSS3GPP_ERR_UNSUPPORTED_ADDED_AUDIO_STREAM ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_AUDIO_MIXING_UNSUPPORTED", \
- M4VSS3GPP_ERR_AUDIO_MIXING_UNSUPPORTED ),
-#ifdef M4VSS3GPP_ERR_AUDIO_MIXING_MP3_UNSUPPORTED
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_AUDIO_MIXING_MP3_UNSUPPORTED", \
- M4VSS3GPP_ERR_AUDIO_MIXING_MP3_UNSUPPORTED ),
-#endif
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK", \
- M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK ),
-#ifdef M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AAC
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_FEATURE_UNSUPPORTED_WITH_AAC", \
- M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AAC ),
-#endif
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_AUDIO_CANNOT_BE_MIXED", \
- M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED ),
-#ifdef M4VSS3GPP_ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED", \
- M4VSS3GPP_ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED ),
-#endif
-#ifdef M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_EVRC
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_FEATURE_UNSUPPORTED_WITH_EVRC", \
- M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_EVRC ),
-#endif
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_H263_PROFILE_NOT_SUPPORTED", \
- M4VSS3GPP_ERR_H263_PROFILE_NOT_SUPPORTED ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE", \
- M4VSS3GPP_ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE ),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ERR_INTERNAL", \
- M4NO_ERROR ),
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(Error, ERROR_CLASS_NAME,
- videoEditClasses_getUnknownErrorName, videoEditClasses_getUnknownErrorString)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(FileType)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("THREE_GPP", VideoEditClasses_kFileType_3GPP),
- VIDEOEDIT_JAVA_CONSTANT_INIT("MP4", VideoEditClasses_kFileType_MP4),
- VIDEOEDIT_JAVA_CONSTANT_INIT("AMR", VideoEditClasses_kFileType_AMR),
- VIDEOEDIT_JAVA_CONSTANT_INIT("MP3", VideoEditClasses_kFileType_MP3),
- VIDEOEDIT_JAVA_CONSTANT_INIT("PCM", VideoEditClasses_kFileType_PCM),
- VIDEOEDIT_JAVA_CONSTANT_INIT("JPG", VideoEditClasses_kFileType_JPG),
- VIDEOEDIT_JAVA_CONSTANT_INIT("GIF", VideoEditClasses_kFileType_GIF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("PNG", VideoEditClasses_kFileType_PNG),
- VIDEOEDIT_JAVA_CONSTANT_INIT("M4V", VideoEditClasses_kFileType_M4V),
- VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED", VideoEditClasses_kFileType_Unsupported)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(FileType, FILE_TYPE_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(MediaRendering)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("RESIZING", M4xVSS_kResizing),
- VIDEOEDIT_JAVA_CONSTANT_INIT("CROPPING", M4xVSS_kCropping),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BLACK_BORDERS", M4xVSS_kBlackBorders)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(MediaRendering, MEDIA_RENDERING_CLASS_NAME,
- M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(SlideDirection)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("RIGHT_OUT_LEFT_IN", M4xVSS_SlideTransition_RightOutLeftIn),
- VIDEOEDIT_JAVA_CONSTANT_INIT("LEFT_OUT_RIGTH_IN", M4xVSS_SlideTransition_LeftOutRightIn),
- VIDEOEDIT_JAVA_CONSTANT_INIT("TOP_OUT_BOTTOM_IN", M4xVSS_SlideTransition_TopOutBottomIn),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BOTTOM_OUT_TOP_IN", M4xVSS_SlideTransition_BottomOutTopIn)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(SlideDirection, SLIDE_DIRECTION_CLASS_NAME,
- M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(TransitionBehaviour)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("SPEED_UP", M4VSS3GPP_TransitionBehaviour_SpeedUp),
- VIDEOEDIT_JAVA_CONSTANT_INIT("LINEAR", M4VSS3GPP_TransitionBehaviour_Linear),
- VIDEOEDIT_JAVA_CONSTANT_INIT("SPEED_DOWN", M4VSS3GPP_TransitionBehaviour_SpeedDown),
- VIDEOEDIT_JAVA_CONSTANT_INIT("SLOW_MIDDLE", M4VSS3GPP_TransitionBehaviour_SlowMiddle),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FAST_MIDDLE", M4VSS3GPP_TransitionBehaviour_FastMiddle)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(TransitionBehaviour, TRANSITION_BEHAVIOUR_CLASS_NAME,
- M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoEffect)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("NONE", M4VSS3GPP_kVideoEffectType_None),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_FROM_BLACK", M4VSS3GPP_kVideoEffectType_FadeFromBlack),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_TO_BLACK", M4VSS3GPP_kVideoEffectType_FadeToBlack),
- VIDEOEDIT_JAVA_CONSTANT_INIT("EXTERNAL", M4VSS3GPP_kVideoEffectType_External),
- VIDEOEDIT_JAVA_CONSTANT_INIT("BLACK_AND_WHITE", M4xVSS_kVideoEffectType_BlackAndWhite),
- VIDEOEDIT_JAVA_CONSTANT_INIT("PINK", M4xVSS_kVideoEffectType_Pink),
- VIDEOEDIT_JAVA_CONSTANT_INIT("GREEN", M4xVSS_kVideoEffectType_Green),
- VIDEOEDIT_JAVA_CONSTANT_INIT("SEPIA", M4xVSS_kVideoEffectType_Sepia),
- VIDEOEDIT_JAVA_CONSTANT_INIT("NEGATIVE", M4xVSS_kVideoEffectType_Negative),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FRAMING", M4xVSS_kVideoEffectType_Framing),
- VIDEOEDIT_JAVA_CONSTANT_INIT("TEXT", M4xVSS_kVideoEffectType_Text),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ZOOM_IN", M4xVSS_kVideoEffectType_ZoomIn),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ZOOM_OUT", M4xVSS_kVideoEffectType_ZoomOut),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FIFTIES", M4xVSS_kVideoEffectType_Fifties),
- VIDEOEDIT_JAVA_CONSTANT_INIT("COLORRGB16", M4xVSS_kVideoEffectType_ColorRGB16),
- VIDEOEDIT_JAVA_CONSTANT_INIT("GRADIENT", M4xVSS_kVideoEffectType_Gradient),
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoEffect, VIDEO_EFFECT_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoFormat)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("NO_VIDEO", M4VIDEOEDITING_kNoneVideo),
- VIDEOEDIT_JAVA_CONSTANT_INIT("H263", M4VIDEOEDITING_kH263),
- VIDEOEDIT_JAVA_CONSTANT_INIT("MPEG4", M4VIDEOEDITING_kMPEG4),
- VIDEOEDIT_JAVA_CONSTANT_INIT("H264", M4VIDEOEDITING_kH264),
- VIDEOEDIT_JAVA_CONSTANT_INIT("NULL_VIDEO", M4VIDEOEDITING_kNullVideo),
- VIDEOEDIT_JAVA_CONSTANT_INIT("UNSUPPORTED", M4VIDEOEDITING_kUnsupportedVideo),
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoFormat, VIDEO_FORMAT_CLASS_NAME, M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoFrameRate)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("FR_5_FPS", M4VIDEOEDITING_k5_FPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FR_7_5_FPS", M4VIDEOEDITING_k7_5_FPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FR_10_FPS", M4VIDEOEDITING_k10_FPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FR_12_5_FPS", M4VIDEOEDITING_k12_5_FPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FR_15_FPS", M4VIDEOEDITING_k15_FPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FR_20_FPS", M4VIDEOEDITING_k20_FPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FR_25_FPS", M4VIDEOEDITING_k25_FPS),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FR_30_FPS", M4VIDEOEDITING_k30_FPS)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoFrameRate, VIDEO_FRAME_RATE_CLASS_NAME,
- M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoFrameSize)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("SQCIF", M4VIDEOEDITING_kSQCIF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("QQVGA", M4VIDEOEDITING_kQQVGA),
- VIDEOEDIT_JAVA_CONSTANT_INIT("QCIF", M4VIDEOEDITING_kQCIF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("QVGA", M4VIDEOEDITING_kQVGA),
- VIDEOEDIT_JAVA_CONSTANT_INIT("CIF", M4VIDEOEDITING_kCIF),
- VIDEOEDIT_JAVA_CONSTANT_INIT("VGA", M4VIDEOEDITING_kVGA),
- VIDEOEDIT_JAVA_CONSTANT_INIT("WVGA", M4VIDEOEDITING_kWVGA),
- VIDEOEDIT_JAVA_CONSTANT_INIT("NTSC", M4VIDEOEDITING_kNTSC),
- VIDEOEDIT_JAVA_CONSTANT_INIT("nHD", M4VIDEOEDITING_k640_360),
- VIDEOEDIT_JAVA_CONSTANT_INIT("WVGA16x9", M4VIDEOEDITING_k854_480),
- VIDEOEDIT_JAVA_CONSTANT_INIT("V720p", M4VIDEOEDITING_k1280_720),
- VIDEOEDIT_JAVA_CONSTANT_INIT("W720p", M4VIDEOEDITING_k1080_720),
- VIDEOEDIT_JAVA_CONSTANT_INIT("S720p", M4VIDEOEDITING_k960_720),
- VIDEOEDIT_JAVA_CONSTANT_INIT("V1080p", M4VIDEOEDITING_k1920_1080)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoFrameSize, VIDEO_FRAME_SIZE_CLASS_NAME,
- M4OSA_NULL, M4OSA_NULL)
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoTransition)
-{
- VIDEOEDIT_JAVA_CONSTANT_INIT("NONE", M4VSS3GPP_kVideoTransitionType_None),
- VIDEOEDIT_JAVA_CONSTANT_INIT("CROSS_FADE", M4VSS3GPP_kVideoTransitionType_CrossFade),
- VIDEOEDIT_JAVA_CONSTANT_INIT("EXTERNAL", M4VSS3GPP_kVideoTransitionType_External),
- VIDEOEDIT_JAVA_CONSTANT_INIT("ALPHA_MAGIC", M4xVSS_kVideoTransitionType_AlphaMagic),
- VIDEOEDIT_JAVA_CONSTANT_INIT("SLIDE_TRANSITION", M4xVSS_kVideoTransitionType_SlideTransition),
- VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_BLACK", M4xVSS_kVideoTransitionType_FadeBlack)
-};
-
-VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS(VideoTransition, VIDEO_TRANSITION_CLASS_NAME,
- M4OSA_NULL, M4OSA_NULL)
-
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(AlphaMagic)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("file", "Ljava/lang/String;"),
- VIDEOEDIT_JAVA_FIELD_INIT("blendingPercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("invertRotation", "Z" ),
- VIDEOEDIT_JAVA_FIELD_INIT("rgbWidth", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("rgbHeight", "I" )
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(AlphaMagic, ALPHA_MAGIC_SETTINGS_CLASS_NAME)
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(Properties)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("duration", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("fileType", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("videoFormat", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("videoDuration", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("videoBitrate", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("width", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("height", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("averageFrameRate", "F"),
- VIDEOEDIT_JAVA_FIELD_INIT("profile", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("level", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("profileSupported", "Z"),
- VIDEOEDIT_JAVA_FIELD_INIT("levelSupported", "Z"),
- VIDEOEDIT_JAVA_FIELD_INIT("audioFormat", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("audioDuration", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("audioBitrate", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("audioChannels", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("audioSamplingFrequency", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("videoRotation", "I")
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(Properties, PROPERTIES_CLASS_NAME)
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(BackgroundMusic)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("file", "Ljava/lang/String;"),
- VIDEOEDIT_JAVA_FIELD_INIT("fileType", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("insertionTime", "J" ),
- VIDEOEDIT_JAVA_FIELD_INIT("volumePercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("beginLoop", "J" ),
- VIDEOEDIT_JAVA_FIELD_INIT("endLoop", "J" ),
- VIDEOEDIT_JAVA_FIELD_INIT("enableDucking", "Z" ),
- VIDEOEDIT_JAVA_FIELD_INIT("duckingThreshold","I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("lowVolume", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("isLooping", "Z" )
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(BackgroundMusic, BACKGROUND_MUSIC_SETTINGS_CLASS_NAME)
-
-/*
-VIDEOEDIT_JAVA_DEFINE_FIELDS(BestEditSettings)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("videoFormat", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("videoFrameSize", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("audioFormat", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("audioChannels", "I")
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(BestEditSettings, BEST_EDIT_SETTINGS_CLASS_NAME)
-*/
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(ClipSettings)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("clipPath", "Ljava/lang/String;"),
- VIDEOEDIT_JAVA_FIELD_INIT("fileType", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("beginCutTime", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("endCutTime", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("beginCutPercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("endCutPercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("panZoomEnabled", "Z" ),
- VIDEOEDIT_JAVA_FIELD_INIT("panZoomPercentStart", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftXStart", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftYStart", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("panZoomPercentEnd", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftXEnd", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("panZoomTopLeftYEnd", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("mediaRendering", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("rgbWidth", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("rgbHeight", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("rotationDegree", "I" )
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(ClipSettings, CLIP_SETTINGS_CLASS_NAME)
-
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(EditSettings)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("clipSettingsArray", "[L"CLIP_SETTINGS_CLASS_NAME";" ),
- VIDEOEDIT_JAVA_FIELD_INIT("transitionSettingsArray", "[L"TRANSITION_SETTINGS_CLASS_NAME";" ),
- VIDEOEDIT_JAVA_FIELD_INIT("effectSettingsArray", "[L"EFFECT_SETTINGS_CLASS_NAME";" ),
- VIDEOEDIT_JAVA_FIELD_INIT("videoFrameRate", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("outputFile", "Ljava/lang/String;" ),
- VIDEOEDIT_JAVA_FIELD_INIT("videoFrameSize", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("videoFormat", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("videoProfile", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("videoLevel", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("audioFormat", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("audioSamplingFreq", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("maxFileSize", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("audioChannels", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("videoBitrate", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("audioBitrate", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("backgroundMusicSettings",\
- "L"BACKGROUND_MUSIC_SETTINGS_CLASS_NAME";"),
- VIDEOEDIT_JAVA_FIELD_INIT("primaryTrackVolume", "I" )
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(EditSettings, EDIT_SETTINGS_CLASS_NAME)
-
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(EffectSettings)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("startTime", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("duration", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("videoEffectType", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("audioEffectType", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("startPercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("durationPercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("framingFile", "Ljava/lang/String;"),
- VIDEOEDIT_JAVA_FIELD_INIT("framingBuffer", "[I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("bitmapType", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("width", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("height", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("topLeftX", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("topLeftY", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("framingResize", "Z" ),
- VIDEOEDIT_JAVA_FIELD_INIT("framingScaledSize", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("text", "Ljava/lang/String;"),
- VIDEOEDIT_JAVA_FIELD_INIT("textRenderingData", "Ljava/lang/String;"),
- VIDEOEDIT_JAVA_FIELD_INIT("textBufferWidth", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("textBufferHeight", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("fiftiesFrameRate", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("rgb16InputColor", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingStartPercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingMiddlePercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingEndPercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingFadeInTimePercent", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("alphaBlendingFadeOutTimePercent", "I" )
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(EffectSettings, EFFECT_SETTINGS_CLASS_NAME)
-
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(Engine)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("mManualEditContext", "J")
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(Engine, MANUAL_EDIT_ENGINE_CLASS_NAME)
-
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(SlideTransitionSettings)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("direction", "I")
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(SlideTransitionSettings, SLIDE_TRANSITION_SETTINGS_CLASS_NAME)
-
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(TransitionSettings)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("duration", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("videoTransitionType", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("audioTransitionType", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("transitionBehaviour", "I" ),
- VIDEOEDIT_JAVA_FIELD_INIT("alphaSettings", "L"ALPHA_MAGIC_SETTINGS_CLASS_NAME";" ),
- VIDEOEDIT_JAVA_FIELD_INIT("slideSettings", "L"SLIDE_TRANSITION_SETTINGS_CLASS_NAME";")
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(TransitionSettings, TRANSITION_SETTINGS_CLASS_NAME)
-
-
-VIDEOEDIT_JAVA_DEFINE_FIELDS(Version)
-{
- VIDEOEDIT_JAVA_FIELD_INIT("major", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("minor", "I"),
- VIDEOEDIT_JAVA_FIELD_INIT("revision", "I")
-};
-
-VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(Version, VERSION_CLASS_NAME)
-
-
-VIDEOEDIT_JAVA_DEFINE_METHODS(Engine)
-{
- VIDEOEDIT_JAVA_METHOD_INIT("onProgressUpdate", "(II)V")
-};
-
-VIDEOEDIT_JAVA_DEFINE_METHOD_CLASS(Engine, MANUAL_EDIT_ENGINE_CLASS_NAME)
-
-
-static const char*
-videoEditClasses_getBrandString(M4OSA_UInt32 brand)
-{
- static char brandString[11] = "0x00000000";
- const char* pBrandString = M4OSA_NULL;
- M4OSA_UInt8* pBrand = (M4OSA_UInt8*)&brand;
- M4OSA_UInt32 brandHost = 0;
-
- // Convert the brand from big endian to host.
- brandHost = pBrand[0];
- brandHost = brandHost << 8;
- brandHost += pBrand[1];
- brandHost = brandHost << 8;
- brandHost += pBrand[2];
- brandHost = brandHost << 8;
- brandHost += pBrand[3];
-
- switch (brandHost)
- {
- case M4VIDEOEDITING_BRAND_0000:
- pBrandString = "0000";
- break;
- case M4VIDEOEDITING_BRAND_3G2A:
- pBrandString = "3G2A";
- break;
- case M4VIDEOEDITING_BRAND_3GP4:
- pBrandString = "3GP4";
- break;
- case M4VIDEOEDITING_BRAND_3GP5:
- pBrandString = "3GP5";
- break;
- case M4VIDEOEDITING_BRAND_3GP6:
- pBrandString = "3GP6";
- break;
- case M4VIDEOEDITING_BRAND_AVC1:
- pBrandString = "AVC1";
- break;
- case M4VIDEOEDITING_BRAND_EMP:
- pBrandString = "EMP";
- break;
- case M4VIDEOEDITING_BRAND_ISOM:
- pBrandString = "ISOM";
- break;
- case M4VIDEOEDITING_BRAND_MP41:
- pBrandString = "MP41";
- break;
- case M4VIDEOEDITING_BRAND_MP42:
- pBrandString = "MP42";
- break;
- case M4VIDEOEDITING_BRAND_VFJ1:
- pBrandString = "VFJ1";
- break;
- default:
- M4OSA_chrSPrintf((M4OSA_Char *)brandString,
- sizeof(brandString) - 1,
- (M4OSA_Char*)"0x%08X", brandHost);
- pBrandString = brandString;
- break;
- }
-
- // Return the brand string.
- return(pBrandString);
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-static void
-videoEditClasses_logFtypBox(
- M4VIDEOEDITING_FtypBox* pBox,
- int indentation)
-{
- // Check if memory was allocated for the FtypBox.
- if (M4OSA_NULL != pBox)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c major_brand: %s", indentation, ' ',
- videoEditClasses_getBrandString(pBox->major_brand));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c minor_version: %08X", indentation, ' ',
- (unsigned int)pBox->minor_version);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c nbCompatibleBrands: %u", indentation, ' ',
- (unsigned int)pBox->nbCompatibleBrands);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c compatible_brands:", indentation, ' ');
- indentation += VIDEOEDIT_LOG_INDENTATION;
- for (int i = 0; (i < (int)pBox->nbCompatibleBrands) &&\
- (i < M4VIDEOEDITING_MAX_COMPATIBLE_BRANDS); i++)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c compatible_brand[%d]: %s", indentation, ' ',
- i, videoEditClasses_getBrandString(pBox->compatible_brands[i]));
- }
- indentation -= VIDEOEDIT_LOG_INDENTATION;
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c <null>",
- indentation, ' ');
- }
-}
-#endif
-
-
-void
-videoEditClasses_init(
- bool* pResult,
- JNIEnv* pEnv)
-{
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",\
- "videoEditClasses_init()");
-
- // Initialize the constants.
- videoEditJava_initAudioEffectConstants(pResult, pEnv);
- videoEditJava_initAudioFormatConstants(pResult, pEnv);
- videoEditJava_initAudioSamplingFrequencyConstants(pResult, pEnv);
- videoEditJava_initAudioTransitionConstants(pResult, pEnv);
- videoEditJava_initBitrateConstants(pResult, pEnv);
- videoEditJava_initClipTypeConstants(pResult, pEnv);
- videoEditJava_initEngineConstants(pResult, pEnv);
- videoEditJava_initErrorConstants(pResult, pEnv);
- videoEditJava_initFileTypeConstants(pResult, pEnv);
- videoEditJava_initMediaRenderingConstants(pResult, pEnv);
- videoEditJava_initSlideDirectionConstants(pResult, pEnv);
- videoEditJava_initTransitionBehaviourConstants(pResult, pEnv);
- videoEditJava_initVideoEffectConstants(pResult, pEnv);
- videoEditJava_initVideoFormatConstants(pResult, pEnv);
- videoEditJava_initVideoFrameRateConstants(pResult, pEnv);
- videoEditJava_initVideoFrameSizeConstants(pResult, pEnv);
- videoEditJava_initVideoTransitionConstants(pResult, pEnv);
-
- // Initialize the fields.
- videoEditJava_initAlphaMagicFields(pResult, pEnv);
- videoEditJava_initBackgroundMusicFields(pResult, pEnv);
- videoEditJava_initClipSettingsFields(pResult, pEnv);
- videoEditJava_initEditSettingsFields(pResult, pEnv);
- videoEditJava_initEffectSettingsFields(pResult, pEnv);
- videoEditJava_initEngineFields(pResult, pEnv);
- videoEditJava_initSlideTransitionSettingsFields(pResult, pEnv);
- videoEditJava_initTransitionSettingsFields(pResult, pEnv);
- videoEditJava_initVersionFields(pResult, pEnv);
- // Initialize the methods.
- videoEditJava_initEngineMethods(pResult, pEnv);
- }
-}
-
-void
-videoEditPropClass_init(
- bool* pResult,
- JNIEnv* pEnv)
-{
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",\
- "videoEditPropClass_init()");
-
- // Initialize the constants.
- videoEditJava_initAudioFormatConstants(pResult, pEnv);
- videoEditJava_initErrorConstants(pResult, pEnv);
- videoEditJava_initFileTypeConstants(pResult, pEnv);
- videoEditJava_initVideoFormatConstants(pResult, pEnv);
-
- // Initialize the fields.
- videoEditJava_initPropertiesFields(pResult, pEnv);
- }
-}
-
-void
-videoEditClasses_getAlphaMagicSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4xVSS_AlphaMagicSettings** ppSettings)
-{
- VideoEditJava_AlphaMagicFieldIds fieldIds;
- M4xVSS_AlphaMagicSettings* pSettings = M4OSA_NULL;
- memset(&fieldIds, 0, sizeof(VideoEditJava_AlphaMagicFieldIds));
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_getAlphaMagicSettings()");
-
- // Retrieve the field ids.
- videoEditJava_getAlphaMagicFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only validate the AlphaMagicSettings if the fields could be located.
- if (*pResult)
- {
- // Check if the clip is set.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (NULL == object),
- "alphaSettings is null");
- }
-
- // Only retrieve the AlphaMagicSettings if the fields could be located and validated.
- if (*pResult)
- {
- // Allocate memory for the AlphaMagicSettings.
- pSettings = (M4xVSS_AlphaMagicSettings*)videoEditOsal_alloc(pResult, pEnv,
- sizeof(M4xVSS_AlphaMagicSettings), "AlphaMagicSettings");
-
- // Check if memory could be allocated for the AlphaMagicSettings.
- if (*pResult)
- {
- // Set the alpha magic file path (JPG file).
- pSettings->pAlphaFilePath = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv, object,
- fieldIds.file, M4OSA_NULL);
-
- // Check if the alpha magic file path is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (M4OSA_NULL == pSettings->pAlphaFilePath), "alphaSettings.file is null");
- }
-
- // Check if the alpha file path could be retrieved.
- if (*pResult)
- {
- // Set the blending percentage between 0 and 100.
- pSettings->blendingPercent = (M4OSA_UInt8)pEnv->GetIntField(object,
- fieldIds.blendingPercent);
-
- // Set the direct effect or reverse.
- pSettings->isreverse = (M4OSA_Bool)pEnv->GetBooleanField(object,
- fieldIds.invertRotation);
-
- // Get the rgb width
- pSettings->width = (M4OSA_UInt32) pEnv->GetIntField(object, fieldIds.rgbWidth );
-
- pSettings->height = (M4OSA_UInt32) pEnv->GetIntField(object, fieldIds.rgbHeight );
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "((((((((((path %s", pSettings->pAlphaFilePath);
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "------- getAlphaMagicSettings width %d", pEnv->GetIntField(object,
- fieldIds.rgbWidth ));
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "-------- getAlphaMagicSettings Height %d",
- pEnv->GetIntField(object, fieldIds.rgbHeight ));
- }
-
- // Check if settings could be set.
- if (*pResult)
- {
- // Return the settings.
- (*ppSettings) = pSettings;
- }
- else
- {
- // Free the settings.
- videoEditClasses_freeAlphaMagicSettings(&pSettings);
- }
- }
-}
-
-void
-videoEditClasses_freeAlphaMagicSettings(
- M4xVSS_AlphaMagicSettings** ppSettings)
-{
- // Check if memory was allocated for the AlphaMagicSettings.
- if (M4OSA_NULL != (*ppSettings))
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_freeAlphaMagicSettings()");
-
- // Free the alpha file path.
- videoEditOsal_free((*ppSettings)->pAlphaFilePath);
- (*ppSettings)->pAlphaFilePath = M4OSA_NULL;
-
- // Free the settings structure.
- videoEditOsal_free((*ppSettings));
- (*ppSettings) = M4OSA_NULL;
- }
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logAlphaMagicSettings(
- M4xVSS_AlphaMagicSettings* pSettings,
- int indentation)
-{
- // Check if memory was allocated for the AlphaMagicSettings.
- if (M4OSA_NULL != pSettings)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pAlphaFilePath: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->pAlphaFilePath) ? \
- (char *)pSettings->pAlphaFilePath : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c blendingPercent: %u %%", indentation, ' ',
- (unsigned int)pSettings->blendingPercent);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c isreverse: %s", indentation, ' ',
- pSettings->isreverse ? "true" : "false");
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c <null>", indentation, ' ');
- }
-}
-#endif
-
-
-void
-videoEditClasses_getBackgroundMusicSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4xVSS_BGMSettings** ppSettings)
-{
- VideoEditJava_BackgroundMusicFieldIds fieldIds;
- M4xVSS_BGMSettings* pSettings = M4OSA_NULL;
- bool converted = true;
- memset(&fieldIds, 0, sizeof(VideoEditJava_BackgroundMusicFieldIds));
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_getBackgroundMusicSettings()");
-
- // Retrieve the field ids.
- videoEditJava_getBackgroundMusicFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only retrieve the BackgroundMusicSettings if the fields could be located.
- if (*pResult)
- {
- // Check if the object is valid.
- if (NULL != object)
- {
- // Allocate memory for the BackgroundMusicSettings.
- pSettings = (M4xVSS_BGMSettings*)videoEditOsal_alloc(pResult, pEnv,
- sizeof(M4xVSS_BGMSettings), "BackgroundMusicSettings");
-
- // Check if memory could be allocated for the BackgroundMusicSettings.
- if (*pResult)
- {
- // Set the input file path.
- pSettings->pFile = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv, object,
- fieldIds.file, M4OSA_NULL);
-
- // Check if the input file path is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (M4OSA_NULL == pSettings->pFile), "backgroundMusicSettings.file is null");
- }
-
- // Check if the input file path could be retrieved.
- if (*pResult)
- {
- // Set the file type .3gp, .amr, .mp3.
- pSettings->FileType = M4VIDEOEDITING_kFileType_PCM;
- /*(M4VIDEOEDITING_FileType)videoEditJava_getClipTypeJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.fileType));*/
-
- // Check if the file type is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "backgroundMusicSettings.fileType is invalid");
- }
-
- // Check if the file type could be retrieved.
- if (*pResult)
- {
- // Set the time, in milliseconds, at which the added audio track is inserted.
- pSettings->uiAddCts = (M4OSA_UInt32)pEnv->GetLongField(object,
- fieldIds.insertionTime);
-
- // Set the volume, in percentage (0..100), of the added audio track.
- pSettings->uiAddVolume = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.volumePercent);
-
- // Set the start time of the loop in milli seconds.
- pSettings->uiBeginLoop = (M4OSA_UInt32)pEnv->GetLongField(object,
- fieldIds.beginLoop);
-
- // Set the end time of the loop in milli seconds.
- pSettings->uiEndLoop = (M4OSA_UInt32)pEnv->GetLongField(object,
- fieldIds.endLoop);
- // Set the end time of the loop in milli seconds.
- pSettings->b_DuckingNeedeed =
- (M4OSA_Bool)pEnv->GetBooleanField(object, fieldIds.enableDucking);
-
- // Set the end time of the loop in milli seconds.
- pSettings->InDucking_threshold =
- (M4OSA_Int32)pEnv->GetIntField(object, fieldIds.duckingThreshold);
-
- // Set the end time of the loop in milli seconds.
- pSettings->lowVolume =
- (M4OSA_Float)(((M4OSA_Float)pEnv->GetIntField(object, fieldIds.lowVolume)));
-
- // Set the end time of the loop in milli seconds.
- pSettings->bLoop = (M4OSA_Bool)pEnv->GetBooleanField(object, fieldIds.isLooping);
-
- // Set sampling freq and channels
- pSettings->uiSamplingFrequency = M4VIDEOEDITING_k32000_ASF;
- pSettings->uiNumChannels = 2;
- }
-
- // Check if settings could be set.
- if (*pResult)
- {
- // Return the settings.
- (*ppSettings) = pSettings;
- }
- else
- {
- // Free the settings.
- videoEditClasses_freeBackgroundMusicSettings(&pSettings);
- }
- }
- }
-}
-
-void
-videoEditClasses_freeBackgroundMusicSettings(
- M4xVSS_BGMSettings** ppSettings)
-{
- // Check if memory was allocated for the BackgroundMusicSettings.
- if (M4OSA_NULL != (*ppSettings))
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_freeBackgroundMusicSettings()");
-
- // Free the input file path.
- videoEditOsal_free((*ppSettings)->pFile);
- (*ppSettings)->pFile = M4OSA_NULL;
-
- // Free the settings structure.
- videoEditOsal_free((*ppSettings));
- (*ppSettings) = M4OSA_NULL;
- }
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logBackgroundMusicSettings(
- M4xVSS_BGMSettings* pSettings,
- int indentation)
-{
- // Check if memory was allocated for the BackgroundMusicSettings.
- if (M4OSA_NULL != pSettings)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c pFile: %s",
- indentation, ' ',
- (M4OSA_NULL != pSettings->pFile) ? (char *)pSettings->pFile : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c FileType: %s", indentation, ' ',
- videoEditJava_getClipTypeString(pSettings->FileType));
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c uiAddCts: %u ms",
- indentation, ' ', (unsigned int)pSettings->uiAddCts);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c uiAddVolume: %u %%",
- indentation, ' ', (unsigned int)pSettings->uiAddVolume);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c uiBeginLoop: %u ms",
- indentation, ' ', (unsigned int)pSettings->uiBeginLoop);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c uiEndLoop: %u ms",
- indentation, ' ', (unsigned int)pSettings->uiEndLoop);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c b_DuckingNeedeed:\
- %u ", indentation, ' ', (bool)pSettings->b_DuckingNeedeed);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c InDucking_threshold: \
- %u ms", indentation, ' ', (unsigned int)pSettings->InDucking_threshold);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c lowVolume: %2.2f ",\
- indentation, ' ', (float)pSettings->lowVolume);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c bLoop: %u ms",\
- indentation, ' ', (bool)pSettings->bLoop);
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c <null>",
- indentation, ' ');
- }
-}
-#endif
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logClipProperties(
- M4VIDEOEDITING_ClipProperties* pProperties,
- int indentation)
-{
- // Check if memory was allocated for the ClipProperties.
- if (M4OSA_NULL != pProperties)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bAnalysed: %s", indentation, ' ',
- pProperties->bAnalysed ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c Version: %d.%d.%d", indentation, ' ',
- pProperties->Version[0], pProperties->Version[1], pProperties->Version[2]);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiClipDuration: %u", indentation, ' ',
- (unsigned int)pProperties->uiClipDuration);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c FileType: %s", indentation, ' ',
- videoEditJava_getClipTypeString(pProperties->FileType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c ftyp:",
- indentation, ' ');
- videoEditClasses_logFtypBox(&pProperties->ftyp, indentation + VIDEOEDIT_LOG_INDENTATION);
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c VideoStreamType: %s", indentation, ' ',
- videoEditJava_getVideoFormatString(pProperties->VideoStreamType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiClipVideoDuration: %u", indentation, ' ',
- (unsigned int)pProperties->uiClipVideoDuration);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiVideoBitrate: %s", indentation, ' ',
- videoEditJava_getBitrateString(pProperties->uiVideoBitrate));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiVideoMaxAuSize: %u", indentation, ' ',
- (unsigned int)pProperties->uiVideoMaxAuSize);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiVideoWidth: %u", indentation, ' ',
- (unsigned int)pProperties->uiVideoWidth);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiVideoHeight: %u", indentation, ' ',
- (unsigned int)(unsigned int)pProperties->uiVideoHeight);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiVideoTimeScale: %u", indentation, ' ',
- (unsigned int)pProperties->uiVideoTimeScale);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c fAverageFrameRate: %.3f", indentation, ' ',
- pProperties->fAverageFrameRate);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bMPEG4dataPartition: %s", indentation, ' ',
- pProperties->bMPEG4dataPartition ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bMPEG4rvlc: %s", indentation, ' ',
- pProperties->bMPEG4rvlc ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bMPEG4resynchMarker: %s", indentation, ' ',
- pProperties->bMPEG4resynchMarker ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c AudioStreamType: %s", indentation, ' ',
- videoEditJava_getAudioFormatString(pProperties->AudioStreamType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiClipAudioDuration: %u", indentation, ' ',
- (unsigned int)pProperties->uiClipAudioDuration);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiAudioBitrate: %s", indentation, ' ',
- videoEditJava_getBitrateString(pProperties->uiAudioBitrate));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiAudioMaxAuSize: %u", indentation, ' ',
- (unsigned int)pProperties->uiAudioMaxAuSize);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiNbChannels: %u", indentation, ' ',
- (unsigned int)pProperties->uiNbChannels);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiSamplingFrequency: %u", indentation, ' ',
- (unsigned int)pProperties->uiSamplingFrequency);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiExtendedSamplingFrequency: %u", indentation, ' ',
- (unsigned int)pProperties->uiExtendedSamplingFrequency);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiDecodedPcmSize: %u", indentation, ' ',
- (unsigned int)pProperties->uiDecodedPcmSize);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bVideoIsEditable: %s", indentation, ' ',
- pProperties->bVideoIsEditable ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bAudioIsEditable: %s", indentation, ' ',
- pProperties->bAudioIsEditable ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bVideoIsCompatibleWithMasterClip: %s", indentation, ' ',
- pProperties->bVideoIsCompatibleWithMasterClip ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bAudioIsCompatibleWithMasterClip: %s", indentation, ' ',
- pProperties->bAudioIsCompatibleWithMasterClip ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiClipAudioVolumePercentage: %d", indentation, ' ',
- pProperties->uiClipAudioVolumePercentage);
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES", "%*c <null>",
- indentation, ' ');
- }
-}
-#endif
-
-void
-videoEditClasses_getClipSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_ClipSettings** ppSettings)
-{
-
- VideoEditJava_ClipSettingsFieldIds fieldIds;
- M4VSS3GPP_ClipSettings* pSettings = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
- bool converted = true;
- memset(&fieldIds, 0, sizeof(VideoEditJava_ClipSettingsFieldIds));
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_getClipSettings()");
-
- // Retrieve the field ids.
- videoEditJava_getClipSettingsFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only validate the ClipSettings if the fields could be located.
- if (*pResult)
- {
- // Check if the clip is set.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (NULL == object),
- "clip is null");
- }
-
- // Only retrieve the ClipSettings if the fields could be located and validated.
- if (*pResult)
- {
- // Allocate memory for the ClipSettings.
- pSettings = (M4VSS3GPP_ClipSettings *)videoEditOsal_alloc(pResult, pEnv,
- sizeof(M4VSS3GPP_ClipSettings), "ClipSettings");
-
- // Check if memory could be allocated for the ClipSettings.
- if (*pResult)
- {
- // Log the API call.
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4xVSS_CreateClipSettings()");
-
- // Initialize the ClipSettings.
- result = M4xVSS_CreateClipSettings(pSettings, NULL, 0, 0);
-
- // Log the result.
- VIDEOEDIT_LOG_RESULT(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- videoEditOsal_getResultString(result));
-
- // Check if the initialization succeeded.
- videoEditJava_checkAndThrowRuntimeException(pResult, pEnv,
- (M4NO_ERROR != result), result);
- }
-
- // Check if the allocation and initialization succeeded
- //(required because pSettings is dereferenced).
- if (*pResult)
- {
- // Set the input file path.
- pSettings->pFile = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv, object,
- fieldIds.clipPath, &pSettings->filePathSize);
-
- // Check if the file path is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (M4OSA_NULL == pSettings->pFile), "clip.clipPath is null");
- }
-
- // Check if the input file could be retrieved.
- if (*pResult)
- {
- // Set the file type .3gp, .amr, .mp3.
- pSettings->FileType = (M4VIDEOEDITING_FileType)videoEditJava_getClipTypeJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.fileType));
-
- if (( pSettings->FileType == M4VIDEOEDITING_kFileType_JPG) ||
- ( pSettings->FileType == M4VIDEOEDITING_kFileType_PNG)) {
- pSettings->FileType = M4VIDEOEDITING_kFileType_ARGB8888;
- }
-
- // Check if the file type is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "clip.fileType is invalid");
- }
-
- // Check if the file type could be retrieved.
- if (*pResult)
- {
- // Set the begin cut time, in milliseconds.
- pSettings->uiBeginCutTime =
- (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.beginCutTime);
-
- // Set the end cut time, in milliseconds.
- pSettings->uiEndCutTime = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.endCutTime);
-
- // Set the begin cut time, in percent of clip duration (only for 3GPP clip !).
- pSettings->xVSS.uiBeginCutPercent =
- (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.beginCutPercent);
-
- // Set the end cut time, in percent of clip duration (only for 3GPP clip !).
- pSettings->xVSS.uiEndCutPercent =
- (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.endCutPercent);
-
- // Set the duration of the clip, if different from 0,
- // has priority on uiEndCutTime or uiEndCutPercent.
- pSettings->xVSS.uiDuration = 0;
-
- // Set whether or not the pan and zoom mode is enabled.
- pSettings->xVSS.isPanZoom =
- (M4OSA_Bool)pEnv->GetBooleanField(object, fieldIds.panZoomEnabled);
-
- // Set the pan and zoom start zoom percentage.
- pSettings->xVSS.PanZoomXa =
- (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomPercentStart);
-
- // Set the pan and zoom start x.
- pSettings->xVSS.PanZoomTopleftXa =
- (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomTopLeftXStart);
-
- // Set the pan and zoom start y.
- pSettings->xVSS.PanZoomTopleftYa =
- (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomTopLeftYStart);
-
- // Set the pan and zoom end zoom percentage.
- pSettings->xVSS.PanZoomXb =
- (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomPercentEnd);
-
- // Set the pan and zoom end x.
- pSettings->xVSS.PanZoomTopleftXb =
- (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomTopLeftXEnd);
-
- // Set the pan and zoom end y.
- pSettings->xVSS.PanZoomTopleftYb =
- (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.panZoomTopLeftYEnd);
-
- // Set the media rendering mode, only used with JPEG to crop, resize,
- // or render black borders.
- pSettings->xVSS.MediaRendering =
- (M4xVSS_MediaRendering)videoEditJava_getMediaRenderingJavaToC(
- &converted, pEnv->GetIntField(object,fieldIds.mediaRendering));
-
- // Check if the media rendering is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, !converted,
- "clip.mediaRendering is invalid");
-
- // Capture the rgb file width and height
- pSettings->ClipProperties.uiStillPicWidth =
- (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.rgbFileWidth);
- pSettings->ClipProperties.uiStillPicHeight =
- (M4OSA_UInt16)pEnv->GetIntField(object, fieldIds.rgbFileHeight);
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", \
- "getClipSettings-- rgbFileWidth %d ",
- pSettings->ClipProperties.uiStillPicWidth);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", \
- "getClipSettings-- rgbFileHeight %d ",
- pSettings->ClipProperties.uiStillPicHeight);
-
- // Set the video rotation degree
- pSettings->ClipProperties.videoRotationDegrees =
- (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.rotationDegree);
- }
-
- // Check if settings could be set.
- if (*pResult)
- {
- // Return the settings.
- (*ppSettings) = pSettings;
- }
- else
- {
- // Free the settings.
- videoEditClasses_freeClipSettings(&pSettings);
- }
- }
-}
-
-void
-videoEditClasses_createClipSettings(
- bool* pResult,
- JNIEnv* pEnv,
- M4VSS3GPP_ClipSettings* pSettings,
- jobject* pObject)
-{
- VideoEditJava_ClipSettingsFieldIds fieldIds;
- jclass clazz = NULL;
- jobject object = NULL;
- memset(&fieldIds, 0, sizeof(VideoEditJava_ClipSettingsFieldIds));
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_createClipSettings()");
-
- // Retrieve the class.
- videoEditJava_getClipSettingsClass(pResult, pEnv, &clazz);
-
- // Retrieve the field ids.
- videoEditJava_getClipSettingsFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only create an object if the class and fields could be located.
- if (*pResult)
- {
- // Allocate a new object.
- object = pEnv->AllocObject(clazz);
- if (NULL != object)
- {
- // Set the clipPath field.
- pEnv->SetObjectField(object, fieldIds.clipPath, NULL);
-
- // Set the fileType field.
- pEnv->SetIntField(object, fieldIds.fileType, videoEditJava_getClipTypeCToJava(
- pSettings->FileType));
-
- // Set the beginCutTime field.
- pEnv->SetIntField(object, fieldIds.beginCutTime, pSettings->uiBeginCutTime);
-
- // Set the endCutTime field.
- pEnv->SetIntField(object, fieldIds.endCutTime, pSettings->uiEndCutTime);
-
- // Set the beginCutPercent field.
- pEnv->SetIntField(object, fieldIds.beginCutPercent, pSettings->xVSS.uiBeginCutPercent);
-
- // Set the endCutPercent field.
- pEnv->SetIntField(object, fieldIds.endCutPercent, pSettings->xVSS.uiEndCutPercent);
-
- // Set the panZoomEnabled field.
- pEnv->SetBooleanField(object, fieldIds.panZoomEnabled, pSettings->xVSS.isPanZoom);
-
- // Set the panZoomPercentStart field.
- pEnv->SetIntField(object, fieldIds.panZoomPercentStart,
- (1000 - pSettings->xVSS.PanZoomXa));
-
- // Set the panZoomTopLeftXStart field.
- pEnv->SetIntField(object, fieldIds.panZoomTopLeftXStart,
- pSettings->xVSS.PanZoomTopleftXa);
-
- // Set the panZoomTopLeftYStart field.
- pEnv->SetIntField(object, fieldIds.panZoomTopLeftYStart,
- pSettings->xVSS.PanZoomTopleftYa);
-
- // Set the panZoomPercentEnd field.
- pEnv->SetIntField(object, fieldIds.panZoomPercentEnd,
- (1000 - pSettings->xVSS.PanZoomXb));
-
- // Set the panZoomTopLeftXEnd field.
- pEnv->SetIntField(object, fieldIds.panZoomTopLeftXEnd,
- pSettings->xVSS.PanZoomTopleftXb);
-
- // Set the panZoomTopLeftYEnd field.
- pEnv->SetIntField(object, fieldIds.panZoomTopLeftYEnd,
- pSettings->xVSS.PanZoomTopleftYb);
-
- // Set the mediaRendering field.
- pEnv->SetIntField(object, fieldIds.mediaRendering,
- videoEditJava_getMediaRenderingCToJava(pSettings->xVSS.MediaRendering));
-
- // Set the rgb file width and height
- pEnv->SetIntField(object, fieldIds.rgbFileWidth,
- pSettings->ClipProperties.uiStillPicWidth );
-
- pEnv->SetIntField(object, fieldIds.rgbFileHeight,
- pSettings->ClipProperties.uiStillPicHeight );
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "rgbFileWeight %d rgbFileHeight %d ",
- pSettings->ClipProperties.uiStillPicWidth ,
- pSettings->ClipProperties.uiStillPicHeight);
-
- // Set the video rotation
- pEnv->SetIntField(object, fieldIds.rotationDegree,
- pSettings->ClipProperties.videoRotationDegrees);
-
- // Return the object.
- (*pObject) = object;
- }
- }
-}
-void
-videoEditPropClass_createProperties(
- bool* pResult,
- JNIEnv* pEnv,
- VideoEditPropClass_Properties* pProperties,
- jobject* pObject)
-{
- VideoEditJava_PropertiesFieldIds fieldIds;
- jclass clazz = NULL;
- jobject object = NULL;
- memset(&fieldIds, 0, sizeof(VideoEditJava_PropertiesFieldIds));
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "videoEditPropClass_createProperties()");
-
- // Retrieve the class.
- videoEditJava_getPropertiesClass(pResult, pEnv, &clazz);
-
- // Retrieve the field ids.
- videoEditJava_getPropertiesFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only create an object if the class and fields could be located.
- if (*pResult)
- {
- // Allocate a new object.
- object = pEnv->AllocObject(clazz);
- if (NULL != object)
- {
- // Set the duration field.
- pEnv->SetIntField(object, fieldIds.duration, pProperties->uiClipDuration);
-
- // Set the fileType field.
- pEnv->SetIntField(object, fieldIds.fileType,
- videoEditJava_getFileTypeCToJava(pProperties->FileType));
-
- // Set the videoFormat field.
- pEnv->SetIntField(object, fieldIds.videoFormat,
- videoEditJava_getVideoFormatCToJava(pProperties->VideoStreamType));
-
- // Set the videoDuration field.
- pEnv->SetIntField(object, fieldIds.videoDuration, pProperties->uiClipVideoDuration);
-
- // Set the videoBitrate field.
- pEnv->SetIntField(object, fieldIds.videoBitrate, pProperties->uiVideoBitrate);
-
- // Set the width field.
- pEnv->SetIntField(object, fieldIds.width, pProperties->uiVideoWidth);
-
- // Set the height field.
- pEnv->SetIntField(object, fieldIds.height, pProperties->uiVideoHeight);
-
- // Set the averageFrameRate field.
- pEnv->SetFloatField(object, fieldIds.averageFrameRate, pProperties->fAverageFrameRate);
-
- // Set the profile field.
- pEnv->SetIntField(object, fieldIds.profile,
- pProperties->uiVideoProfile);
-
- // Set the level field.
- pEnv->SetIntField(object, fieldIds.level,
- pProperties->uiVideoLevel);
-
- // Set whether profile supported
- pEnv->SetBooleanField(object, fieldIds.profileSupported,
- pProperties->bProfileSupported);
-
- // Set whether level supported
- pEnv->SetBooleanField(object, fieldIds.levelSupported,
- pProperties->bLevelSupported);
-
- // Set the audioFormat field.
- pEnv->SetIntField(object, fieldIds.audioFormat,
- videoEditJava_getAudioFormatCToJava(pProperties->AudioStreamType));
-
- // Set the audioDuration field.
- pEnv->SetIntField(object, fieldIds.audioDuration, pProperties->uiClipAudioDuration);
-
- // Set the audioBitrate field.
- pEnv->SetIntField(object, fieldIds.audioBitrate, pProperties->uiAudioBitrate);
-
- // Set the audioChannels field.
- pEnv->SetIntField(object, fieldIds.audioChannels, pProperties->uiNbChannels);
-
- // Set the audioSamplingFrequency field.
- pEnv->SetIntField(object, fieldIds.audioSamplingFrequency,
- pProperties->uiSamplingFrequency);
-
- // Set the video rotation field.
- pEnv->SetIntField(object, fieldIds.videoRotation, pProperties->uiRotation);
-
- // Return the object.
- (*pObject) = object;
- }
- }
-}
-
-void
-videoEditClasses_freeClipSettings(
- M4VSS3GPP_ClipSettings** ppSettings)
-{
- // Check if memory was allocated for the ClipSettings.
- if (M4OSA_NULL != (*ppSettings))
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_freeClipSettings()");
-
- // Free the input file path.
- videoEditOsal_free((*ppSettings)->pFile);
- (*ppSettings)->pFile = M4OSA_NULL;
- (*ppSettings)->filePathSize = 0;
-
- // Free the clip settings.
- M4xVSS_FreeClipSettings((*ppSettings));
-
- // Free the settings structure.
- videoEditOsal_free((*ppSettings));
- (*ppSettings) = M4OSA_NULL;
- }
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logClipSettings(
- M4VSS3GPP_ClipSettings* pSettings,
- int indentation)
-{
- // Check if memory was allocated for the ClipSettings.
- if (M4OSA_NULL != pSettings)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pFile: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->pFile) ? (char*)pSettings->pFile : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c FileType: %s", indentation, ' ',
- videoEditJava_getClipTypeString(pSettings->FileType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c filePathSize: %u", indentation, ' ',
- (unsigned int)pSettings->filePathSize);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c ClipProperties:", indentation, ' ');
- videoEditClasses_logClipProperties(&pSettings->ClipProperties,
- indentation + VIDEOEDIT_LOG_INDENTATION);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiBeginCutTime: %u ms", indentation, ' ',
- (unsigned int)pSettings->uiBeginCutTime);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiEndCutTime: %u ms", indentation, ' ',
- (unsigned int)pSettings->uiEndCutTime);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiBeginCutPercent: %u %%", indentation, ' ',
- (unsigned int)pSettings->xVSS.uiBeginCutPercent);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiEndCutPercent: %u %%", indentation, ' ',
- (unsigned int)pSettings->xVSS.uiEndCutPercent);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiDuration: %u ms", indentation, ' ',
- (unsigned int)pSettings->xVSS.uiDuration);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c isPanZoom: %s", indentation, ' ',
- pSettings->xVSS.isPanZoom ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c PanZoomXa: %d ms", indentation, ' ',
- pSettings->xVSS.PanZoomXa);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c PanZoomTopleftXa: %d ms", indentation, ' ',
- pSettings->xVSS.PanZoomTopleftXa);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c PanZoomTopleftYa: %d ms", indentation, ' ',
- pSettings->xVSS.PanZoomTopleftYa);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c PanZoomXb: %d ms", indentation, ' ',
- pSettings->xVSS.PanZoomXb);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c PanZoomTopleftXb: %d ms", indentation, ' ',
- pSettings->xVSS.PanZoomTopleftXb);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c PanZoomTopleftYb: %d ms", indentation, ' ',
- pSettings->xVSS.PanZoomTopleftYb);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c MediaRendering: %s", indentation, ' ',
- videoEditJava_getMediaRenderingString(pSettings->xVSS.MediaRendering));
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c <null>", indentation, ' ');
- }
-}
-#endif
-
-
-void
-videoEditClasses_getEditSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_EditSettings** ppSettings,
- bool flag)
-{
- VideoEditJava_EditSettingsFieldIds fieldIds;
- jobjectArray clipSettingsArray = NULL;
- jsize clipSettingsArraySize = 0;
- jobject clipSettings = NULL;
- jobjectArray transitionSettingsArray = NULL;
- jsize transitionSettingsArraySize = 0;
- jobject transitionSettings = NULL;
- jobjectArray effectSettingsArray = NULL;
- jsize effectSettingsArraySize = 0;
- jobject effectSettings = NULL;
- jobject backgroundMusicSettings = NULL;
- int audioChannels = 0;
- M4VSS3GPP_EditSettings* pSettings = M4OSA_NULL;
- bool converted = true;
- memset(&fieldIds, 0, sizeof(VideoEditJava_EditSettingsFieldIds));
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_getEditSettings()");
-
- // Retrieve the field ids.
- videoEditJava_getEditSettingsFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only retrieve the EditSettings if the previous action succeeded.
- if (*pResult)
- {
- // Check if the object is valid.
- if (NULL != object)
- {
- // Retrieve the clipSettingsArray.
- videoEditJava_getArray(pResult, pEnv, object,
- fieldIds.clipSettingsArray,
- &clipSettingsArray,
- &clipSettingsArraySize);
-
- // Retrieve the transitionSettingsArray.
- videoEditJava_getArray(pResult, pEnv, object,
- fieldIds.transitionSettingsArray,
- &transitionSettingsArray,
- &transitionSettingsArraySize);
-
- // Retrieve the effectSettingsArray.
- videoEditJava_getArray(pResult, pEnv, object,
- fieldIds.effectSettingsArray,
- &effectSettingsArray,
- &effectSettingsArraySize);
-
- // Retrieve the backgroundMusicSettings.
- videoEditJava_getObject(pResult, pEnv, object, fieldIds.backgroundMusicSettings,
- &backgroundMusicSettings);
-
- // Check if the arrays and background music settings object could be retrieved.
- if (*pResult)
- {
- // Retrieve the number of channels.
- audioChannels = pEnv->GetIntField(object, fieldIds.audioChannels);
- }
- }
- }
-
- // Only validate the EditSettings if the fields could be located.
- if (*pResult)
- {
- // Check if there is at least one clip.
- //videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- // (clipSettingsArraySize < 1),
- // "there should be at least one clip");
- if(clipSettingsArraySize < 1) {
- return;
- }
- if(flag)
- {
- // Check if there are clips.
- if ((clipSettingsArraySize != 0) || (transitionSettingsArraySize != 0))
- {
- // The number of transitions must be equal to the number of clips - 1.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (clipSettingsArraySize != (transitionSettingsArraySize + 1)),
- "the number of transitions should be equal to the number of clips - 1");
- }
- }
- }
-
- // Only retrieve the EditSettings if the fields could be located.
- if (*pResult)
- {
- // Check if the object is valid.
- if (NULL != object)
- {
- // Allocate memory for the EditSettings.
- pSettings = (M4VSS3GPP_EditSettings*)videoEditOsal_alloc(pResult, pEnv,
- sizeof(M4VSS3GPP_EditSettings), "EditSettings");
-
- // Check if memory could be allocated for the EditSettings.
- if (*pResult)
- {
- // Set the number of clips that will be edited.
- pSettings->uiClipNumber = clipSettingsArraySize;
-
- // Check if the clip settings array contains items.
- if (clipSettingsArraySize > 0)
- {
- // Allocate memory for the clip settings array.
- pSettings->pClipList = (M4VSS3GPP_ClipSettings **)videoEditOsal_alloc(pResult,
- pEnv,
- clipSettingsArraySize * sizeof(M4VSS3GPP_ClipSettings *),
- "ClipSettingsArray");
- if (*pResult)
- {
- // Loop over all clip settings objects.
- for (int i = 0; ((*pResult) && (i < clipSettingsArraySize)); i++)
- {
- // Get the clip settings object.
- clipSettings = pEnv->GetObjectArrayElement(clipSettingsArray, i);
-
- // Get the clip settings.
- videoEditClasses_getClipSettings(pResult, pEnv, clipSettings,
- &pSettings->pClipList[i]);
-
- // Free the local references to avoid memory leaks
- pEnv->DeleteLocalRef(clipSettings);
- }
- }
- }
-
- // Check if the transition settings array contains items.
- if (transitionSettingsArraySize > 0)
- {
- // Allocate memory for the transition settings array.
- pSettings->pTransitionList =
- (M4VSS3GPP_TransitionSettings **)videoEditOsal_alloc(pResult,
- pEnv, transitionSettingsArraySize * sizeof(M4VSS3GPP_TransitionSettings *),
- "TransitionSettingsArray");
- if (*pResult)
- {
- // Loop over all transition settings objects.
- for (int i = 0; ((*pResult) && (i < transitionSettingsArraySize)); i++)
- {
- // Get the transition settings object.
- transitionSettings =
- pEnv->GetObjectArrayElement(transitionSettingsArray, i);
-
- // Get the transition settings.
- videoEditClasses_getTransitionSettings(pResult, pEnv,
- transitionSettings, &pSettings->pTransitionList[i]);
-
- // Free the local references to avoid memory leaks
- pEnv->DeleteLocalRef(transitionSettings);
- }
- }
- }
-
- // Check if the effect settings array contains items.
- if (effectSettingsArraySize > 0)
- {
- // Allocate memory for the effect settings array.
- pSettings->Effects = (M4VSS3GPP_EffectSettings*)videoEditOsal_alloc(pResult,
- pEnv,
- effectSettingsArraySize * sizeof(M4VSS3GPP_EffectSettings),
- "EffectSettingsArray");
- if (*pResult)
- {
- // Loop over all effect settings objects.
- for (int i = 0; ((*pResult) && (i < effectSettingsArraySize)); i++)
- {
- // Get the effect settings object.
- effectSettings = pEnv->GetObjectArrayElement(effectSettingsArray, i);
-
- // Get the effect settings.
- videoEditClasses_getEffectSettings(pResult, pEnv, effectSettings,
- &pSettings->Effects[i]);
-
- // Free the local references to avoid memory leaks
- pEnv->DeleteLocalRef(effectSettings);
- }
- }
- }
-
- // Check if the clips, transitions and effects could be set.
- if (*pResult)
- {
- // Set the number of effects in the clip.
- pSettings->nbEffects = (M4OSA_UInt8)effectSettingsArraySize;
-
- // Set the frame rate of the output video.
- pSettings->videoFrameRate =
- (M4VIDEOEDITING_VideoFramerate)videoEditJava_getVideoFrameRateJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.videoFrameRate));
-
- // Check if the frame rate is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "editSettings.videoFrameRate is invalid");
- }
-
- // Check if the frame rate could be set.
- if (*pResult)
- {
- // Set the path of the output file.
- pSettings->pOutputFile = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv,
- object, fieldIds.outputFile, &pSettings->uiOutputPathSize);
- }
-
- // Check if path of the output file could be set.
- if (*pResult)
- {
- // Set the path of the temporary file produced when using
- // the constant memory 3gp writer.
- pSettings->pTemporaryFile = M4OSA_NULL;
-
- // Set the output video size.
- pSettings->xVSS.outputVideoSize =
- (M4VIDEOEDITING_VideoFrameSize)videoEditJava_getVideoFrameSizeJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.videoFrameSize));
-
- // Check if the output video size is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "editSettings.videoFrameSize is invalid");
- }
-
- // Check if the output video size could be set.
- if (*pResult)
- {
- // Set the output video format.
- pSettings->xVSS.outputVideoFormat =
- (M4VIDEOEDITING_VideoFormat)videoEditJava_getVideoFormatJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.videoFormat));
-
- // Check if the output video format is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "editSettings.videoFormat is invalid");
- }
-
- // Check if the output video format could be set.
- if (*pResult)
- {
- // Set the output audio format.
- pSettings->xVSS.outputAudioFormat =
- (M4VIDEOEDITING_AudioFormat)videoEditJava_getAudioFormatJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.audioFormat));
-
- // Check if the output audio format is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "editSettings.audioFormat is invalid");
- }
-
- // Check if the output audio format could be set.
- if (*pResult)
- {
- // Set the output audio sampling frequency when not replacing the audio,
- // or replacing it with MP3 audio.
- pSettings->xVSS.outputAudioSamplFreq =
- (M4VIDEOEDITING_AudioSamplingFrequency)\
- videoEditJava_getAudioSamplingFrequencyJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.audioSamplingFreq));
-
- // Check if the output audio sampling frequency is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "editSettings.audioSamplingFreq is invalid");
- }
-
- // Check if the output audio sampling frequency could be set.
- if (*pResult)
- {
- // Check if the number of audio channels is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- ((0 != audioChannels ) ||
- ((M4VIDEOEDITING_kNoneAudio != pSettings->xVSS.outputAudioFormat) &&
- (M4VIDEOEDITING_kNullAudio != pSettings->xVSS.outputAudioFormat) ) ) &&
- (1 != audioChannels ) &&
- (2 != audioChannels ),
- "editSettings.audioChannels must be set to 0, 1 or 2");
- }
-
- // Check if the number of audio channels is valid.
- if (*pResult)
- {
- // Set the maximum output file size (MMS usecase).
- pSettings->xVSS.outputFileSize = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.maxFileSize);
-
- // Whether or not the audio is mono, only valid for AAC.
- pSettings->xVSS.bAudioMono = (M4OSA_Bool)(1 == audioChannels);
-
- // Set the output video bitrate.
- pSettings->xVSS.outputVideoBitrate = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.videoBitrate);
-
- // Set the output video profile.
- pSettings->xVSS.outputVideoProfile = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.videoProfile);
-
- // Set the output video level.
- pSettings->xVSS.outputVideoLevel = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.videoLevel);
-
- // Set the output audio bitrate.
- pSettings->xVSS.outputAudioBitrate = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.audioBitrate);
-
- // Set the background music settings.
- videoEditClasses_getBackgroundMusicSettings(pResult, pEnv,
- backgroundMusicSettings, &pSettings->xVSS.pBGMtrack);
-
- // Set the text rendering function (will be set elsewhere).
- pSettings->xVSS.pTextRenderingFct = M4OSA_NULL;
- pSettings->PTVolLevel =
- (M4OSA_Float)pEnv->GetIntField(object, fieldIds.primaryTrackVolume);
- }
- }
-
- // Check if settings could be set.
- if (*pResult)
- {
- // Return the settings.
- (*ppSettings) = pSettings;
- }
- else
- {
- // Free the settings.
- videoEditClasses_freeEditSettings(&pSettings);
- }
- }
- }
-}
-
-void
-videoEditClasses_freeEditSettings(
- M4VSS3GPP_EditSettings** ppSettings)
-{
- // Check if memory was allocated for the EditSettings.
- if (M4OSA_NULL != (*ppSettings))
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_freeEditSettings()");
-
- // Free the background music settings.
- videoEditClasses_freeBackgroundMusicSettings(&(*ppSettings)->xVSS.pBGMtrack);
-
- // Free the path of the output file.
- videoEditOsal_free((*ppSettings)->pOutputFile);
- (*ppSettings)->pOutputFile = M4OSA_NULL;
- (*ppSettings)->uiOutputPathSize = 0;
-
- // Check if the EffectSettings should be freed.
- if (M4OSA_NULL != (*ppSettings)->Effects)
- {
- // Loop over all effect settings.
- for (int i = 0; i < (*ppSettings)->nbEffects; i++)
- {
- // Free the effect settings.
- videoEditClasses_freeEffectSettings(&(*ppSettings)->Effects[i]);
- }
-
- // Free the memory for the effect settings array.
- videoEditOsal_free((*ppSettings)->Effects);
- (*ppSettings)->Effects = M4OSA_NULL;
- }
-
- // Reset the number of effects in the clip.
- (*ppSettings)->nbEffects = 0;
-
- // Check if there are clips.
- if (0 < (*ppSettings)->uiClipNumber)
- {
- // Check if the TransitionSettings should be freed.
- if (M4OSA_NULL != (*ppSettings)->pTransitionList)
- {
- // Loop over all transition settings.
- for (int i = 0; i < ((*ppSettings)->uiClipNumber - 1); i++)
- {
- // Free the transition settings.
- videoEditClasses_freeTransitionSettings(&(*ppSettings)->pTransitionList[i]);
- }
-
- // Free the memory for the transition settings array.
- videoEditOsal_free((*ppSettings)->pTransitionList);
- (*ppSettings)->pTransitionList = M4OSA_NULL;
- }
-
- // Check if the ClipSettings should be freed.
- if (M4OSA_NULL != (*ppSettings)->pClipList)
- {
- // Loop over all clip settings.
- for (int i = 0; i < (*ppSettings)->uiClipNumber; i++)
- {
- // Free the clip settings.
- videoEditClasses_freeClipSettings(&(*ppSettings)->pClipList[i]);
- }
-
- // Free the memory for the clip settings array.
- videoEditOsal_free((*ppSettings)->pClipList);
- (*ppSettings)->pClipList = M4OSA_NULL;
- }
- }
-
- // Reset the number of clips.
- (*ppSettings)->uiClipNumber = 0;
-
- // Free the settings structure.
- videoEditOsal_free((*ppSettings));
- (*ppSettings) = M4OSA_NULL;
- }
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logEditSettings(
- M4VSS3GPP_EditSettings* pSettings,
- int indentation)
-{
- // Check if memory was allocated for the EditSettings.
- if (M4OSA_NULL != pSettings)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiClipNumber: %d", indentation, ' ',
- pSettings->uiClipNumber);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiMasterClip: %d", indentation, ' ',
- pSettings->uiMasterClip);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pClipList: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->pClipList) ? " " : "<null>");
- if (M4OSA_NULL != pSettings->pClipList)
- {
- indentation += VIDEOEDIT_LOG_INDENTATION;
- for (int i = 0; i < pSettings->uiClipNumber; i++)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pClipList[%d]:", indentation, ' ',
- i);
- videoEditClasses_logClipSettings(pSettings->pClipList[i],
- indentation + VIDEOEDIT_LOG_INDENTATION);
- }
- indentation -= VIDEOEDIT_LOG_INDENTATION;
- }
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pTransitionList: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->pTransitionList) ? " " : "<null>");
- if (M4OSA_NULL != pSettings->pTransitionList)
- {
- indentation += VIDEOEDIT_LOG_INDENTATION;
- for (int i = 0; i < (pSettings->uiClipNumber - 1); i++)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pTransitionList[%d]:", indentation, ' ', i);
- videoEditClasses_logTransitionSettings(pSettings->pTransitionList[i],
- indentation + VIDEOEDIT_LOG_INDENTATION);
- }
- indentation -= VIDEOEDIT_LOG_INDENTATION;
- }
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c Effects: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->Effects) ? " " : "<null>");
- if (M4OSA_NULL != pSettings->Effects)
- {
- indentation += VIDEOEDIT_LOG_INDENTATION;
- for (int i = 0; i < pSettings->nbEffects; i++)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c Effects[%d]:", indentation, ' ', i);
- videoEditClasses_logEffectSettings(&pSettings->Effects[i],
- indentation + VIDEOEDIT_LOG_INDENTATION);
- }
- indentation -= VIDEOEDIT_LOG_INDENTATION;
- }
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c nbEffects: %d", indentation, ' ',
- pSettings->nbEffects);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c videoFrameRate: %s", indentation, ' ',
- videoEditJava_getVideoFrameRateString(pSettings->videoFrameRate));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pOutputFile: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->pOutputFile) ? (char*)pSettings->pOutputFile : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiOutputPathSize: %u", indentation, ' ',
- (unsigned int)pSettings->uiOutputPathSize);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pTemporaryFile: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->pTemporaryFile) ?\
- (char*)pSettings->pTemporaryFile : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputVideoSize: %s", indentation, ' ',
- videoEditJava_getVideoFrameSizeString(pSettings->xVSS.outputVideoSize));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputVideoFormat: %s", indentation, ' ',
- videoEditJava_getVideoFormatString(pSettings->xVSS.outputVideoFormat));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputVideoProfile: %u", indentation, ' ',
- videoEditJava_getVideoFormatString(pSettings->xVSS.outputVideoProfile));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputVideoLevel: %u", indentation, ' ',
- videoEditJava_getVideoFormatString(pSettings->xVSS.outputVideoLevel));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputAudioFormat: %s", indentation, ' ',
- videoEditJava_getAudioFormatString(pSettings->xVSS.outputAudioFormat));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputAudioSamplFreq: %s", indentation, ' ',
- videoEditJava_getAudioSamplingFrequencyString(pSettings->xVSS.outputAudioSamplFreq));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputFileSize: %u", indentation, ' ',
- (unsigned int)pSettings->xVSS.outputFileSize);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bAudioMono: %s", indentation, ' ',
- pSettings->xVSS.bAudioMono ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputVideoBitrate: %s", indentation, ' ',
- videoEditJava_getBitrateString(pSettings->xVSS.outputVideoBitrate));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c outputAudioBitrate: %s", indentation, ' ',
- videoEditJava_getBitrateString(pSettings->xVSS.outputAudioBitrate));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pBGMtrack:", indentation, ' ');
- videoEditClasses_logBackgroundMusicSettings(pSettings->xVSS.pBGMtrack,
- indentation + VIDEOEDIT_LOG_INDENTATION);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pTextRenderingFct: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->xVSS.pTextRenderingFct) ? "set" : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c PTVolLevel: %u", indentation, ' ',
- (unsigned int)pSettings->PTVolLevel);
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c <null>", indentation, ' ');
- }
-}
-#endif
-
-
-void
-videoEditClasses_getEffectSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_EffectSettings* pSettings)
-{
-
- VideoEditJava_EffectSettingsFieldIds fieldIds;
- bool converted = true;
- memset(&fieldIds, 0, sizeof(VideoEditJava_EffectSettingsFieldIds));
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_getEffectSettings()");
-
- // Retrieve the field ids.
- videoEditJava_getEffectSettingsFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only validate the EffectSettings if the fields could be located.
- if (*pResult)
- {
- // Check if the effect is set.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (NULL == object),
- "effect is null");
- }
-
- // Only retrieve the EffectSettings if the fields could be located and validated.
- if (*pResult)
- {
- // Set the start time in milliseconds.
- pSettings->uiStartTime = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.startTime);
-
- // Set the duration in milliseconds.
- pSettings->uiDuration = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.duration);
-
- // Set the video effect type, None, FadeIn, FadeOut, etc.
- pSettings->VideoEffectType =
- (M4VSS3GPP_VideoEffectType)videoEditJava_getVideoEffectJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.videoEffectType));
-
- // Check if the video effect type is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "effect.videoEffectType is invalid");
- }
-
- // Check if the video effect type could be set.
- if (*pResult)
- {
- // Set the external effect function.
- pSettings->ExtVideoEffectFct = M4OSA_NULL;
-
- // Set the context given to the external effect function.
- pSettings->pExtVideoEffectFctCtxt = M4OSA_NULL;
-
- // Set the audio effect type, None, FadeIn, FadeOut.
- pSettings->AudioEffectType =
- (M4VSS3GPP_AudioEffectType)videoEditJava_getAudioEffectJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.audioEffectType));
-
- // Check if the audio effect type is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "effect.audioEffectType is invalid");
- }
-
- // Check if the audio effect type could be set.
- if (*pResult)
- {
- // Set the start in percentage of the cut clip duration.
- pSettings->xVSS.uiStartPercent = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.startPercent);
-
- // Set the duration in percentage of the ((clip duration) - (effect starttime)).
- pSettings->xVSS.uiDurationPercent = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.durationPercent);
-
- // Set the framing file path (GIF/PNG file).
- pSettings->xVSS.pFramingFilePath = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv,
- object, fieldIds.framingFile, M4OSA_NULL);
-
- // Check if this is a framing effect.
- if (M4xVSS_kVideoEffectType_Framing == (M4xVSS_VideoEffectType)pSettings->VideoEffectType)
- {
- // Check if the framing file path is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (M4OSA_NULL == pSettings->xVSS.pFramingFilePath), "effect.framingFile is null");
- }
- }
-
- // Check if the framing file path could be retrieved.
- if (*pResult)
- {
- // Set the Framing RGB565 buffer.
- pSettings->xVSS.pFramingBuffer = M4OSA_NULL;
-
- // Set the top-left X coordinate in the output picture
- // where the added frame will be displayed.
- pSettings->xVSS.topleft_x = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.topLeftX);
-
- // Set the top-left Y coordinate in the output picture
- // where the added frame will be displayed.
- pSettings->xVSS.topleft_y = (M4OSA_UInt32)pEnv->GetIntField(object, fieldIds.topLeftY);
-
- // Set whether or not the framing image is resized to output video size.
- pSettings->xVSS.bResize =
- (M4OSA_Bool)pEnv->GetBooleanField(object, fieldIds.framingResize);
-
- // Set the new size to which framing buffer needs to be resized to
- pSettings->xVSS.framingScaledSize =
- (M4VIDEOEDITING_VideoFrameSize)pEnv->GetIntField(object, fieldIds.framingScaledSize);
-
- // Set the text buffer.
- pSettings->xVSS.pTextBuffer = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv, object,
- fieldIds.text, &pSettings->xVSS.textBufferSize);
- }
-
- // Check if the text buffer could be retrieved.
- if (*pResult)
- {
- // Set the data used by the font engine (size, color...).
- pSettings->xVSS.pRenderingData = (M4OSA_Char*)videoEditJava_getString(pResult, pEnv,
- object, fieldIds.textRenderingData, M4OSA_NULL);
- }
-
- // Check if the text rendering data could be retrieved.
- if (*pResult)
- {
- // Set the text plane width.
- pSettings->xVSS.uiTextBufferWidth = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.textBufferWidth);
-
- // Set the text plane height.
- pSettings->xVSS.uiTextBufferHeight = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.textBufferHeight);
-
- // Set the processing rate of the effect added when using the Fifties effect.
- pSettings->xVSS.uiFiftiesOutFrameRate = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.fiftiesFrameRate);
-
- // Set the RGB16 input color of the effect added when using the rgb16 color effect.
- pSettings->xVSS.uiRgb16InputColor = (M4OSA_UInt16)pEnv->GetIntField(object,
- fieldIds.rgb16InputColor);
-
- // Set the start percentage of Alpha blending.
- pSettings->xVSS.uialphaBlendingStart = (M4OSA_UInt8)pEnv->GetIntField(object,
- fieldIds.alphaBlendingStartPercent);
-
- // Set the middle percentage of Alpha blending.
- pSettings->xVSS.uialphaBlendingMiddle = (M4OSA_UInt8)pEnv->GetIntField(object,
- fieldIds.alphaBlendingMiddlePercent);
-
- // Set the end percentage of Alpha blending.
- pSettings->xVSS.uialphaBlendingEnd = (M4OSA_UInt8)pEnv->GetIntField(object,
- fieldIds.alphaBlendingEndPercent);
-
- // Set the duration, in percentage of effect duration, of the FadeIn phase.
- pSettings->xVSS.uialphaBlendingFadeInTime = (M4OSA_UInt8)pEnv->GetIntField(object,
- fieldIds.alphaBlendingFadeInTimePercent);
-
- // Set the duration, in percentage of effect duration, of the FadeOut phase.
- pSettings->xVSS.uialphaBlendingFadeOutTime = (M4OSA_UInt8)pEnv->GetIntField(object,
- fieldIds.alphaBlendingFadeOutTimePercent);
-
- if (pSettings->xVSS.pFramingFilePath != M4OSA_NULL)
- {
- pSettings->xVSS.pFramingBuffer =
- (M4VIFI_ImagePlane *)M4OSA_32bitAlignedMalloc(sizeof(M4VIFI_ImagePlane),
- 0x00,(M4OSA_Char *)"framing buffer");
- }
-
- if (pSettings->xVSS.pFramingBuffer != M4OSA_NULL)
- {
- // OverFrame height and width
- pSettings->xVSS.pFramingBuffer->u_width = pEnv->GetIntField(object,
- fieldIds.width);
-
- pSettings->xVSS.pFramingBuffer->u_height = pEnv->GetIntField(object,
- fieldIds.height);
-
- pSettings->xVSS.width = pSettings->xVSS.pFramingBuffer->u_width;
- pSettings->xVSS.height = pSettings->xVSS.pFramingBuffer->u_height;
- pSettings->xVSS.rgbType = M4VSS3GPP_kRGB565;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "pFramingBuffer u_width %d ", pSettings->xVSS.pFramingBuffer->u_width);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "pFramingBuffer u_height %d", pSettings->xVSS.pFramingBuffer->u_height);
-
- }
-
- // Check if settings could be set.
- if (!(*pResult))
- {
- // Free the settings.
- videoEditClasses_freeEffectSettings(pSettings);
- }
- }
-}
-
-void
-videoEditClasses_freeEffectSettings(
- M4VSS3GPP_EffectSettings* pSettings)
-{
- // Check if memory was allocated for the EffectSettings.
- if (M4OSA_NULL != pSettings)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_freeEffectSettings()");
-
- // Free the data used by the font engine (size, color...).
- videoEditOsal_free(pSettings->xVSS.pRenderingData);
- pSettings->xVSS.pRenderingData = M4OSA_NULL;
-
- // Free the text buffer.
- videoEditOsal_free(pSettings->xVSS.pTextBuffer);
- pSettings->xVSS.pTextBuffer = M4OSA_NULL;
- pSettings->xVSS.textBufferSize = 0;
-
- // Free the framing file path.
- videoEditOsal_free(pSettings->xVSS.pFramingFilePath);
- pSettings->xVSS.pFramingFilePath = M4OSA_NULL;
- }
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logEffectSettings(
- M4VSS3GPP_EffectSettings* pSettings,
- int indentation)
-{
- // Check if memory was allocated for the EffectSettings.
- if (M4OSA_NULL != pSettings)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiStartTime: %u ms", indentation, ' ',
- (unsigned int)pSettings->uiStartTime);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiDuration: %u ms", indentation, ' ',
- (unsigned int)pSettings->uiDuration);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c VideoEffectType: %s", indentation, ' ',
- videoEditJava_getVideoEffectString(pSettings->VideoEffectType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c ExtVideoEffectFct: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->ExtVideoEffectFct) ? "set" : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pExtVideoEffectFctCtxt: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->pExtVideoEffectFctCtxt) ? "set" : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c AudioEffectType: %s", indentation, ' ',
- videoEditJava_getAudioEffectString(pSettings->AudioEffectType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiStartPercent: %u %%", indentation, ' ',
- (unsigned int)pSettings->xVSS.uiStartPercent);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiDurationPercent: %u %%", indentation, ' ',
- (unsigned int)pSettings->xVSS.uiDurationPercent);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pFramingFilePath: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->xVSS.pFramingFilePath) ?\
- (char*)pSettings->xVSS.pFramingFilePath : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pFramingBuffer: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->xVSS.pFramingBuffer) ? "set" : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c topleft_x: %u", indentation, ' ',
- (unsigned int)pSettings->xVSS.topleft_x);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c topleft_y: %u", indentation, ' ',
- (unsigned int)pSettings->xVSS.topleft_y);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c bResize: %s", indentation, ' ',
- pSettings->xVSS.bResize ? "true" : "false");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pTextBuffer: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->xVSS.pTextBuffer) ?\
- (char*)pSettings->xVSS.pTextBuffer : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c textBufferSize: %u", indentation, ' ',
- (unsigned int)pSettings->xVSS.textBufferSize);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pRenderingData: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->xVSS.pRenderingData) ?\
- (char*)pSettings->xVSS.pRenderingData : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiTextBufferWidth: %u", indentation, ' ',
- (unsigned int)pSettings->xVSS.uiTextBufferWidth);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiTextBufferHeight: %u", indentation, ' ',
- (unsigned int)pSettings->xVSS.uiTextBufferHeight);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiFiftiesOutFrameRate: %u", indentation, ' ',
- (unsigned int)pSettings->xVSS.uiFiftiesOutFrameRate);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiRgb16InputColor: %d", indentation, ' ',
- pSettings->xVSS.uiRgb16InputColor);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uialphaBlendingStart: %d %%", indentation, ' ',
- pSettings->xVSS.uialphaBlendingStart);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uialphaBlendingMiddle: %d %%", indentation, ' ',
- pSettings->xVSS.uialphaBlendingMiddle);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uialphaBlendingEnd: %d %%", indentation, ' ',
- pSettings->xVSS.uialphaBlendingEnd);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uialphaBlendingFadeInTime: %d %%", indentation, ' ',
- pSettings->xVSS.uialphaBlendingFadeInTime);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uialphaBlendingFadeOutTime: %d %%", indentation, ' ',
- pSettings->xVSS.uialphaBlendingFadeOutTime);
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c <null>", indentation, ' ');
- }
-}
-#endif
-
-
-void
-videoEditClasses_getSlideTransitionSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4xVSS_SlideTransitionSettings** ppSettings)
-{
- VideoEditJava_SlideTransitionSettingsFieldIds fieldIds = {NULL};
- M4xVSS_SlideTransitionSettings* pSettings = M4OSA_NULL;
- bool converted = true;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_getSlideTransitionSettings()");
-
- // Retrieve the field ids.
- videoEditJava_getSlideTransitionSettingsFieldIds(pResult, pEnv, &fieldIds);
- }
-
-
- // Only validate the SlideTransitionSettings if the fields could be located.
- if (*pResult)
- {
- // Check if the clip is set.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (NULL == object),
- "slideSettings is null");
- }
-
- // Only retrieve the SlideTransitionSettings if the fields could be located and validated.
- if (*pResult)
- {
- // Allocate memory for the SlideTransitionSettings.
- pSettings = (M4xVSS_SlideTransitionSettings*)videoEditOsal_alloc(pResult, pEnv,
- sizeof(M4xVSS_SlideTransitionSettings), "SlideTransitionSettings");
-
- // Check if memory could be allocated for the SlideTransitionSettings.
- if (*pResult)
- {
- // Set the direction of the slide.
- pSettings->direction =
- (M4xVSS_SlideTransition_Direction)videoEditJava_getSlideDirectionJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.direction));
-
- // Check if the direction is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- !converted, "slideSettings.direction is invalid");
- }
-
- // Check if settings could be set.
- if (*pResult)
- {
- // Return the settings.
- (*ppSettings) = pSettings;
- }
- else
- {
- // Free the settings.
- videoEditClasses_freeSlideTransitionSettings(&pSettings);
- }
- }
-}
-
-void
-videoEditClasses_freeSlideTransitionSettings(
- M4xVSS_SlideTransitionSettings** ppSettings)
-{
- // Check if memory was allocated for the SlideTransitionSettings.
- if (M4OSA_NULL != (*ppSettings))
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_freeSlideTransitionSettings()");
-
- // Free the settings structure.
- videoEditOsal_free((*ppSettings));
- (*ppSettings) = M4OSA_NULL;
- }
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logSlideTransitionSettings(
- M4xVSS_SlideTransitionSettings* pSettings,
- int indentation)
-{
- // Check if memory was allocated for the SlideTransitionSettings.
- if (M4OSA_NULL != pSettings)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c direction: %s", indentation, ' ',
- videoEditJava_getSlideDirectionString(pSettings->direction));
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c <null>", indentation, ' ');
- }
-}
-#endif
-
-
-void
-videoEditClasses_getTransitionSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_TransitionSettings** ppSettings)
-{
-
- VideoEditJava_TransitionSettingsFieldIds fieldIds;
- jobject alphaSettings = NULL;
- jobject slideSettings = NULL;
- M4VSS3GPP_TransitionSettings* pSettings = M4OSA_NULL;
- bool converted = true;
- memset(&fieldIds, 0, sizeof(VideoEditJava_TransitionSettingsFieldIds));
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_getTransitionSettings()");
-
- // Retrieve the field ids.
- videoEditJava_getTransitionSettingsFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only validate the TransitionSettings if the fields could be located.
- if (*pResult)
- {
- // Check if the transition is set.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (NULL == object),
- "transition is null");
- }
-
- // Check if the field ids could be located and validated.
- if (*pResult)
- {
- // Retrieve the alphaSettings.
- videoEditJava_getObject(pResult, pEnv, object, fieldIds.alphaSettings, &alphaSettings);
-
- // Retrieve the slideSettings.
- videoEditJava_getObject(pResult, pEnv, object, fieldIds.slideSettings, &slideSettings);
- }
-
- // Only retrieve the TransitionSettings if the fields could be located.
- if (*pResult)
- {
- // Allocate memory for the TransitionSettings.
- pSettings = (M4VSS3GPP_TransitionSettings*)videoEditOsal_alloc(pResult,
- pEnv, sizeof(M4VSS3GPP_TransitionSettings), "TransitionSettings");
-
- // Check if memory could be allocated for the TransitionSettings.
- if (*pResult)
- {
- // Set the duration of the transition, in milliseconds (set to 0 to get no transition).
- pSettings->uiTransitionDuration = (M4OSA_UInt32)pEnv->GetIntField(object,
- fieldIds.duration);
-
- // Set the type of the video transition.
- pSettings->VideoTransitionType =
- (M4VSS3GPP_VideoTransitionType)videoEditJava_getVideoTransitionJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.videoTransitionType));
-
- // Check if the video transition type is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, !converted,
- "transition.videoTransitionType is invalid");
- }
-
- // Check if the video transition type could be set.
- if (*pResult)
- {
- // Set the external transition video effect function.
- pSettings->ExtVideoTransitionFct = M4OSA_NULL;
-
- // Set the context of the external transition video effect function.
- pSettings->pExtVideoTransitionFctCtxt = M4OSA_NULL;
-
- // Set the type of the audio transition.
- pSettings->AudioTransitionType =
- (M4VSS3GPP_AudioTransitionType)videoEditJava_getAudioTransitionJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.audioTransitionType));
-
- // Check if the audio transition type is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, !converted,
- "transition.audioTransitionType is invalid");
- }
-
- // Check if the audio transition type could be set.
- if (*pResult)
- {
- // Set the transition behaviour.
- pSettings->TransitionBehaviour =
- (M4VSS3GPP_TransitionBehaviour)videoEditJava_getTransitionBehaviourJavaToC(
- &converted, pEnv->GetIntField(object, fieldIds.transitionBehaviour));
-
- // Check if the transition behaviour is valid.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, !converted,
- "transition.transitionBehaviour is invalid");
- }
-
- // Check if the audio transition behaviour could be set.
- if (*pResult)
- {
- // Check if a slide transition or alpha magic setting object is expected.
- if ((int)pSettings->VideoTransitionType == M4xVSS_kVideoTransitionType_SlideTransition)
- {
- // Set the slide transition settings.
- videoEditClasses_getSlideTransitionSettings(pResult, pEnv, slideSettings,
- &pSettings->xVSS.transitionSpecific.pSlideTransitionSettings);
- }
- else if ((int)pSettings->VideoTransitionType == M4xVSS_kVideoTransitionType_AlphaMagic)
- {
- // Set the alpha magic settings.
- videoEditClasses_getAlphaMagicSettings(pResult, pEnv, alphaSettings,
- &pSettings->xVSS.transitionSpecific.pAlphaMagicSettings);
- }
- }
-
- // Check if settings could be set.
- if (*pResult)
- {
- // Return the settings.
- (*ppSettings) = pSettings;
- }
- else
- {
- // Free the settings.
- videoEditClasses_freeTransitionSettings(&pSettings);
- }
- }
-}
-
-void
-videoEditClasses_freeTransitionSettings(
- M4VSS3GPP_TransitionSettings** ppSettings)
-{
- // Check if memory was allocated for the TransitionSettings.
- if (M4OSA_NULL != (*ppSettings))
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_freeTransitionSettings()");
-
- // Check if a slide transition or alpha magic setting structure is expected.
- if ((int)(*ppSettings)->VideoTransitionType == M4xVSS_kVideoTransitionType_SlideTransition)
- {
- // Free the slide transition settings.
- videoEditClasses_freeSlideTransitionSettings(
- &(*ppSettings)->xVSS.transitionSpecific.pSlideTransitionSettings);
- }
- else
- {
- // Free the alpha magic settings.
- videoEditClasses_freeAlphaMagicSettings(
- &(*ppSettings)->xVSS.transitionSpecific.pAlphaMagicSettings);
- }
-
- // Free the settings structure.
- videoEditOsal_free((*ppSettings));
- (*ppSettings) = M4OSA_NULL;
- }
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logTransitionSettings(
- M4VSS3GPP_TransitionSettings* pSettings,
- int indentation)
-{
- // Check if memory was allocated for the TransitionSettings.
- if (M4OSA_NULL != pSettings)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c uiTransitionDuration: %u ms", indentation, ' ',
- (unsigned int)pSettings->uiTransitionDuration);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c VideoTransitionType: %s", indentation, ' ',
- videoEditJava_getVideoTransitionString(pSettings->VideoTransitionType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c ExtVideoTransitionFct: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->ExtVideoTransitionFct) ? "set" : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pExtVideoTransitionFctCtxt: %s", indentation, ' ',
- (M4OSA_NULL != pSettings->pExtVideoTransitionFctCtxt) ? "set" : "<null>");
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c AudioTransitionType: %s", indentation, ' ',
- videoEditJava_getAudioTransitionString(pSettings->AudioTransitionType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c TransitionBehaviour: %s", indentation, ' ',
- videoEditJava_getTransitionBehaviourString(pSettings->TransitionBehaviour));
-
- // Check if a slide transition or alpha magic setting structure is expected.
- if ((int)pSettings->VideoTransitionType == M4xVSS_kVideoTransitionType_SlideTransition)
- {
- // Log the slide transition settings.
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pSlideTransitionSettings:", indentation, ' ');
- videoEditClasses_logSlideTransitionSettings\
- (pSettings->xVSS.transitionSpecific.pSlideTransitionSettings,
- indentation + VIDEOEDIT_LOG_INDENTATION);
- }
- else
- {
- // Log the alpha magic settings.
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c pAlphaMagicSettings:", indentation, ' ');
- videoEditClasses_logAlphaMagicSettings\
- (pSettings->xVSS.transitionSpecific.pAlphaMagicSettings,
- indentation + VIDEOEDIT_LOG_INDENTATION);
- }
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c <null>", indentation, ' ');
- }
-}
-#endif
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditPropClass_logProperties(
- VideoEditPropClass_Properties* pProperties,
- int indentation)
-{
- // Check if memory was allocated for the Properties.
- if (M4OSA_NULL != pProperties)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiClipDuration: %u", indentation, ' ',
- (unsigned int)pProperties->uiClipDuration);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c FileType: %s", indentation, ' ',
- videoEditJava_getFileTypeString(pProperties->FileType));
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c VideoStreamType: %s", indentation, ' ',
- videoEditJava_getVideoFormatString(pProperties->VideoStreamType));
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiClipVideoDuration: %u", indentation, ' ',
- (unsigned int)pProperties->uiClipVideoDuration);
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiVideoBitrate: %s", indentation, ' ',
- videoEditJava_getBitrateString(pProperties->uiVideoBitrate));
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiVideoWidth: %u", indentation, ' ',
- (unsigned int)pProperties->uiVideoWidth);
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiVideoHeight: %u", indentation, ' ',
- (unsigned int)(unsigned int)pProperties->uiVideoHeight);
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c fAverageFrameRate: %.3f", indentation, ' ',
- pProperties->fAverageFrameRate);
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c AudioStreamType: %s", indentation, ' ',
- videoEditJava_getAudioFormatString(pProperties->AudioStreamType));
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiClipAudioDuration: %u", indentation, ' ',
- (unsigned int)pProperties->uiClipAudioDuration);
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiAudioBitrate: %s", indentation, ' ',
- videoEditJava_getBitrateString(pProperties->uiAudioBitrate));
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiNbChannels: %u", indentation, ' ',
- (unsigned int)pProperties->uiNbChannels);
-
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c uiSamplingFrequency: %u", indentation, ' ',
- (unsigned int)pProperties->uiSamplingFrequency);
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_PROP_CLASSES",
- "%*c <null>", indentation, ' ');
- }
-}
-#endif
-
-
-void
-videoEditClasses_createVersion(
- bool* pResult,
- JNIEnv* pEnv,
- M4_VersionInfo* pVersionInfo,
- jobject* pObject)
-{
-
- VideoEditJava_VersionFieldIds fieldIds;
- jclass clazz = NULL;
- jobject object = NULL;
- memset(&fieldIds, 0, sizeof(VideoEditJava_VersionFieldIds));
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_createVersion()");
-
- // Retrieve the class.
- videoEditJava_getVersionClass(pResult, pEnv, &clazz);
-
- // Retrieve the field ids.
- videoEditJava_getVersionFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Only create an object if the class and fields could be located.
- if (*pResult)
- {
- // Allocate a new object.
- object = pEnv->AllocObject(clazz);
-
- // check if alloc is done
- videoEditJava_checkAndThrowRuntimeException(pResult, pEnv,
- (NULL == object),
- M4ERR_ALLOC);
- if (NULL != object)
- {
- // Set the major field.
- pEnv->SetIntField(object, fieldIds.major, pVersionInfo->m_major);
-
- // Set the minor field.
- pEnv->SetIntField(object, fieldIds.minor, pVersionInfo->m_minor);
-
- // Set the revision field.
- pEnv->SetIntField(object, fieldIds.revision, pVersionInfo->m_revision);
-
- // Return the object.
- (*pObject) = object;
- }
- }
-}
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-void
-videoEditClasses_logVersion(
- M4_VersionInfo* pVersionInfo,
- int indentation)
-{
- // Check if memory was allocated for the Version.
- if (M4OSA_NULL != pVersionInfo)
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c major: %u ms", indentation, ' ',
- (unsigned int)pVersionInfo->m_major);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c minor: %u", indentation, ' ',
- (unsigned int)pVersionInfo->m_minor);
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c revision: %u", indentation, ' ',
- (unsigned int)pVersionInfo->m_revision);
- }
- else
- {
- VIDEOEDIT_LOG_SETTING(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "%*c <null>", indentation, ' ');
- }
-}
-#endif
-
-
-void*
-videoEditClasses_getContext(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object)
-{
- void* pContext = M4OSA_NULL;
- jclass clazz = NULL;
- VideoEditJava_EngineFieldIds fieldIds = {NULL};
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_getContext()");
-
- // Retrieve the class.
- videoEditJava_getEngineClass(pResult, pEnv, &clazz);
-
- // Retrieve the field ids.
- videoEditJava_getEngineFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Check if the class and field ids could be located.
- if (*pResult)
- {
- // Retrieve the context pointer.
- pContext = (void *)pEnv->GetLongField(object, fieldIds.context);
- }
-
- // Return the context pointer.
- return(pContext);
-}
-
-void
-videoEditClasses_setContext(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- void* pContext)
-{
- jclass clazz = NULL;
- VideoEditJava_EngineFieldIds fieldIds = {NULL};
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "videoEditClasses_setContext()");
-
- // Retrieve the class.
- videoEditJava_getEngineClass(pResult, pEnv, &clazz);
-
- // Retrieve the field ids.
- videoEditJava_getEngineFieldIds(pResult, pEnv, &fieldIds);
- }
-
- // Check if the class and field ids could be located.
- if (*pResult)
- {
- // Set the context field.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "The context value from JAVA before setting is = %p",
- (void *)pEnv->GetLongField(object, fieldIds.context));
-
- pEnv->SetLongField(object, fieldIds.context, (jlong)pContext);
- M4OSA_TRACE1_1("The context value in JNI is = %p",pContext);
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_CLASSES",
- "The context value from JAVA after setting is = %p",
- (void *)pEnv->GetLongField(object, fieldIds.context));
- }
-}
-
diff --git a/media/jni/mediaeditor/VideoEditorClasses.h b/media/jni/mediaeditor/VideoEditorClasses.h
deleted file mode 100644
index a4c82a8..0000000
--- a/media/jni/mediaeditor/VideoEditorClasses.h
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VIDEO_EDITOR_CLASSES_H
-#define VIDEO_EDITOR_CLASSES_H
-
-#include <VideoEditorJava.h>
-#include <VideoEditorClasses.h>
-/**
- ************************************************************************
- * @file VideoEditorClasses.h
- * @brief Interface for JNI methods/defines that have specific
- * access to class, objects and method Ids defined in Java layer
- ************************************************************************
-*/
-
-
-extern "C" {
-#include <M4xVSS_API.h>
-#include <M4VSS3GPP_API.h>
-#include <M4VSS3GPP_ErrorCodes.h>
-#include <M4MCS_ErrorCodes.h>
-#include <M4READER_Common.h>
-#include <M4WRITER_common.h>
-};
-
-/*
- * Java layer class/object name strings
- */
-#define PACKAGE_NAME "android/media/videoeditor"
-
-#define MANUAL_EDIT_ENGINE_CLASS_NAME PACKAGE_NAME"/MediaArtistNativeHelper"
-#define MEDIA_PROPERTIES_ENGINE_CLASS_NAME PACKAGE_NAME"/MediaArtistNativeHelper"
-
-#define AUDIO_FORMAT_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioFormat"
-#define RESULTS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$Results"
-#define VERSION_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$Version"
-#define AUDIO_SAMPLING_FREQUENCY_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioSamplingFrequency"
-#define BITRATE_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$Bitrate"
-#define ERROR_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$Result"
-#define FILE_TYPE_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$FileType"
-#define MEDIA_RENDERING_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$MediaRendering"
-#define VIDEO_FORMAT_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoFormat"
-#define VIDEO_FRAME_RATE_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoFrameRate"
-#define VIDEO_FRAME_SIZE_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoFrameSize"
-#define VIDEO_PROFILE_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoProfile"
-#define ALPHA_MAGIC_SETTINGS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$AlphaMagicSettings"
-#define AUDIO_EFFECT_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioEffect"
-#define AUDIO_TRANSITION_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioTransition"
-#define BACKGROUND_MUSIC_SETTINGS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$BackgroundMusicSettings"
-#define CLIP_SETTINGS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$ClipSettings"
-#define EDIT_SETTINGS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$EditSettings"
-#define EFFECT_SETTINGS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$EffectSettings"
-#define SLIDE_DIRECTION_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$SlideDirection"
-#define SLIDE_TRANSITION_SETTINGS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$SlideTransitionSettings"
-#define TRANSITION_BEHAVIOUR_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$TransitionBehaviour"
-#define TRANSITION_SETTINGS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$TransitionSettings"
-#define VIDEO_EFFECT_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoEffect"
-#define VIDEO_TRANSITION_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$VideoTransition"
-#define PREVIEW_CLIPS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$PreviewClips"
-#define PREVIEW_SETTING_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$PreviewSettings"
-#define PREVIEW_PROPERTIES_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$PreviewClipProperties"
-#define AUDIO_SETTINGS_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$AudioSettings"
-#define PROPERTIES_CLASS_NAME MANUAL_EDIT_ENGINE_CLASS_NAME"$Properties"
-
-#define TASK_IDLE 0
-#define TASK_LOADING_SETTINGS 1
-#define TASK_ENCODING 2
-
-/*
- * File type enum
- */
-typedef enum
-{
- VideoEditClasses_kFileType_3GPP,
- VideoEditClasses_kFileType_MP4,
- VideoEditClasses_kFileType_AMR,
- VideoEditClasses_kFileType_MP3,
- VideoEditClasses_kFileType_PCM,
- VideoEditClasses_kFileType_JPG,
- VideoEditClasses_kFileType_BMP,
- VideoEditClasses_kFileType_GIF,
- VideoEditClasses_kFileType_PNG,
- VideoEditClasses_kFileType_ARGB8888,
- VideoEditClasses_kFileType_M4V,
- VideoEditClasses_kFileType_Unsupported
-} VideoEditClasses_FileType;
-
-/*
- * Alpha magic transition structure
- */
-typedef struct
-{
- jfieldID file;
- jfieldID blendingPercent;
- jfieldID invertRotation;
- jfieldID rgbWidth;
- jfieldID rgbHeight;
-} VideoEditJava_AlphaMagicFieldIds;
-
-typedef struct
-{
- jfieldID file;
- jfieldID fileType;
- jfieldID insertionTime;
- jfieldID volumePercent;
- jfieldID beginLoop;
- jfieldID endLoop;
- jfieldID enableDucking;
- jfieldID duckingThreshold;
- jfieldID lowVolume;
- jfieldID isLooping;
-} VideoEditJava_BackgroundMusicFieldIds;
-/*
- * Structure to hold media properties from native layer
- */
-typedef struct {
- M4OSA_UInt32 uiClipDuration;
- VideoEditClasses_FileType FileType;
- M4VIDEOEDITING_VideoFormat VideoStreamType;
- M4OSA_UInt32 uiClipVideoDuration;
- M4OSA_UInt32 uiVideoBitrate;
- M4OSA_UInt32 uiVideoWidth;
- M4OSA_UInt32 uiVideoHeight;
- M4OSA_Float fAverageFrameRate;
- M4OSA_UInt32 uiVideoProfile; /**< H263 or MPEG-4 or H264 profile(from core decoder) */
- M4OSA_UInt32 uiVideoLevel; /**< H263 or MPEG-4 or H264 level*/
- M4OSA_Bool bProfileSupported;
- M4OSA_Bool bLevelSupported;
- M4VIDEOEDITING_AudioFormat AudioStreamType;
- M4OSA_UInt32 uiClipAudioDuration;
- M4OSA_UInt32 uiAudioBitrate;
- M4OSA_UInt32 uiNbChannels;
- M4OSA_UInt32 uiSamplingFrequency;
- M4OSA_UInt32 uiRotation;
-} VideoEditPropClass_Properties;
-
-typedef struct
-{
- jfieldID duration;
- jfieldID fileType;
- jfieldID videoFormat;
- jfieldID videoDuration;
- jfieldID videoBitrate;
- jfieldID width;
- jfieldID height;
- jfieldID averageFrameRate;
- jfieldID profile;
- jfieldID level;
- jfieldID profileSupported;
- jfieldID levelSupported;
- jfieldID audioFormat;
- jfieldID audioDuration;
- jfieldID audioBitrate;
- jfieldID audioChannels;
- jfieldID audioSamplingFrequency;
- jfieldID videoRotation;
-} VideoEditJava_PropertiesFieldIds;
-
-
-typedef struct
-{
- jfieldID clipPath;
- jfieldID fileType;
- jfieldID beginCutTime;
- jfieldID endCutTime;
- jfieldID beginCutPercent;
- jfieldID endCutPercent;
- jfieldID panZoomEnabled;
- jfieldID panZoomPercentStart;
- jfieldID panZoomTopLeftXStart;
- jfieldID panZoomTopLeftYStart;
- jfieldID panZoomPercentEnd;
- jfieldID panZoomTopLeftXEnd;
- jfieldID panZoomTopLeftYEnd;
- jfieldID mediaRendering;
- jfieldID rgbFileWidth;
- jfieldID rgbFileHeight;
- jfieldID rotationDegree;
-} VideoEditJava_ClipSettingsFieldIds;
-
-typedef struct
-{
- jfieldID clipSettingsArray;
- jfieldID transitionSettingsArray;
- jfieldID effectSettingsArray;
- jfieldID videoFrameRate;
- jfieldID outputFile;
- jfieldID videoFrameSize;
- jfieldID videoFormat;
- jfieldID videoProfile;
- jfieldID videoLevel;
- jfieldID audioFormat;
- jfieldID audioSamplingFreq;
- jfieldID maxFileSize;
- jfieldID audioChannels;
- jfieldID videoBitrate;
- jfieldID audioBitrate;
- jfieldID backgroundMusicSettings;
- jfieldID primaryTrackVolume;
-} VideoEditJava_EditSettingsFieldIds;
-
-
-typedef struct
-{
- jfieldID startTime;
- jfieldID duration;
- jfieldID videoEffectType;
- jfieldID audioEffectType;
- jfieldID startPercent;
- jfieldID durationPercent;
- jfieldID framingFile;
- jfieldID framingBuffer;
- jfieldID bitmapType;
- jfieldID width;
- jfieldID height;
- jfieldID topLeftX;
- jfieldID topLeftY;
- jfieldID framingResize;
- jfieldID framingScaledSize;
- jfieldID text;
- jfieldID textRenderingData;
- jfieldID textBufferWidth;
- jfieldID textBufferHeight;
- jfieldID fiftiesFrameRate;
- jfieldID rgb16InputColor;
- jfieldID alphaBlendingStartPercent;
- jfieldID alphaBlendingMiddlePercent;
- jfieldID alphaBlendingEndPercent;
- jfieldID alphaBlendingFadeInTimePercent;
- jfieldID alphaBlendingFadeOutTimePercent;
-} VideoEditJava_EffectSettingsFieldIds;
-
-typedef struct
-{
- jfieldID context;
-} VideoEditJava_EngineFieldIds;
-
-typedef struct
-{
- jfieldID direction;
-} VideoEditJava_SlideTransitionSettingsFieldIds;
-
-typedef struct
-{
- jfieldID duration;
- jfieldID videoTransitionType;
- jfieldID audioTransitionType;
- jfieldID transitionBehaviour;
- jfieldID alphaSettings;
- jfieldID slideSettings;
-} VideoEditJava_TransitionSettingsFieldIds;
-
-typedef struct
-{
- jfieldID major;
- jfieldID minor;
- jfieldID revision;
-} VideoEditJava_VersionFieldIds;
-
-
-typedef struct
-{
- jmethodID onProgressUpdate;
-} VideoEditJava_EngineMethodIds;
-
-
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(AudioEffect )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(AudioFormat )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(AudioSamplingFrequency)
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(AudioTransition )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(Bitrate )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(Engine )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(Error )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(FileType )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(MediaRendering )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(SlideDirection )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(TransitionBehaviour )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoEffect )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoFormat )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoFrameRate )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoFrameSize )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoProfile )
-VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(VideoTransition )
-
-
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(AlphaMagic )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(BackgroundMusic )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(ClipSettings )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(ClipSettings )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(EditSettings )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(EffectSettings )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(Engine )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(SlideTransitionSettings )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(TransitionSettings )
-VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(Version )
-
-VIDEOEDIT_JAVA_DECLARE_METHOD_CLASS(Engine )
-
-/*
- * Init all Edit settings related structures
- */
-void
-videoEditClasses_init(
- bool* pResult,
- JNIEnv* pEnv);
-/**
- ************************************************************************
- * @brief Media Properties init function.
- * @param pResult (OUT) Pointer to hold result
- * @param pEnv (IN) JVM Interface pointer
- ************************************************************************
-*/
-void
-videoEditPropClass_init(
- bool* pResult,
- JNIEnv* pEnv);
-/**
- ************************************************************************
- * @brief Interface to populate Media Properties.
- * @param pResult (IN/OUT) Pointer to hold result
- * @param pEnv (IN) JVM Interface pointer
- * @param pProperties (IN) Media propeties structure pointer
- * @param pObject (OUT) Java object to hold media
- * properties for java layer.
- ************************************************************************
-*/
-void
-videoEditPropClass_createProperties(
- bool* pResult,
- JNIEnv* pEnv,
- VideoEditPropClass_Properties* pProperties,
- jobject* pObject);
-
-/**
- ************************************************************************
- * @brief Interface to log/display media properties.
- * @param pProperties (IN) Pointer holding media properties
- * @param indentation (IN) Indentation to follow in display
- ************************************************************************
-*/
-void
-videoEditPropClass_logProperties(
- VideoEditPropClass_Properties* pProperties,
- int indentation);
-
-/*
- * Get alpha magic transition settings
- */
-void
-videoEditClasses_getAlphaMagicSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4xVSS_AlphaMagicSettings** ppSettings);
-
-/*
- * Free alpha magic transition settings structure
- */
-void
-videoEditClasses_freeAlphaMagicSettings(
- M4xVSS_AlphaMagicSettings** ppSettings);
-
-/*
- * Log alpha magic transition settings
- */
-void
-videoEditClasses_logAlphaMagicSettings(
- M4xVSS_AlphaMagicSettings* pSettings,
- int indentation);
-
-/*
- * Get Background Track settings
- */
-void
-videoEditClasses_getBackgroundMusicSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4xVSS_BGMSettings** ppSettings);
-
-/*
- * Free Background Track settings structure
- */
-void
-videoEditClasses_freeBackgroundMusicSettings(
- M4xVSS_BGMSettings** ppSettings);
-
-/*
- * Log Background Track settings
- */
-void
-videoEditClasses_logBackgroundMusicSettings(
- M4xVSS_BGMSettings* pSettings,
- int indentation);
-
-/*
- * Log clip properties
- */
-void
-videoEditClasses_logClipProperties(
- M4VIDEOEDITING_ClipProperties* pProperties,
- int indentation);
-
-/*
- * Get clip settings from Java
- */
-void
-videoEditClasses_getClipSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_ClipSettings** ppSettings);
-/**
- ************************************************************************
- * @brief Interface function to retrieve media properties for a given
- * file.
- * @param pEnv (IN) Pointer holding media properties
- * @param thiz (IN) Indentation to follow in display
- * @param file (IN) File path for which media properties has
- * to be retrieved.
- ************************************************************************
-*/
-jobject
-videoEditProp_getProperties(
- JNIEnv* pEnv,
- jobject thiz,
- jstring file);
-
-/*
- * Create/Set the clip settings to java Object
- */
-void
-videoEditClasses_createClipSettings(
- bool* pResult,
- JNIEnv* pEnv,
- M4VSS3GPP_ClipSettings* pSettings,
- jobject* pObject);
-
-/*
- * Free clip settings structure
- */
-void
-videoEditClasses_freeClipSettings(
- M4VSS3GPP_ClipSettings** ppSettings);
-
-/*
- * Log clip settings structure
- */
-void
-videoEditClasses_logClipSettings(
- M4VSS3GPP_ClipSettings* pSettings,
- int indentation);
-
-/*
- * Get Edit settings from Java
- */
-void
-videoEditClasses_getEditSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_EditSettings** ppSettings,
- bool flag);
-
-/*
- * Free Edit Settings structure
- */
-void
-videoEditClasses_freeEditSettings(
- M4VSS3GPP_EditSettings** ppSettings);
-
-/*
- * Log Edit settings structure
- */
-void
-videoEditClasses_logEditSettings(
- M4VSS3GPP_EditSettings* pSettings,
- int indentation);
-
-/*
- * Get Effect settings from Java
- */
-void
-videoEditClasses_getEffectSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_EffectSettings* pSettings);
-
-/*
- * Free Effect settings structure
- */
-void
-videoEditClasses_freeEffectSettings(
- M4VSS3GPP_EffectSettings* pSettings);
-
-/*
- * Log Effect settings
- */
-void
-videoEditClasses_logEffectSettings(
- M4VSS3GPP_EffectSettings* pSettings,
- int indentation);
-
-/*
- * Get Transition-Sliding settings from Java
- */
-void
-videoEditClasses_getSlideTransitionSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4xVSS_SlideTransitionSettings** ppSettings);
-
-/*
- * Free Transition-Sliding structure
- */
-void
-videoEditClasses_freeSlideTransitionSettings(
- M4xVSS_SlideTransitionSettings** ppSettings);
-
-/*
- * Free Transition-Sliding structure
- */
-void
-videoEditClasses_logSlideTransitionSettings(
- M4xVSS_SlideTransitionSettings* pSettings,
- int indentation);
-
-/*
- * Get Transition settings from Java
- */
-void
-videoEditClasses_getTransitionSettings(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_TransitionSettings** ppSettings);
-
-/*
- * Free Transition settings structure
- */
-void
-videoEditClasses_freeTransitionSettings(
- M4VSS3GPP_TransitionSettings** ppSettings);
-
-/*
- * Log Transition settings
- */
-void
-videoEditClasses_logTransitionSettings(
- M4VSS3GPP_TransitionSettings* pSettings,
- int indentation);
-
-/*
- * Set version information to Java object
- */
-void
-videoEditClasses_createVersion(
- bool* pResult,
- JNIEnv* pEnv,
- M4_VersionInfo* pVersionInfo,
- jobject* pObject);
-
-/*
- * Log Version information
- */
-void
-videoEditClasses_logVersion(
- M4_VersionInfo* pVersionInfo,
- int indentation);
-
-
-void*
-videoEditClasses_getContext(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object);
-
-void
-videoEditClasses_setContext(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- void* pContext);
-
-
-#endif // VIDEO_EDITOR_CLASSES_H
-
diff --git a/media/jni/mediaeditor/VideoEditorJava.cpp b/media/jni/mediaeditor/VideoEditorJava.cpp
deleted file mode 100644
index fde0fb5..0000000
--- a/media/jni/mediaeditor/VideoEditorJava.cpp
+++ /dev/null
@@ -1,901 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VideoEditorJava"
-
-#include <VideoEditorClasses.h>
-#include <VideoEditorJava.h>
-#include <VideoEditorLogging.h>
-#include <VideoEditorOsal.h>
-
-extern "C" {
-#include <M4OSA_CharStar.h>
-};
-
-
-void
-videoEditJava_checkAndThrowIllegalArgumentExceptionFunc(
- bool* pResult,
- JNIEnv* pEnv,
- bool condition,
- const char* pMessage,
- const char* pFile,
- int lineNo)
-{
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Check if the condition is true.
- if (condition)
- {
- // Log the exception.
- VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",\
- "videoEditJava_checkAndThrowIllegalArgumentException, %s (%s:%d)",
- pMessage, pFile, lineNo);
-
- // Reset the result flag.
- (*pResult) = false;
-
- // Throw an exception.
- jniThrowException(pEnv, "java/lang/IllegalArgumentException", pMessage);
- }
- }
-}
-
-void
-videoEditJava_checkAndThrowRuntimeExceptionFunc(
- bool* pResult,
- JNIEnv* pEnv,
- bool condition,
- M4OSA_ERR result,
- const char* pFile,
- int lineNo
- )
-{
- const char* pMessage = NULL;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Check if the condition is true.
- if (condition)
- {
- // Get the error string.
- pMessage = videoEditJava_getErrorName(result);
-
- // Log the exception.
- VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
- "videoEditJava_checkAndThrowRuntimeException, %s (%s:%d)",
- pMessage, pFile, lineNo);
-
- // Reset the result flag.
- (*pResult) = false;
-
- // Throw an exception.
- jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
- }
- }
-}
-
-void
-videoEditJava_checkAndThrowIllegalStateExceptionFunc(
- bool* pResult,
- JNIEnv* pEnv,
- bool condition,
- const char* pMessage,
- const char* pFile,
- int lineNo
- )
-{
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Check if the condition is true.
- if (condition)
- {
- // Log the exception.
- VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
- "videoEditJava_checkAndThrowIllegalStateException, %s (%s:%d)",
- pMessage, pFile, lineNo);
-
- // Reset the result flag.
- (*pResult) = false;
-
- // Throw an exception.
- jniThrowException(pEnv, "java/lang/IllegalStateException", pMessage);
- }
- }
-}
-
-void
-videoEditJava_getClass(
- bool* pResult,
- JNIEnv* pEnv,
- const char* pName,
- jclass* pClazz)
-{
- // Only look for the class if locating the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getClass(%s)", pName);
-
- // Look up the class.
- jclass clazz = pEnv->FindClass(pName);
-
- // Clear any resulting exceptions.
- pEnv->ExceptionClear();
-
- // Check if the class could be located.
- if (NULL != clazz)
- {
- // Return the class.
- (*pClazz) = clazz;
- }
- else
- {
- // Reset the result flag.
- (*pResult) = false;
-
- // Log the error.
- VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getClass, error: unable to locate class %s", pName);
-
- // Throw an exception.
- jniThrowException(pEnv, "java/lang/ClassNotFoundException",
- "unable to locate class");
- }
- }
-}
-
-void
-videoEditJava_getMethodId(
- bool* pResult,
- JNIEnv* pEnv,
- jclass clazz,
- const char* pName,
- const char* pType,
- jmethodID* pMethodId)
-{
- // Only look for the class if locating the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getMethodId(%s,%s)", pName, pType);
-
- // Look up the method id.
- jmethodID methodId = pEnv->GetMethodID(clazz, pName, pType);
-
- // Clear any resulting exceptions.
- pEnv->ExceptionClear();
-
- // Check if the method could be located.
- if (NULL != methodId)
- {
- // Return the method id.
- (*pMethodId) = methodId;
- }
- else
- {
- // Reset the result flag.
- (*pResult) = false;
-
- // Log the error.
- VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getMethodId, error: unable to locate method %s with type %s",
- pName, pType);
-
- // Throw an exception.
- jniThrowException(pEnv, "java/lang/NoSuchMethodException", "unable to locate method");
- }
- }
-}
-
-void
-videoEditJava_getFieldId(
- bool* pResult,
- JNIEnv* pEnv,
- jclass clazz,
- const char* pName,
- const char* pType,
- jfieldID* pFieldId)
-{
- // Only look for the class if locating the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getFieldId(%s,%s)", pName, pType);
-
- // Look up the field id.
- jfieldID fieldId = pEnv->GetFieldID(clazz, pName, pType);
-
- // Clear any resulting exceptions.
- pEnv->ExceptionClear();
-
- // Check if the field could be located.
- if (NULL != fieldId)
- {
- // Return the field id.
- (*pFieldId) = fieldId;
- }
- else
- {
- // Reset the result flag.
- (*pResult) = false;
-
- // Log the error.
- VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getFieldId, error: unable to locate field %s with type %s",
- pName, pType);
-
- // Throw an exception.
- jniThrowException(pEnv, "java/lang/NoSuchFieldException", "unable to locate field");
- }
- }
-}
-
-void
-videoEditJava_getObject(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- jfieldID objectFieldId,
- jobject* pObject)
-{
- // Only retrieve the array object and size if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getObject()");
-
- // Retrieve the object.
- (*pObject) = pEnv->GetObjectField(object, objectFieldId);
-
- // Clear any resulting exceptions.
- pEnv->ExceptionClear();
- }
-}
-
-void
-videoEditJava_getArray(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- jfieldID arrayFieldId,
- jobjectArray* pArray,
- jsize* pArraySize)
-{
- // Only retrieve the array object and size if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA", "videoEditJava_getArray()");
-
- // Retrieve the array object.
- jobjectArray array = (jobjectArray)pEnv->GetObjectField(object, arrayFieldId);
- jsize arraySize = 0;
-
- // Clear any resulting exceptions.
- pEnv->ExceptionClear();
-
- // Check if the array could be retrieved.
- if (NULL != array)
- {
- // Retrieve the array size.
- arraySize = pEnv->GetArrayLength(array);
- }
-
- // Return the array and its size.
- (*pArray) = array;
- (*pArraySize) = arraySize;
- }
-}
-
-void*
-videoEditJava_getString(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- jfieldID stringFieldId,
- M4OSA_UInt32* pLength)
-{
- void* pString = M4OSA_NULL;
- jstring string = NULL;
- M4OSA_UInt32 length = 0;
- M4OSA_Char* pLocal = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA", "videoEditJava_getString()");
-
- // Check if an object containing a string was specified.
- if (NULL != stringFieldId)
- {
- // Retrieve the string object.
- string = (jstring)pEnv->GetObjectField(object, stringFieldId);
-
- // Clear any resulting exceptions.
- pEnv->ExceptionClear();
- }
- else
- {
- // The string itself was specified.
- string = (jstring)object;
- }
-
- // Check if the string could be retrieved.
- if (NULL != string)
- {
- // Get a local copy of the string.
- pLocal = (M4OSA_Char*)pEnv->GetStringUTFChars(string, M4OSA_NULL);
- if (M4OSA_NULL != pLocal)
- {
- // Determine the length of the path
- // (add one extra character for the zero terminator).
- length = strlen((const char *)pLocal) + 1;
-
- // Allocate memory for the string.
- pString = videoEditOsal_alloc(pResult, pEnv, length, "String");
- if (*pResult)
- {
- // Copy the string.
- result = M4OSA_chrNCopy((M4OSA_Char*)pString, pLocal, length);
-
- // Check if the copy succeeded.
- videoEditJava_checkAndThrowRuntimeException(pResult, pEnv,
- (M4NO_ERROR != result), result);
-
- // Check if the string could not be copied.
- if (!(*pResult))
- {
- // Free the allocated memory.
- videoEditOsal_free(pString);
- pString = M4OSA_NULL;
- }
- }
-
- // Release the local copy of the string.
- pEnv->ReleaseStringUTFChars(string, (const char *)pLocal);
- }
- }
-
- // Check if the string was empty or could be copied.
- if (*pResult)
- {
- // Check if the length was requested.
- if (M4OSA_NULL != pLength)
- {
- // Return the length.
- (*pLength) = length;
- }
- }
-
- // Delete local references to avoid memory leaks
- pEnv->DeleteLocalRef(string);
- }
-
- // Return the string.
- return(pString);
-}
-
-void
-videoEditJava_getStaticIntField(
- bool* pResult,
- JNIEnv* pEnv,
- jclass clazz,
- const char* pName,
- int* pValue)
-{
- // Only look for the class if locating the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getStaticIntField(%s)", pName);
-
- // Look up the field id.
- jfieldID fieldId = pEnv->GetStaticFieldID(clazz, pName, "I");
-
- // Clear any resulting exceptions.
- pEnv->ExceptionClear();
-
- // Check if the field could be located.
- if (NULL != fieldId)
- {
- // Retrieve the field value.
- (*pValue) = pEnv->GetStaticIntField(clazz, fieldId);
-
- // Log the value.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getStaticIntField, %s = %d", pName, (*pValue));
- }
- else
- {
- // Reset the result flag.
- (*pResult) = false;
-
- // Log the error.
- VIDEOEDIT_LOG_EXCEPTION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_JAVA",
- "videoEditJava_getStaticIntField, error: unable to locate field %s", pName);
-
- // Throw an exception.
- jniThrowException(pEnv, "java/lang/NoSuchFieldException",
- "unable to locate static field");
- }
- }
-}
-
-void
-videoEditJava_initConstantClass(
- bool* pResult,
- JNIEnv* pEnv,
- VideoEditJava_ConstantsClass* pClass)
-{
- bool gotten = true;
- jclass clazz = NULL;
- int index = 0;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_initConstantClass(%s)", pClass->pName);
-
- // Only initialize the class once.
- if (!pClass->initialized)
- {
- // Look up the class.
- videoEditJava_getClass(pResult, pEnv, pClass->pName, &clazz);
-
- // Loop over the constants.
- for (index = 0; index < pClass->count; index++)
- {
- // Look up the constant.
- videoEditJava_getStaticIntField(pResult, pEnv, clazz,
- pClass->pConstants[index].pName,
- &pClass->pConstants[index].java);
- }
-
- // Check if all constants could be located.
- if (*pResult)
- {
- // Set the initialized flag.
- pClass->initialized = true;
- }
- }
- }
-}
-
-const char*
-videoEditJava_getConstantClassName(
- const VideoEditJava_ConstantsClass* pClass,
- int value,
- VideoEditJava_UnknownConstant unknown)
-{
- const char* pName = M4OSA_NULL;
- int index = 0;
-
- // Loop over the list with constants.
- for (index = 0;
- ((M4OSA_NULL == pName) && (index < pClass->count));
- index++)
- {
- // Check if the specified value matches the c value of the constant.
- if (value == pClass->pConstants[index].c)
- {
- // Set the name.
- pName = pClass->pConstants[index].pName;
- }
- }
-
- // Check if no constant was found.
- if (M4OSA_NULL == pName)
- {
- // Check if a function was specified to handle this case.
- if (M4OSA_NULL != unknown)
- {
- // Pass the constant to the specified unknown function.
- pName = unknown(value);
- }
- else
- {
- // Set the description to a default value.
- pName = "<unknown>";
- }
- }
-
- // Return the result.
- return(pName);
-}
-
-const char*
-videoEditJava_getConstantClassString(
- const VideoEditJava_ConstantsClass* pClass,
- int value,
- VideoEditJava_UnknownConstant unknown)
-{
- const char* pString = M4OSA_NULL;
- int index = 0;
-
- // Loop over the list with constants.
- for (index = 0;
- ((M4OSA_NULL == pString) && (index < pClass->count));
- index++)
- {
- // Check if the specified value matches the c value of the constant.
- if (value == pClass->pConstants[index].c)
- {
- // Set the description.
- pString = pClass->pConstants[index].pDescription;
- }
- }
-
- // Check if no constant was found.
- if (M4OSA_NULL == pString)
- {
- // Check if a function was specified to handle this case.
- if (M4OSA_NULL != unknown)
- {
- // Pass the constant to the specified unknown function.
- pString = unknown(value);
- }
- else
- {
- // Set the description to a default value.
- pString = "<unknown>";
- }
- }
-
- // Return the result.
- return(pString);
-}
-
-int
-videoEditJava_getConstantClassJavaToC(
- bool* pResult,
- const VideoEditJava_ConstantsClass* pClass,
- int value)
-{
- bool gotten = false;
- int index = 0;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Loop over the list with constants.
- for (index = 0; ((!gotten) && (index < pClass->count)); index++)
- {
- // Check if the specified value matches the java value of the constant.
- if (value == pClass->pConstants[index].java)
- {
- // Set the value to the c value.
- value = pClass->pConstants[index].c;
-
- // Set the gotten flag.
- gotten = true;
- }
- }
-
- // Check if the value was not found.
- if (!gotten)
- {
- (*pResult) = false;
- }
- }
-
- // Return the translated value.
- return(value);
-}
-
-int
-videoEditJava_getConstantClassJavaToC(
- bool* pResult,
- const VideoEditJava_ConstantsClass* pClass,
- int value,
- int unknown)
-{
- bool gotten = false;
- int index = 0;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Loop over the list with constants.
- for (index = 0; ((!gotten) && (index < pClass->count)); index++)
- {
- // Check if the specified value matches the java value of the constant.
- if (value == pClass->pConstants[index].java)
- {
- // Set the value to the c value.
- value = pClass->pConstants[index].c;
-
- // Set the gotten flag.
- gotten = true;
- }
- }
-
- // If the constant was not found, look for the specified unknown.
- if (!gotten)
- {
- // Set the value to the c value.
- value = unknown;
- }
- }
-
- // Return the translated value.
- return(value);
-}
-
-int
-videoEditJava_getConstantClassCToJava(
- const VideoEditJava_ConstantsClass* pClass,
- int value)
-{
- bool gotten = false;
- int index = 0;
-
- // Loop over the list with constants.
- for (index = 0; ((!gotten) && (index < pClass->count)); index++)
- {
- // Check if the specified value matches the c value of the constant.
- if (value == pClass->pConstants[index].c)
- {
- // Set the value to the java value.
- value = pClass->pConstants[index].java;
-
- // Set the gotten flag.
- gotten = true;
- }
- }
-
- // Return the translated value.
- return(value);
-}
-
-int
-videoEditJava_getConstantClassCToJava(
- const VideoEditJava_ConstantsClass* pClass,
- int value,
- int unknown)
-{
- bool gotten = false;
- int index = 0;
-
- // Loop over the list with constants.
- for (index = 0; ((!gotten) && (index < pClass->count)); index++)
- {
- // Check if the specified value matches the c value of the constant.
- if (value == pClass->pConstants[index].c)
- {
- // Set the value to the java value.
- value = pClass->pConstants[index].java;
-
- // Set the gotten flag.
- gotten = true;
- }
- }
-
- // If the constant was not found, look for the specified unknown.
- if (!gotten)
- {
- // Loop over the list with constants.
- for (index = 0; ((!gotten) && (index < pClass->count)); index++)
- {
- // Check if the specified value matches the java value of the constant.
- if (unknown == pClass->pConstants[index].c)
- {
- // Set the value to the c value.
- value = pClass->pConstants[index].java;
-
- // Set the gotten flag.
- gotten = true;
- }
- }
- }
-
- // Return the translated value.
- return(value);
-}
-
-void
-videoEditJava_initFieldClass(
- bool* pResult,
- JNIEnv* pEnv,
- VideoEditJava_FieldsClass* pClass)
-{
- bool gotten = true;
- jclass clazz = NULL;
- int index = 0;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_initFieldClass(%s)", pClass->pName);
-
- // Only initialize the class once.
- if (!pClass->initialized)
- {
- // Look up the class.
- videoEditJava_getClass(pResult, pEnv, pClass->pName, &clazz);
-
- // Loop over the fields.
- for (index = 0; index < pClass->count; index++)
- {
- // Look up the field id.
- videoEditJava_getFieldId(
- pResult,
- pEnv,
- clazz,
- pClass->pFields[index].pName,
- pClass->pFields[index].pType,
- &pClass->pFields[index].fieldId);
- }
-
- // Check if all fields could be located.
- if (*pResult)
- {
- // Set the initialized flag.
- pClass->initialized = true;
- }
- }
- }
-}
-
-void
-videoEditJava_fieldClassClass(
- bool* pResult,
- JNIEnv* pEnv,
- const VideoEditJava_FieldsClass* pClass,
- jclass* pClazz)
-{
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Check if the class is initialized.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, (!pClass->initialized),
- "field class not initialized");
-
- // Get the class.
- videoEditJava_getClass(pResult, pEnv, pClass->pName, pClazz);
- }
-}
-
-void
-videoEditJava_fieldClassFieldIds(
- bool* pResult,
- JNIEnv* pEnv,
- const VideoEditJava_FieldsClass* pClass,
- int count,
- VideoEditJava_FieldIds* pIds)
-{
- int index = 0;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Check if the class is initialized.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, (!pClass->initialized),
- "field class not initialized");
-
- // Check if the number of fields matches.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,
- (pClass->count != count),
- "field class type mismatch");
-
- // Check if the class and object are valid.
- if (*pResult)
- {
- // Loop over the class fields.
- for (index = 0; index < count; index++)
- {
- // Copy the field ids.
- pIds->fieldIds[index] = pClass->pFields[index].fieldId;
- }
- }
- }
-}
-
-void
-videoEditJava_initMethodClass(
- bool* pResult,
- JNIEnv* pEnv,
- VideoEditJava_MethodsClass* pClass)
-{
- bool gotten = true;
- jclass clazz = NULL;
- int index = 0;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Log the function call.
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_JAVA",
- "videoEditJava_initMethodClass(%s)", pClass->pName);
-
- // Only initialize the class once.
- if (!pClass->initialized)
- {
- // Look up the class.
- videoEditJava_getClass(pResult, pEnv, pClass->pName, &clazz);
-
- // Loop over the methods.
- for (index = 0; index < pClass->count; index++)
- {
- // Look up the method id.
- videoEditJava_getMethodId(
- pResult,
- pEnv,
- clazz,
- pClass->pMethods[index].pName,
- pClass->pMethods[index].pType,
- &pClass->pMethods[index].methodId);
- }
-
- // Check if all methods could be located.
- if (*pResult)
- {
- // Set the initialized flag.
- pClass->initialized = true;
- }
- }
- }
-}
-
-void
-videoEditJava_methodClassMethodIds(
- bool* pResult,
- JNIEnv* pEnv,
- const VideoEditJava_MethodsClass* pClass,
- int count,
- VideoEditJava_MethodIds* pIds)
-{
- int index = 0;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Check if the class is initialized.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv, (!pClass->initialized),
- "method class not initialized");
-
- // Check if the number of methods matches.
- videoEditJava_checkAndThrowIllegalArgumentException(pResult, pEnv,\
- (pClass->count != count),
- "method class type mismatch");
-
- // Check if the class and object are valid.
- if (*pResult)
- {
- // Loop over the class methods.
- for (index = 0; index < count; index++)
- {
- // Copy the method ids.
- pIds->methodIds[index] = pClass->pMethods[index].methodId;
- }
- }
- }
-}
-
diff --git a/media/jni/mediaeditor/VideoEditorJava.h b/media/jni/mediaeditor/VideoEditorJava.h
deleted file mode 100644
index 0a2db08..0000000
--- a/media/jni/mediaeditor/VideoEditorJava.h
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VIDEO_EDiTOR_JAVA_H
-#define VIDEO_EDiTOR_JAVA_H
-
-#include <jni.h>
-#include <JNIHelp.h>
-
-/**
- ************************************************************************
- * @file VideoEditorJava.h
- * @brief Interface for JNI methods that have specific access to
- * class, objects and method Ids defined in Java layer
- ************************************************************************
-*/
-
-extern "C" {
-#include <M4OSA_Types.h>
-#include <M4OSA_Error.h>
-}
-
-#define VIDEOEDIT_JAVA_CONSTANT_INIT(m_name, m_c) \
- { m_name, \
- 0, \
- m_c, \
- #m_c }
-
-#define VIDEOEDIT_JAVA_DEFINE_CONSTANTS(m_class) \
-static \
-VideoEditJava_Constant g##m_class##Constants [] =
-
-#define VIDEOEDIT_JAVA_DEFINE_CONSTANT_CLASS( \
- m_class, \
- m_name, \
- m_unknownName, \
- m_unknownString) \
- \
-static VideoEditJava_ConstantsClass g##m_class##ConstantsClass = \
-{ m_name, \
- &g##m_class##Constants[0], \
- (sizeof(g##m_class##Constants) / sizeof(VideoEditJava_Constant)), \
- false \
-}; \
- \
- \
-void videoEditJava_init##m_class##Constants( \
- bool* pResult, \
- JNIEnv* pEnv) \
-{ \
- videoEditJava_initConstantClass( \
- pResult, \
- pEnv, \
- &g##m_class##ConstantsClass); \
-} \
- \
-const char* videoEditJava_get##m_class##Name( \
- int value) \
-{ \
- return(videoEditJava_getConstantClassName( \
- &g##m_class##ConstantsClass, \
- value, \
- m_unknownName)); \
-} \
- \
-const char* videoEditJava_get##m_class##String( \
- int value) \
-{ \
- return(videoEditJava_getConstantClassString( \
- &g##m_class##ConstantsClass, \
- value, \
- m_unknownString)); \
-} \
- \
-int \
-videoEditJava_get##m_class##JavaToC( \
- bool* pResult, \
- int value) \
-{ \
- return(videoEditJava_getConstantClassJavaToC( \
- pResult, \
- &g##m_class##ConstantsClass, \
- value)); \
-} \
- \
-int \
-videoEditJava_get##m_class##JavaToC( \
- bool* pResult, \
- int value, \
- int unknown) \
-{ \
- return(videoEditJava_getConstantClassJavaToC( \
- pResult, \
- &g##m_class##ConstantsClass, \
- value, \
- unknown)); \
-} \
- \
-int \
-videoEditJava_get##m_class##CToJava( \
- int value) \
-{ \
- return(videoEditJava_getConstantClassCToJava( \
- &g##m_class##ConstantsClass, \
- value)); \
-} \
- \
-int \
-videoEditJava_get##m_class##CToJava( \
- int value, \
- int unknown) \
-{ \
- return(videoEditJava_getConstantClassCToJava( \
- &g##m_class##ConstantsClass, \
- value, \
- unknown)); \
-}
-
-
-#define VIDEOEDIT_JAVA_DECLARE_CONSTANT_CLASS(m_class) \
-void \
-videoEditJava_init##m_class##Constants( \
- bool* pResult, \
- JNIEnv* pEnv); \
- \
-const char* \
-videoEditJava_get##m_class##Name( \
- int value); \
- \
-const char* \
-videoEditJava_get##m_class##String( \
- int value); \
- \
-int \
-videoEditJava_get##m_class##JavaToC( \
- bool* pResult, \
- int value, \
- int unknown); \
- \
-int \
-videoEditJava_get##m_class##JavaToC( \
- bool* pResult, \
- int value); \
- \
-int \
-videoEditJava_get##m_class##CToJava( \
- int value); \
- \
-int \
-videoEditJava_get##m_class##CToJava( \
- int value, \
- int unknown);
-
-#define VIDEOEDIT_JAVA_FIELD_INIT(m_name, m_type) \
- { m_name, \
- m_type, \
- NULL }
-
-#define VIDEOEDIT_JAVA_DEFINE_FIELDS(m_class) \
-static \
-VideoEditJava_Field g##m_class##Fields [] =
-
-#define VIDEOEDIT_JAVA_DEFINE_FIELD_CLASS(m_class, m_name) \
-static VideoEditJava_FieldsClass g##m_class##FieldsClass = \
- { m_name, \
- &g##m_class##Fields[0], \
- (sizeof(g##m_class##Fields) / sizeof(VideoEditJava_Field)), \
- false }; \
- \
-void \
-videoEditJava_init##m_class##Fields( \
- bool* pResult, \
- JNIEnv* pEnv) \
-{ \
- videoEditJava_initFieldClass( \
- pResult, \
- pEnv, \
- &g##m_class##FieldsClass); \
-} \
- \
-void \
-videoEditJava_get##m_class##Class( \
- bool* pResult, \
- JNIEnv* pEnv, \
- jclass* pClazz) \
-{ \
- videoEditJava_fieldClassClass( \
- pResult, \
- pEnv, \
- &g##m_class##FieldsClass, \
- pClazz); \
-} \
- \
-void \
-videoEditJava_get##m_class##FieldIds( \
- bool* pResult, \
- JNIEnv* pEnv, \
- VideoEditJava_##m_class##FieldIds* pIds) \
-{ \
- videoEditJava_fieldClassFieldIds( \
- pResult, \
- pEnv, \
- &g##m_class##FieldsClass, \
- (sizeof(VideoEditJava_##m_class##FieldIds) / \
- sizeof(jfieldID)), \
- (VideoEditJava_FieldIds*)pIds); \
-}
-
-#define VIDEOEDIT_JAVA_DECLARE_FIELD_CLASS(m_class) \
-void \
-videoEditJava_init##m_class##Fields( \
- bool* pResult, \
- JNIEnv* pEnv); \
- \
-void \
-videoEditJava_get##m_class##Class( \
- bool* pResult, \
- JNIEnv* pEnv, \
- jclass* pClazz); \
- \
-void \
-videoEditJava_get##m_class##FieldIds( \
- bool* pResult, \
- JNIEnv* pEnv, \
- VideoEditJava_##m_class##FieldIds* pIds);
-
-
-#define VIDEOEDIT_JAVA_METHOD_INIT(m_name, m_type) \
- { m_name, \
- m_type, \
- NULL }
-
-#define VIDEOEDIT_JAVA_DEFINE_METHODS(m_class) \
-static \
-VideoEditJava_Method g##m_class##Methods [] =
-
-#define VIDEOEDIT_JAVA_DEFINE_METHOD_CLASS(m_class, m_name) \
-static VideoEditJava_MethodsClass g##m_class##MethodsClass = \
- { m_name, \
- &g##m_class##Methods[0], \
- (sizeof(g##m_class##Methods) / sizeof(VideoEditJava_Method)), \
- false }; \
- \
-void \
-videoEditJava_init##m_class##Methods( \
- bool* pResult, \
- JNIEnv* pEnv) \
-{ \
- videoEditJava_initMethodClass( \
- pResult, \
- pEnv, \
- &g##m_class##MethodsClass); \
-} \
- \
-void \
-videoEditJava_get##m_class##MethodIds( \
- bool* pResult, \
- JNIEnv* pEnv, \
- VideoEditJava_##m_class##MethodIds* pIds) \
-{ \
- videoEditJava_methodClassMethodIds( \
- pResult, \
- pEnv, \
- &g##m_class##MethodsClass, \
- (sizeof(VideoEditJava_##m_class##MethodIds) / \
- sizeof(jmethodID)), \
- (VideoEditJava_MethodIds*)pIds); \
-}
-
-#define VIDEOEDIT_JAVA_DECLARE_METHOD_CLASS(m_class) \
-void \
-videoEditJava_init##m_class##Methods( \
- bool* pResult, \
- JNIEnv* pEnv); \
- \
-void \
-videoEditJava_get##m_class##MethodIds( \
- bool* pResult, \
- JNIEnv* pEnv, \
- VideoEditJava_##m_class##MethodIds* pIds);
-
-
-typedef struct
-{
- const char* pName;
- int java;
- int c;
- const char* pDescription;
-} VideoEditJava_Constant;
-
-typedef struct
-{
- const char* pName;
- VideoEditJava_Constant* pConstants;
- int count;
- bool initialized;
-} VideoEditJava_ConstantsClass;
-
-typedef const char* (*VideoEditJava_UnknownConstant)(int constant);
-
-typedef struct
-{
- const char* pName;
- const char* pType;
- jfieldID fieldId;
-} VideoEditJava_Field;
-
-typedef struct
-{
- const char* pName;
- VideoEditJava_Field* pFields;
- int count;
- bool initialized;
-} VideoEditJava_FieldsClass;
-
-typedef struct
-{
- jfieldID fieldIds[];
-} VideoEditJava_FieldIds;
-
-typedef struct
-{
- const char* pName;
- const char* pType;
- jmethodID methodId;
-} VideoEditJava_Method;
-
-typedef struct
-{
- const char* pName;
- VideoEditJava_Method* pMethods;
- int count;
- bool initialized;
-} VideoEditJava_MethodsClass;
-
-typedef struct
-{
- jmethodID methodIds[];
-} VideoEditJava_MethodIds;
-
-#define videoEditJava_checkAndThrowIllegalArgumentException(\
- a, b, c, d) videoEditJava_checkAndThrowIllegalArgumentExceptionFunc(\
- a, b, c, d, __FILE__, __LINE__)
-
-#define videoEditJava_checkAndThrowRuntimeException(\
- a, b, c, d) videoEditJava_checkAndThrowRuntimeExceptionFunc(\
- a, b, c, d, __FILE__, __LINE__)
-
-#define videoEditJava_checkAndThrowIllegalStateException(\
- a, b, c, d) videoEditJava_checkAndThrowIllegalStateExceptionFunc(\
- a, b, c, d, __FILE__, __LINE__)
-
-void
-videoEditJava_checkAndThrowIllegalArgumentExceptionFunc(
- bool* pResult,
- JNIEnv* pEnv,
- bool condition,
- const char* pMessage,
- const char* pFile,
- int lineNo
- );
-
-void
-videoEditJava_checkAndThrowRuntimeExceptionFunc(
- bool* pResult,
- JNIEnv* pEnv,
- bool condition,
- M4OSA_ERR result,
- const char* pFile,
- int lineNo
- );
-
-void
-videoEditJava_checkAndThrowIllegalStateExceptionFunc(
- bool* pResult,
- JNIEnv* pEnv,
- bool condition,
- const char* pMessage,
- const char* pFile,
- int lineNo
- );
-
-void
-videoEditJava_getClass(
- bool* pResult,
- JNIEnv* pEnv,
- const char* pName,
- jclass* pClazz);
-
-void
-videoEditJava_getMethodId(
- bool* pResult,
- JNIEnv* pEnv,
- jclass clazz,
- const char* pName,
- const char* pType,
- jmethodID* pMethodId);
-
-void videoEditJava_getFieldId(
- bool* pResult,
- JNIEnv* pEnv,
- jclass clazz,
- const char* pName,
- const char* pType,
- jfieldID* pFieldId);
-
-void videoEditJava_getObject(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- jfieldID objectFieldId,
- jobject* pObject);
-
-void videoEditJava_getArray(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- jfieldID arrayFieldId,
- jobjectArray* pArray,
- jsize* pArraySize);
-
-void* videoEditJava_getString(
- bool* pResult,
- JNIEnv* pEnv,
- jobject object,
- jfieldID stringFieldId,
- M4OSA_UInt32* pLength);
-
-void videoEditJava_getStaticIntField(
- bool* pResult,
- JNIEnv* env,
- jclass clazz,
- const char* pName,
- int* pValue);
-
-void
-videoEditJava_initConstantClass(
- bool* pResult,
- JNIEnv* pEnv,
- VideoEditJava_ConstantsClass* pClass);
-
-const char*
-videoEditJava_getConstantClassName(
- const VideoEditJava_ConstantsClass* pClass,
- int value,
- VideoEditJava_UnknownConstant unknown);
-
-const char*
-videoEditJava_getConstantClassString(
- const VideoEditJava_ConstantsClass* pClass,
- int value,
- VideoEditJava_UnknownConstant unknown);
-
-int
-videoEditJava_getConstantClassJavaToC(
- bool* pResult,
- const VideoEditJava_ConstantsClass* pClass,
- int value);
-
-int
-videoEditJava_getConstantClassJavaToC(
- bool* pResult,
- const VideoEditJava_ConstantsClass* pClass,
- int value,
- int unknown);
-
-int
-videoEditJava_getConstantClassCToJava(
- const VideoEditJava_ConstantsClass* pClass,
- int value);
-
-int
-videoEditJava_getConstantClassCToJava(
- const VideoEditJava_ConstantsClass* pClass,
- int value,
- int unknown);
-
-void
-videoEditJava_initFieldClass(
- bool* pResult,
- JNIEnv* pEnv,
- VideoEditJava_FieldsClass* pClass);
-
-void
-videoEditJava_fieldClassClass(
- bool* pResult,
- JNIEnv* pEnv,
- const VideoEditJava_FieldsClass* pClass,
- jclass* pClazz);
-
-void
-videoEditJava_fieldClassFieldIds(
- bool* pResult,
- JNIEnv* pEnv,
- const VideoEditJava_FieldsClass* pClass,
- int count,
- VideoEditJava_FieldIds* pIds);
-
-void
-videoEditJava_initMethodClass(
- bool* pResult,
- JNIEnv* pEnv,
- VideoEditJava_MethodsClass* pClass);
-
-void
-videoEditJava_methodClassMethodIds(
- bool* pResult,
- JNIEnv* pEnv,
- const VideoEditJava_MethodsClass* pClass,
- int count,
- VideoEditJava_MethodIds* pIds);
-
-#endif // VIDEO_EDiTOR_JAVA_H
-
diff --git a/media/jni/mediaeditor/VideoEditorLogging.h b/media/jni/mediaeditor/VideoEditorLogging.h
deleted file mode 100644
index 1f1228a..0000000
--- a/media/jni/mediaeditor/VideoEditorLogging.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VIDEO_EDITOR_LOGGING_H
-#define VIDEO_EDITOR_LOGGING_H
-
-#ifndef LOG_TAG
-#error "No LOG_TAG defined!"
-#endif
-
-/*
- * This file is used as a proxy for cutils/log.h. Include cutils/log.h here to
- * avoid relying on import ordering.
- */
-#include <cutils/log.h>
-
-//#define VIDEOEDIT_LOGGING_ENABLED
-
-#define VIDEOEDIT_LOG_INDENTATION (3)
-
-#define VIDEOEDIT_LOG_ERROR __android_log_print
-#define VIDEOEDIT_LOG_EXCEPTION __android_log_print
-
-#ifdef VIDEOEDIT_LOGGING_ENABLED
-
-#define VIDEOEDIT_LOG_ALLOCATION __android_log_print
-#define VIDEOEDIT_LOG_API __android_log_print
-#define VIDEOEDIT_LOG_FUNCTION __android_log_print
-#define VIDEOEDIT_LOG_RESULT(x,y, ...) ALOGI(y, __VA_ARGS__ )
-#define VIDEOEDIT_LOG_SETTING __android_log_print
-#define VIDEOEDIT_LOG_EDIT_SETTINGS(m_settings) videoEditClasses_logEditSettings\
- (m_settings, VIDEOEDIT_LOG_INDENTATION)
-#define VIDEOEDIT_PROP_LOG_PROPERTIES(m_properties) videoEditPropClass_logProperties\
- (m_properties, VIDEOEDIT_LOG_INDENTATION)
-#define VIDEOEDIT_PROP_LOG_RESULT __android_log_print
-
-#else
-
-#define VIDEOEDIT_LOG_ALLOCATION (void)
-#define VIDEOEDIT_LOG_API (void)
-#define VIDEOEDIT_LOG_FUNCTION (void)
-#define VIDEOEDIT_LOG_RESULT (void)
-#define VIDEOEDIT_LOG_SETTING (void)
-#define VIDEOEDIT_LOG_EDIT_SETTINGS(m_settings) (void)m_settings
-#define VIDEOEDIT_PROP_LOG_PROPERTIES(m_properties) (void)m_properties
-#define VIDEOEDIT_PROP_LOG_RESULT (void)
-
-#endif
-
-#endif // VIDEO_EDITOR_LOGGING_H
-
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
deleted file mode 100644
index 0894d74..0000000
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ /dev/null
@@ -1,3639 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_NDEBUG 1
-#define LOG_TAG "VideoEditorMain"
-#include <dlfcn.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <VideoEditorClasses.h>
-#include <VideoEditorJava.h>
-#include <VideoEditorOsal.h>
-#include <VideoEditorLogging.h>
-#include <VideoEditorClasses.h>
-#include <VideoEditorThumbnailMain.h>
-#include <M4OSA_Debug.h>
-#include <M4xVSS_Internal.h>
-#include <gui/Surface.h>
-#include "VideoEditorPreviewController.h"
-
-#include "VideoEditorMain.h"
-
-#include <android_runtime/android_view_Surface.h>
-
-extern "C" {
-#include <M4OSA_Clock.h>
-#include <M4OSA_CharStar.h>
-#include <M4OSA_Error.h>
-#include <M4OSA_FileCommon.h>
-#include <M4OSA_FileReader.h>
-#include <M4OSA_FileWriter.h>
-#include <M4OSA_Memory.h>
-#include <M4OSA_Thread.h>
-#include <M4xVSS_API.h>
-#include <M4VSS3GPP_ErrorCodes.h>
-#include <M4MCS_API.h>
-#include <M4MCS_ErrorCodes.h>
-#include <M4READER_Common.h>
-#include <M4WRITER_common.h>
-};
-
-
-using namespace android;
-
-#define THREAD_STACK_SIZE (65536)
-
-#define VIDEOEDITOR_VERSION_MAJOR 0
-#define VIDEOEDITOR_VERSION_MINOR 0
-#define VIDEOEDITOR_VERSION_REVISION 1
-
-
-typedef enum
-{
- ManualEditState_NOT_INITIALIZED,
- ManualEditState_INITIALIZED,
- ManualEditState_ANALYZING,
- ManualEditState_ANALYZING_ERROR,
- ManualEditState_OPENED,
- ManualEditState_SAVING,
- ManualEditState_SAVING_ERROR,
- ManualEditState_SAVED,
- ManualEditState_STOPPING
-} ManualEditState;
-
-typedef struct
-{
- JavaVM* pVM;
- jobject engine;
- jmethodID onCompletionMethodId;
- jmethodID onErrorMethodId;
- jmethodID onWarningMethodId;
- jmethodID onProgressUpdateMethodId;
- jmethodID onPreviewProgressUpdateMethodId;
- jmethodID previewFrameEditInfoId;
- M4xVSS_InitParams initParams;
- void* pTextRendererHandle;
- M4xVSS_getTextRgbBufferFct pTextRendererFunction;
- M4OSA_Context engineContext;
- ManualEditState state;
- M4VSS3GPP_EditSettings* pEditSettings;
- M4OSA_Context threadContext;
- M4OSA_ERR threadResult;
- M4OSA_UInt8 threadProgress;
- VideoEditorPreviewController *mPreviewController;
- M4xVSS_AudioMixingSettings *mAudioSettings;
- /* Audio Graph changes */
- M4OSA_Context pAudioGraphMCSCtx;
- M4OSA_Bool bSkipState;
- jmethodID onAudioGraphProgressUpdateMethodId;
- Mutex mLock;
- bool mIsUpdateOverlay;
- char *mOverlayFileName;
- int mOverlayRenderingMode;
- M4DECODER_VideoDecoders* decoders;
-} ManualEditContext;
-
-extern "C" M4OSA_ERR M4MCS_open_normalMode(
- M4MCS_Context pContext,
- M4OSA_Void* pFileIn,
- M4VIDEOEDITING_FileType InputFileType,
- M4OSA_Void* pFileOut,
- M4OSA_Void* pTempFile);
-
-static M4OSA_ERR videoEditor_toUTF8Fct(
- M4OSA_Void* pBufferIn,
- M4OSA_UInt8* pBufferOut,
- M4OSA_UInt32* bufferOutSize);
-
-static M4OSA_ERR videoEditor_fromUTF8Fct(
- M4OSA_UInt8* pBufferIn,
- M4OSA_Void* pBufferOut,
- M4OSA_UInt32* bufferOutSize);
-
-static M4OSA_ERR videoEditor_getTextRgbBufferFct(
- M4OSA_Void* pRenderingData,
- M4OSA_Void* pTextBuffer,
- M4OSA_UInt32 textBufferSize,
- M4VIFI_ImagePlane** pOutputPlane);
-
-static void videoEditor_callOnProgressUpdate(
- ManualEditContext* pContext,
- int task,
- int progress);
-
-static void videoEditor_freeContext(
- JNIEnv* pEnv,
- ManualEditContext** ppContext);
-
-static M4OSA_ERR videoEditor_threadProc(
- M4OSA_Void* param);
-
-static jobject videoEditor_getVersion(
- JNIEnv* pEnv,
- jobject thiz);
-
-static void videoEditor_init(
- JNIEnv* pEnv,
- jobject thiz,
- jstring tempPath,
- jstring textRendererPath);
-
-static void videoEditor_loadSettings(
- JNIEnv* pEnv,
- jobject thiz,
- jobject settings);
-
-static void videoEditor_unloadSettings(
- JNIEnv* pEnv,
- jobject thiz);
-
-
-static void videoEditor_stopEncoding(
- JNIEnv* pEnv,
- jobject thiz);
-
-static void videoEditor_release(
- JNIEnv* pEnv,
- jobject thiz);
-static jint videoEditor_getPixels(
- JNIEnv* env,
- jobject thiz,
- jstring path,
- jintArray pixelArray,
- M4OSA_UInt32 width,
- M4OSA_UInt32 height,
- M4OSA_UInt32 timeMS);
-static jint videoEditor_getPixelsList(
- JNIEnv* env,
- jobject thiz,
- jstring path,
- jintArray pixelArray,
- M4OSA_UInt32 width,
- M4OSA_UInt32 height,
- M4OSA_UInt32 noOfThumbnails,
- jlong startTime,
- jlong endTime,
- jintArray indexArray,
- jobject callback);
-
-static void
-videoEditor_startPreview(
- JNIEnv* pEnv,
- jobject thiz,
- jobject mSurface,
- jlong fromMs,
- jlong toMs,
- jint callbackInterval,
- jboolean loop);
-
-static void
-videoEditor_populateSettings(
- JNIEnv* pEnv,
- jobject thiz,
- jobject settings,
- jobject object,
- jobject audioSettingObject);
-
-static jint videoEditor_stopPreview(JNIEnv* pEnv,
- jobject thiz);
-
-static jobject
-videoEditor_getProperties(
- JNIEnv* pEnv,
- jobject thiz,
- jstring file);
-
-static jint videoEditor_renderPreviewFrame(JNIEnv* pEnv,
- jobject thiz,
- jobject mSurface,
- jlong fromMs,
- jint surfaceWidth,
- jint surfaceHeight);
-
-static int videoEditor_registerManualEditMethods(
- JNIEnv* pEnv);
-
-static void jniPreviewProgressCallback(void* cookie, M4OSA_UInt32 msgType,
- void *argc);
-
-static jint videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
- jobject thiz,
- jobject mSurface,
- jstring filePath,
- jint frameWidth,
- jint frameHeight,
- jint surfaceWidth,
- jint surfaceHeight,
- jlong fromMs);
-
-static jint videoEditor_generateAudioWaveFormSync ( JNIEnv* pEnv,
- jobject thiz,
- jstring pcmfilePath,
- jstring outGraphfilePath,
- jint frameDuration,
- jint channels,
- jint samplesCount);
-
-static int videoEditor_generateAudioRawFile(JNIEnv* pEnv,
- jobject thiz,
- jstring infilePath,
- jstring pcmfilePath );
-
-M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
- M4OSA_Char* infilePath,
- M4OSA_Char* pcmfilePath );
-
-static jint
-videoEditor_generateClip(
- JNIEnv* pEnv,
- jobject thiz,
- jobject settings);
-
-static void videoEditor_clearSurface(JNIEnv* pEnv,
- jobject thiz,
- jobject surface);
-
-static JNINativeMethod gManualEditMethods[] = {
- {"getVersion", "()L"VERSION_CLASS_NAME";",
- (void *)videoEditor_getVersion },
- {"_init", "(Ljava/lang/String;Ljava/lang/String;)V",
- (void *)videoEditor_init },
- {"nativeStartPreview", "(Landroid/view/Surface;JJIZ)V",
- (void *)videoEditor_startPreview },
- {"nativePopulateSettings",
- "(L"EDIT_SETTINGS_CLASS_NAME";L"PREVIEW_PROPERTIES_CLASS_NAME";L"
- AUDIO_SETTINGS_CLASS_NAME";)V",
- (void *)videoEditor_populateSettings },
- {"nativeRenderPreviewFrame", "(Landroid/view/Surface;JII)I",
- (int *)videoEditor_renderPreviewFrame },
- {"nativeRenderMediaItemPreviewFrame",
- "(Landroid/view/Surface;Ljava/lang/String;IIIIJ)I",
- (int *)videoEditor_renderMediaItemPreviewFrame },
- {"nativeStopPreview", "()I",
- (int *)videoEditor_stopPreview },
- {"stopEncoding", "()V",
- (void *)videoEditor_stopEncoding },
- {"release", "()V",
- (void *)videoEditor_release },
- {"nativeGetPixels", "(Ljava/lang/String;[IIIJ)I",
- (void*)videoEditor_getPixels },
- {"nativeGetPixelsList", "(Ljava/lang/String;[IIIIJJ[ILandroid/media/videoeditor/MediaArtistNativeHelper$NativeGetPixelsListCallback;)I",
- (void*)videoEditor_getPixelsList },
- {"getMediaProperties",
- "(Ljava/lang/String;)Landroid/media/videoeditor/MediaArtistNativeHelper$Properties;",
- (void *)videoEditor_getProperties },
- {"nativeGenerateAudioGraph","(Ljava/lang/String;Ljava/lang/String;III)I",
- (int *)videoEditor_generateAudioWaveFormSync },
- {"nativeGenerateRawAudio", "(Ljava/lang/String;Ljava/lang/String;)I",
- (int *)videoEditor_generateAudioRawFile },
- {"nativeGenerateClip", "(L"EDIT_SETTINGS_CLASS_NAME";)I",
- (void *)videoEditor_generateClip },
- {"nativeClearSurface", "(Landroid/view/Surface;)V",
- (void *)videoEditor_clearSurface },
-};
-
-// temp file name of VSS out file
-#define TEMP_MCS_OUT_FILE_PATH "tmpOut.3gp"
-
-void
-getClipSetting(
- JNIEnv* pEnv,
- jobject object,
- M4VSS3GPP_ClipSettings* pSettings)
-{
-
- jfieldID fid;
- int field = 0;
- bool needToBeLoaded = true;
- jclass clazz = pEnv->FindClass(PROPERTIES_CLASS_NAME);
-
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == clazz),
- "not initialized");
-
- fid = pEnv->GetFieldID(clazz,"duration","I");
- pSettings->ClipProperties.uiClipDuration = pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("duration = %d",pSettings->ClipProperties.uiClipDuration);
-
- fid = pEnv->GetFieldID(clazz,"videoFormat","I");
- pSettings->ClipProperties.VideoStreamType =
- (M4VIDEOEDITING_VideoFormat)pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("videoFormat = %d",pSettings->ClipProperties.VideoStreamType);
-
- fid = pEnv->GetFieldID(clazz,"videoDuration","I");
- pSettings->ClipProperties.uiClipVideoDuration = pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("videoDuration = %d",
- pSettings->ClipProperties.uiClipVideoDuration);
-
- fid = pEnv->GetFieldID(clazz,"width","I");
- pSettings->ClipProperties.uiVideoWidth = pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("width = %d",pSettings->ClipProperties.uiVideoWidth);
-
- fid = pEnv->GetFieldID(clazz,"height","I");
- pSettings->ClipProperties.uiVideoHeight = pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("height = %d",pSettings->ClipProperties.uiVideoHeight);
-
- fid = pEnv->GetFieldID(clazz,"audioFormat","I");
- pSettings->ClipProperties.AudioStreamType =
- (M4VIDEOEDITING_AudioFormat)pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("audioFormat = %d",pSettings->ClipProperties.AudioStreamType);
-
- fid = pEnv->GetFieldID(clazz,"audioDuration","I");
- pSettings->ClipProperties.uiClipAudioDuration = pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("audioDuration = %d",
- pSettings->ClipProperties.uiClipAudioDuration);
-
- fid = pEnv->GetFieldID(clazz,"audioBitrate","I");
- pSettings->ClipProperties.uiAudioBitrate = pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("audioBitrate = %d",pSettings->ClipProperties.uiAudioBitrate);
-
- fid = pEnv->GetFieldID(clazz,"audioChannels","I");
- pSettings->ClipProperties.uiNbChannels = pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("audioChannels = %d",pSettings->ClipProperties.uiNbChannels);
-
- fid = pEnv->GetFieldID(clazz,"audioSamplingFrequency","I");
- pSettings->ClipProperties.uiSamplingFrequency = pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("audioSamplingFrequency = %d",
- pSettings->ClipProperties.uiSamplingFrequency);
-
- fid = pEnv->GetFieldID(clazz,"audioVolumeValue","I");
- pSettings->ClipProperties.uiClipAudioVolumePercentage =
- pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("audioVolumeValue = %d",
- pSettings->ClipProperties.uiClipAudioVolumePercentage);
-
- fid = pEnv->GetFieldID(clazz,"videoRotation","I");
- pSettings->ClipProperties.videoRotationDegrees =
- pEnv->GetIntField(object,fid);
- M4OSA_TRACE1_1("videoRotation = %d",
- pSettings->ClipProperties.videoRotationDegrees);
-
- // Free the local references to avoid memory leaks
- pEnv->DeleteLocalRef(clazz);
-}
-
-static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
- void *argc)
-{
- ManualEditContext *pContext = (ManualEditContext *)cookie;
- JNIEnv* pEnv = NULL;
- bool isFinished = false;
- int currentMs = 0;
- int error = M4NO_ERROR;
- bool isUpdateOverlay = false;
- int overlayEffectIndex;
- char *extPos;
- bool isSendProgress = true;
- jstring tmpFileName;
- VideoEditorCurretEditInfo *pCurrEditInfo;
-
- // Attach the current thread.
- pContext->pVM->AttachCurrentThread(&pEnv, NULL);
- switch(msgType)
- {
- case MSG_TYPE_PROGRESS_INDICATION:
- currentMs = *(int*)argc;
- break;
- case MSG_TYPE_PLAYER_ERROR:
- currentMs = -1;
- error = *(int*)argc;
- break;
- case MSG_TYPE_PREVIEW_END:
- isFinished = true;
- break;
- case MSG_TYPE_OVERLAY_UPDATE:
- {
- int overlayFileNameLen = 0;
- isSendProgress = false;
- pContext->mIsUpdateOverlay = true;
- pCurrEditInfo = (VideoEditorCurretEditInfo*)argc;
- overlayEffectIndex = pCurrEditInfo->overlaySettingsIndex;
- ALOGV("MSG_TYPE_OVERLAY_UPDATE");
-
- if (pContext->mOverlayFileName != NULL) {
- free(pContext->mOverlayFileName);
- pContext->mOverlayFileName = NULL;
- }
-
- overlayFileNameLen =
- strlen((const char*)pContext->pEditSettings->Effects[overlayEffectIndex].xVSS.pFramingFilePath);
-
- pContext->mOverlayFileName =
- (char*)M4OSA_32bitAlignedMalloc(overlayFileNameLen+1,
- M4VS, (M4OSA_Char*)"videoEdito JNI overlayFile");
- if (pContext->mOverlayFileName != NULL) {
- strncpy (pContext->mOverlayFileName,
- (const char*)pContext->pEditSettings->
- Effects[overlayEffectIndex].xVSS.pFramingFilePath, overlayFileNameLen);
- //Change the name to png file
- extPos = strstr(pContext->mOverlayFileName, ".rgb");
- if (extPos != NULL) {
- *extPos = '\0';
- } else {
- ALOGE("ERROR the overlay file is incorrect");
- }
-
- strcat(pContext->mOverlayFileName, ".png");
- ALOGV("Conv string is %s", pContext->mOverlayFileName);
- ALOGV("Current Clip index = %d", pCurrEditInfo->clipIndex);
-
- pContext->mOverlayRenderingMode = pContext->pEditSettings->\
- pClipList[pCurrEditInfo->clipIndex]->xVSS.MediaRendering;
- ALOGV("rendering mode %d ", pContext->mOverlayRenderingMode);
-
- }
-
- break;
- }
-
- case MSG_TYPE_OVERLAY_CLEAR:
- isSendProgress = false;
- if (pContext->mOverlayFileName != NULL) {
- free(pContext->mOverlayFileName);
- pContext->mOverlayFileName = NULL;
- }
-
- ALOGV("MSG_TYPE_OVERLAY_CLEAR");
- //argc is not used
- pContext->mIsUpdateOverlay = true;
- break;
- default:
- break;
- }
-
- if (isSendProgress) {
- tmpFileName = pEnv->NewStringUTF(pContext->mOverlayFileName);
- pEnv->CallVoidMethod(pContext->engine,
- pContext->onPreviewProgressUpdateMethodId,
- currentMs,isFinished, pContext->mIsUpdateOverlay,
- tmpFileName, pContext->mOverlayRenderingMode, error);
-
- if (pContext->mIsUpdateOverlay) {
- pContext->mIsUpdateOverlay = false;
- }
-
- if (tmpFileName) {
- pEnv->DeleteLocalRef(tmpFileName);
- }
- }
-
- // Detach the current thread.
- pContext->pVM->DetachCurrentThread();
-
-}
-static M4OSA_ERR checkClipVideoProfileAndLevel(M4DECODER_VideoDecoders *pDecoders,
- M4OSA_Int32 format, M4OSA_UInt32 profile, M4OSA_UInt32 level){
-
- M4OSA_Int32 codec = 0;
- M4OSA_Bool foundCodec = M4OSA_FALSE;
- M4OSA_ERR result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE;
- M4OSA_Bool foundProfile = M4OSA_FALSE;
- ALOGV("checkClipVideoProfileAndLevel format %d profile;%d level:0x%x",
- format, profile, level);
-
- switch (format) {
- case M4VIDEOEDITING_kH263:
- codec = M4DA_StreamTypeVideoH263;
- break;
- case M4VIDEOEDITING_kH264:
- codec = M4DA_StreamTypeVideoMpeg4Avc;
- break;
- case M4VIDEOEDITING_kMPEG4:
- codec = M4DA_StreamTypeVideoMpeg4;
- break;
- case M4VIDEOEDITING_kNoneVideo:
- case M4VIDEOEDITING_kNullVideo:
- case M4VIDEOEDITING_kUnsupportedVideo:
- // For these case we do not check the profile and level
- return M4NO_ERROR;
- default :
- ALOGE("checkClipVideoProfileAndLevel unsupport Video format %ld", format);
- break;
- }
-
- if (pDecoders != M4OSA_NULL && pDecoders->decoderNumber > 0) {
- VideoDecoder *pVideoDecoder = pDecoders->decoder;
- for(size_t k =0; k < pDecoders->decoderNumber; k++) {
- if (pVideoDecoder != M4OSA_NULL) {
- if (pVideoDecoder->codec == codec) {
- foundCodec = M4OSA_TRUE;
- break;
- }
- }
- pVideoDecoder++;
- }
-
- if (foundCodec) {
- VideoComponentCapabilities* pComponent = pVideoDecoder->component;
- for (size_t i = 0; i < pVideoDecoder->componentNumber; i++) {
- if (pComponent != M4OSA_NULL) {
- VideoProfileLevel *pProfileLevel = pComponent->profileLevel;
- for (size_t j =0; j < pComponent->profileNumber; j++) {
- // Check the profile and level
- if (pProfileLevel != M4OSA_NULL) {
- if (profile == pProfileLevel->mProfile) {
- foundProfile = M4OSA_TRUE;
-
- if (level <= pProfileLevel->mLevel) {
- return M4NO_ERROR;
- }
- } else {
- foundProfile = M4OSA_FALSE;
- }
- }
- pProfileLevel++;
- }
- }
- pComponent++;
- }
- }
- }
-
- if (foundProfile) {
- result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_LEVEL;
- } else {
- result = M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE;
- }
-
- return result;
-}
-static jint videoEditor_stopPreview(JNIEnv* pEnv,
- jobject thiz)
-{
- ManualEditContext* pContext = M4OSA_NULL;
- bool needToBeLoaded = true;
- M4OSA_UInt32 lastProgressTimeMs = 0;
-
- // Get the context.
- pContext =
- (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
- lastProgressTimeMs = pContext->mPreviewController->stopPreview();
-
- if (pContext->mOverlayFileName != NULL) {
- free(pContext->mOverlayFileName);
- pContext->mOverlayFileName = NULL;
- }
-
- return (jint)lastProgressTimeMs;
-}
-
-static void videoEditor_clearSurface(JNIEnv* pEnv,
- jobject thiz,
- jobject surface)
-{
- bool needToBeLoaded = true;
- M4OSA_ERR result = M4NO_ERROR;
- VideoEditor_renderPreviewFrameStr frameStr;
- const char* pMessage = NULL;
- // Let the size be QVGA
- int width = 320;
- int height = 240;
- ManualEditContext* pContext = M4OSA_NULL;
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
- "VIDEO_EDITOR","pContext = 0x%x",pContext);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext->mPreviewController),
- "not initialized");
-
- // Validate the surface parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
- (NULL == surface),
- "surface is null");
-
- sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, surface);
-
- // Validate the mSurface's mNativeSurface field
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (NULL == previewSurface.get()),
- "mNativeSurface is null");
-
- frameStr.pBuffer = M4OSA_NULL;
- frameStr.timeMs = 0;
- frameStr.uiSurfaceWidth = width;
- frameStr.uiSurfaceHeight = height;
- frameStr.uiFrameWidth = width;
- frameStr.uiFrameHeight = height;
- frameStr.bApplyEffect = M4OSA_FALSE;
- frameStr.clipBeginCutTime = 0;
- frameStr.clipEndCutTime = 0;
-
- result = pContext->mPreviewController->clearSurface(previewSurface,
- &frameStr);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
-
- }
-
-static jint videoEditor_renderPreviewFrame(JNIEnv* pEnv,
- jobject thiz,
- jobject mSurface,
- jlong fromMs,
- jint surfaceWidth,
- jint surfaceHeight )
-{
- bool needToBeLoaded = true;
- M4OSA_ERR result = M4NO_ERROR;
- M4OSA_UInt32 timeMs = (M4OSA_UInt32)fromMs;
- M4OSA_UInt32 i=0,tnTimeMs = 0, framesizeYuv =0;
- M4VIFI_UInt8 *pixelArray = M4OSA_NULL;
- M4OSA_UInt32 iCurrentClipIndex = 0, uiNumberOfClipsInStoryBoard =0,
- uiClipDuration = 0, uiTotalClipDuration = 0,
- iIncrementedDuration = 0;
- VideoEditor_renderPreviewFrameStr frameStr;
- M4OSA_Context tnContext = M4OSA_NULL;
- const char* pMessage = NULL;
- M4VIFI_ImagePlane *yuvPlane = NULL;
- VideoEditorCurretEditInfo currEditInfo;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
- "VIDEO_EDITOR", "surfaceWidth = %d",surfaceWidth);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
- "VIDEO_EDITOR", "surfaceHeight = %d",surfaceHeight);
- ManualEditContext* pContext = M4OSA_NULL;
- // Get the context.
- pContext =
- (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
- "VIDEO_EDITOR","pContext = 0x%x",pContext);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext->mPreviewController),
- "not initialized");
-
- // Validate the mSurface parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
- (NULL == mSurface),
- "mSurface is null");
-
- sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
-
- // Validate the mSurface's mNativeSurface field
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (NULL == previewSurface.get()),
- "mNativeSurface is null");
-
- /* Determine the total number of clips, total duration*/
- uiNumberOfClipsInStoryBoard = pContext->pEditSettings->uiClipNumber;
-
- for (i = 0; i < uiNumberOfClipsInStoryBoard; i++) {
- uiClipDuration = pContext->pEditSettings->pClipList[i]->uiEndCutTime -
- pContext->pEditSettings->pClipList[i]->uiBeginCutTime;
- uiTotalClipDuration += uiClipDuration;
- }
-
- /* determine the clip whose thumbnail needs to be rendered*/
- if (timeMs == 0) {
- iCurrentClipIndex = 0;
- i=0;
- } else {
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_renderPreviewFrame() timeMs=%d", timeMs);
-
- if (timeMs > uiTotalClipDuration) {
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_renderPreviewFrame() timeMs > uiTotalClipDuration");
- pMessage = videoEditJava_getErrorName(M4ERR_PARAMETER);
- jniThrowException(pEnv, "java/lang/IllegalArgumentException", pMessage);
- return -1;
- }
-
- for (i = 0; i < uiNumberOfClipsInStoryBoard; i++) {
- if (timeMs <= (iIncrementedDuration +
- (pContext->pEditSettings->pClipList[i]->uiEndCutTime -
- pContext->pEditSettings->pClipList[i]->uiBeginCutTime)))
- {
- iCurrentClipIndex = i;
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_renderPreviewFrame() iCurrentClipIndex=%d for timeMs=%d",
- iCurrentClipIndex, timeMs);
- break;
- }
- else {
- iIncrementedDuration = iIncrementedDuration +
- (pContext->pEditSettings->pClipList[i]->uiEndCutTime -
- pContext->pEditSettings->pClipList[i]->uiBeginCutTime);
- }
- }
- }
- /* If timestamp is beyond story board duration, return*/
- if (i >= uiNumberOfClipsInStoryBoard) {
- if (timeMs == iIncrementedDuration) {
- iCurrentClipIndex = i-1;
- } else {
- return -1;
- }
- }
-
- /*+ Handle the image files here */
- if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType ==
- /*M4VIDEOEDITING_kFileType_JPG*/ M4VIDEOEDITING_kFileType_ARGB8888 ) {
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", " iCurrentClipIndex %d ", iCurrentClipIndex);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- " Height = %d",
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoHeight);
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- " Width = %d",
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth);
-
- LvGetImageThumbNail((const char *)pContext->pEditSettings->\
- pClipList[iCurrentClipIndex]->pFile,
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoHeight,
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->ClipProperties.uiVideoWidth,
- (M4OSA_Void **)&frameStr.pBuffer);
- tnTimeMs = (M4OSA_UInt32)timeMs;
-
- frameStr.videoRotationDegree = 0;
- } else {
- /* Handle 3gp/mp4 Clips here */
- /* get thumbnail*/
- result = ThumbnailOpen(&tnContext,
- (const M4OSA_Char*)pContext->pEditSettings->\
- pClipList[iCurrentClipIndex]->pFile, M4OSA_TRUE);
- if (result != M4NO_ERROR || tnContext == M4OSA_NULL) {
- return -1;
- }
-
- /* timeMs is relative to storyboard; in this api it shud be relative to this clip */
- if ((i >= uiNumberOfClipsInStoryBoard) &&
- (timeMs == iIncrementedDuration)) {
- tnTimeMs = pContext->pEditSettings->\
- pClipList[iCurrentClipIndex]->uiEndCutTime;
- } else {
- tnTimeMs = pContext->pEditSettings->\
- pClipList[iCurrentClipIndex]->uiBeginCutTime
- + (timeMs - iIncrementedDuration);
- }
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "video width = %d",pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoWidth);
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "video height = %d",pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoHeight);
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "current clip index = %d",iCurrentClipIndex);
-
- M4OSA_UInt32 width = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoWidth;
- M4OSA_UInt32 height = pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoHeight;
-
- framesizeYuv = width * height * 1.5;
-
- pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS,
- (M4OSA_Char*)"videoEditor pixelArray");
- if (pixelArray == M4OSA_NULL) {
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_renderPreviewFrame() malloc error");
- ThumbnailClose(tnContext);
- pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
- jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
- return -1;
- }
-
- result = ThumbnailGetPixels16(tnContext, (M4OSA_Int16 *)pixelArray,
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoWidth,
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoHeight,
- &tnTimeMs, 0);
- if (result != M4NO_ERROR) {
- free(pixelArray);
- ThumbnailClose(tnContext);
- return -1;
- }
-
- ThumbnailClose(tnContext);
- tnContext = M4OSA_NULL;
-
-#ifdef DUMPTOFILE
- {
- M4OSA_Context fileContext;
- M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/FirstRGB565.raw";
- remove((const char *)fileName);
- M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
- M4OSA_kFileWrite|M4OSA_kFileCreate);
- M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) pixelArray,
- framesizeYuv);
- M4OSA_fileWriteClose(fileContext);
- }
-#endif
-
- /**
- * Allocate output YUV planes
- */
- yuvPlane = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(3*sizeof(M4VIFI_ImagePlane), M4VS,
- (M4OSA_Char*)"videoEditor_renderPreviewFrame Output plane YUV");
- if (yuvPlane == M4OSA_NULL) {
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_renderPreviewFrame() malloc error for yuv plane");
- free(pixelArray);
- pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
- jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
- return -1;
- }
-
- yuvPlane[0].u_width = width;
- yuvPlane[0].u_height = height;
- yuvPlane[0].u_topleft = 0;
- yuvPlane[0].u_stride = width;
- yuvPlane[0].pac_data = (M4VIFI_UInt8*)pixelArray;
-
- yuvPlane[1].u_width = width>>1;
- yuvPlane[1].u_height = height>>1;
- yuvPlane[1].u_topleft = 0;
- yuvPlane[1].u_stride = width>>1;
- yuvPlane[1].pac_data = yuvPlane[0].pac_data
- + yuvPlane[0].u_width * yuvPlane[0].u_height;
- yuvPlane[2].u_width = (width)>>1;
- yuvPlane[2].u_height = (height)>>1;
- yuvPlane[2].u_topleft = 0;
- yuvPlane[2].u_stride = (width)>>1;
- yuvPlane[2].pac_data = yuvPlane[1].pac_data
- + yuvPlane[1].u_width * yuvPlane[1].u_height;
-
-#ifdef DUMPTOFILE
- {
- M4OSA_Context fileContext;
- M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/ConvertedYuv.yuv";
- remove((const char *)fileName);
- M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
- M4OSA_kFileWrite|M4OSA_kFileCreate);
- M4OSA_fileWriteData(fileContext,
- (M4OSA_MemAddr8) yuvPlane[0].pac_data, framesizeYuv);
- M4OSA_fileWriteClose(fileContext);
- }
-#endif
-
- /* Fill up the render structure*/
- frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data;
-
- frameStr.videoRotationDegree = pContext->pEditSettings->\
- pClipList[iCurrentClipIndex]->ClipProperties.videoRotationDegrees;
- }
-
- frameStr.timeMs = timeMs; /* timestamp on storyboard*/
- frameStr.uiSurfaceWidth =
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoWidth;
- frameStr.uiSurfaceHeight =
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoHeight;
- frameStr.uiFrameWidth =
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoWidth;
- frameStr.uiFrameHeight =
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->\
- ClipProperties.uiVideoHeight;
- if (pContext->pEditSettings->nbEffects > 0) {
- frameStr.bApplyEffect = M4OSA_TRUE;
- } else {
- frameStr.bApplyEffect = M4OSA_FALSE;
- }
- frameStr.clipBeginCutTime = iIncrementedDuration;
- frameStr.clipEndCutTime =
- iIncrementedDuration +
- (pContext->pEditSettings->pClipList[iCurrentClipIndex]->uiEndCutTime -\
- pContext->pEditSettings->pClipList[iCurrentClipIndex]->uiBeginCutTime);
-
- pContext->mPreviewController->setPreviewFrameRenderingMode(
- pContext->pEditSettings->\
- pClipList[iCurrentClipIndex]->xVSS.MediaRendering,
- pContext->pEditSettings->xVSS.outputVideoSize);
- result = pContext->mPreviewController->renderPreviewFrame(previewSurface,
- &frameStr, &currEditInfo);
-
- if (currEditInfo.overlaySettingsIndex != -1) {
- char tmpOverlayFilename[100];
- char *extPos = NULL;
- jstring tmpOverlayString;
- int tmpRenderingMode = 0;
-
- strncpy (tmpOverlayFilename,
- (const char*)pContext->pEditSettings->Effects[currEditInfo.overlaySettingsIndex].xVSS.pFramingFilePath, 99);
-
- //Change the name to png file
- extPos = strstr(tmpOverlayFilename, ".rgb");
- if (extPos != NULL) {
- *extPos = '\0';
- } else {
- ALOGE("ERROR the overlay file is incorrect");
- }
-
- strcat(tmpOverlayFilename, ".png");
-
- tmpRenderingMode = pContext->pEditSettings->pClipList[iCurrentClipIndex]->xVSS.MediaRendering;
- tmpOverlayString = pEnv->NewStringUTF(tmpOverlayFilename);
- pEnv->CallVoidMethod(pContext->engine,
- pContext->previewFrameEditInfoId,
- tmpOverlayString, tmpRenderingMode);
-
- }
-
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
-
- free(frameStr.pBuffer);
- if (pContext->pEditSettings->pClipList[iCurrentClipIndex]->FileType !=
- M4VIDEOEDITING_kFileType_ARGB8888) {
- free(yuvPlane);
- }
-
- return (jint)tnTimeMs;
-}
-
-static jint videoEditor_renderMediaItemPreviewFrame(JNIEnv* pEnv,
- jobject thiz,
- jobject mSurface,
- jstring filePath,
- jint frameWidth,
- jint frameHeight,
- jint surfaceWidth,
- jint surfaceHeight,
- jlong fromMs)
-{
- bool needToBeLoaded = true;
- M4OSA_ERR result = M4NO_ERROR;
- M4OSA_UInt32 timeMs = (M4OSA_UInt32)fromMs;
- M4OSA_UInt32 framesizeYuv =0;
- M4VIFI_UInt8 *pixelArray = M4OSA_NULL;
- VideoEditor_renderPreviewFrameStr frameStr;
- M4OSA_Context tnContext = M4OSA_NULL;
- const char* pMessage = NULL;
- M4VIFI_ImagePlane yuvPlane[3], rgbPlane;
-
- ManualEditContext* pContext = M4OSA_NULL;
- // Get the context.
- pContext =
- (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded,
- pEnv, thiz);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext->mPreviewController),
- "not initialized");
-
- // Validate the mSurface parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
- (NULL == mSurface),
- "mSurface is null");
-
- sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
-
- const char *pString = pEnv->GetStringUTFChars(filePath, NULL);
- if (pString == M4OSA_NULL) {
- if (pEnv != NULL) {
- jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
- }
- }
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_renderMediaItemPreviewFrame() timeMs=%d", timeMs);
- /* get thumbnail*/
- result = ThumbnailOpen(&tnContext,(const M4OSA_Char*)pString, M4OSA_TRUE);
- if (result != M4NO_ERROR || tnContext == M4OSA_NULL) {
- return (jint)timeMs;
- }
-
- framesizeYuv = ((frameWidth)*(frameHeight)*1.5);
-
- pixelArray = (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(framesizeYuv, M4VS,\
- (M4OSA_Char*)"videoEditor pixelArray");
- if (pixelArray == M4OSA_NULL) {
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_renderPreviewFrame() malloc error");
- ThumbnailClose(tnContext);
- pMessage = videoEditJava_getErrorName(M4ERR_ALLOC);
- jniThrowException(pEnv, "java/lang/RuntimeException", pMessage);
- return (jint)timeMs;
- }
-
- result = ThumbnailGetPixels16(tnContext, (M4OSA_Int16 *)pixelArray,
- frameWidth,
- frameHeight, &timeMs, 0);
- if (result != M4NO_ERROR) {
- free(pixelArray);
- ThumbnailClose(tnContext);
- return (jint)fromMs;
- }
-
-#ifdef DUMPTOFILESYSTEM
- {
- M4OSA_Context fileContext;
- M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/FirstRGB565.rgb";
- M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
- M4OSA_kFileWrite|M4OSA_kFileCreate);
- M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) pixelArray,
- framesizeRgb);
- M4OSA_fileWriteClose(fileContext);
- }
-#endif
-
- yuvPlane[0].pac_data = (M4VIFI_UInt8*)pixelArray;
- yuvPlane[0].u_height = frameHeight;
- yuvPlane[0].u_width = frameWidth;
- yuvPlane[0].u_stride = yuvPlane[0].u_width;
- yuvPlane[0].u_topleft = 0;
-
- yuvPlane[1].u_height = frameHeight/2;
- yuvPlane[1].u_width = frameWidth/2;
- yuvPlane[1].u_stride = yuvPlane[1].u_width;
- yuvPlane[1].u_topleft = 0;
- yuvPlane[1].pac_data = yuvPlane[0].pac_data
- + yuvPlane[0].u_width*yuvPlane[0].u_height;
-
- yuvPlane[2].u_height = frameHeight/2;
- yuvPlane[2].u_width = frameWidth/2;
- yuvPlane[2].u_stride = yuvPlane[2].u_width;
- yuvPlane[2].u_topleft = 0;
- yuvPlane[2].pac_data = yuvPlane[0].pac_data
- + yuvPlane[0].u_width*yuvPlane[0].u_height + \
- (yuvPlane[0].u_width/2)*(yuvPlane[0].u_height/2);
-#ifdef DUMPTOFILESYSTEM
- {
- M4OSA_Context fileContext;
- M4OSA_Char* fileName = (M4OSA_Char*)"/mnt/sdcard/ConvertedYuv.yuv";
- M4OSA_fileWriteOpen(&fileContext, (M4OSA_Void*) fileName,\
- M4OSA_kFileWrite|M4OSA_kFileCreate);
- M4OSA_fileWriteData(fileContext, (M4OSA_MemAddr8) yuvPlane[0].pac_data,
- framesizeYuv);
- M4OSA_fileWriteClose(fileContext);
- }
-#endif
-
- /* Fill up the render structure*/
- frameStr.pBuffer = (M4OSA_Void*)yuvPlane[0].pac_data;
- frameStr.timeMs = timeMs; /* timestamp on storyboard*/
- frameStr.uiSurfaceWidth = frameWidth;
- frameStr.uiSurfaceHeight = frameHeight;
- frameStr.uiFrameWidth = frameWidth;
- frameStr.uiFrameHeight = frameHeight;
- frameStr.bApplyEffect = M4OSA_FALSE;
- // clip begin cuttime and end cuttime set to 0
- // as its only required when effect needs to be applied while rendering
- frameStr.clipBeginCutTime = 0;
- frameStr.clipEndCutTime = 0;
-
- /* pContext->mPreviewController->setPreviewFrameRenderingMode(M4xVSS_kBlackBorders,
- (M4VIDEOEDITING_VideoFrameSize)(M4VIDEOEDITING_kHD960+1));*/
- result
- = pContext->mPreviewController->renderPreviewFrame(previewSurface,&frameStr, NULL);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
-
- /* free the pixelArray and yuvPlane[0].pac_data */
- free(yuvPlane[0].pac_data);
-
- ThumbnailClose(tnContext);
-
- if (pString != NULL) {
- pEnv->ReleaseStringUTFChars(filePath, pString);
- }
-
- return (jint)timeMs;
-}
-
-jint videoEditor_generateAudioRawFile( JNIEnv* pEnv,
- jobject thiz,
- jstring infilePath,
- jstring pcmfilePath)
-{
- M4OSA_ERR result = M4NO_ERROR;
- bool loaded = true;
- ManualEditContext* pContext = M4OSA_NULL;
-
-
-
- const char *pInputFile = pEnv->GetStringUTFChars(infilePath, NULL);
- if (pInputFile == M4OSA_NULL) {
- if (pEnv != NULL) {
- jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
- }
- }
-
- const char *pStringOutPCMFilePath = pEnv->GetStringUTFChars(pcmfilePath, NULL);
- if (pStringOutPCMFilePath == M4OSA_NULL) {
- if (pEnv != NULL) {
- jniThrowException(pEnv, "java/lang/RuntimeException", "Input string null");
- }
- }
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
- "VIDEO_EDITOR", "videoEditor_generateAudioRawFile infilePath %s",
- pInputFile);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO,
- "VIDEO_EDITOR", "videoEditor_generateAudioRawFile pcmfilePath %s",
- pStringOutPCMFilePath);
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
-
- result = videoEditor_generateAudio( pEnv, pContext, (M4OSA_Char*)pInputFile,
- (M4OSA_Char*)pStringOutPCMFilePath);
-
- if (pInputFile != NULL) {
- pEnv->ReleaseStringUTFChars(infilePath, pInputFile);
- }
- if (pStringOutPCMFilePath != NULL) {
- pEnv->ReleaseStringUTFChars(pcmfilePath, pStringOutPCMFilePath);
- }
-
- return (jint)result;
-}
-
-M4OSA_ERR videoEditor_generateAudio(JNIEnv* pEnv,ManualEditContext* pContext,
- M4OSA_Char* infilePath,
- M4OSA_Char* pcmfilePath )
-{
- bool needToBeLoaded = true;
- M4OSA_ERR result = M4NO_ERROR;
- M4MCS_Context mcsContext = M4OSA_NULL;
- M4OSA_Char* pInputFile = M4OSA_NULL;
- M4OSA_Char* pOutputFile = M4OSA_NULL;
- M4OSA_Char* pTempPath = M4OSA_NULL;
- M4MCS_OutputParams* pOutputParams = M4OSA_NULL;
- M4MCS_EncodingParams* pEncodingParams = M4OSA_NULL;
- M4OSA_Int32 pInputFileType = 0;
- M4OSA_UInt8 threadProgress = 0;
- M4OSA_Char* pTemp3gpFilePath = M4OSA_NULL;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio()");
-
- videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
- (NULL == pContext),
- "ManualEditContext is null");
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_init()");
-
- pOutputParams = (M4MCS_OutputParams *)M4OSA_32bitAlignedMalloc(
- sizeof(M4MCS_OutputParams),0x00,
- (M4OSA_Char *)"M4MCS_OutputParams");
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pOutputParams),
- "not initialized");
- if (needToBeLoaded == false) {
- return M4ERR_ALLOC;
- }
-
- pEncodingParams = (M4MCS_EncodingParams *)M4OSA_32bitAlignedMalloc(
- sizeof(M4MCS_EncodingParams),0x00,
- (M4OSA_Char *)"M4MCS_EncodingParams");
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pEncodingParams),
- "not initialized");
- if (needToBeLoaded == false) {
- free(pEncodingParams);
- pEncodingParams = M4OSA_NULL;
- return M4ERR_ALLOC;
- }
-
- // Initialize the MCS library.
- result = M4MCS_init(&mcsContext, pContext->initParams.pFileReadPtr,
- pContext->initParams.pFileWritePtr);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,\
- (M4NO_ERROR != result), result);
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == mcsContext),
- "not initialized");
- if(needToBeLoaded == false) {
- free(pOutputParams);
- pOutputParams = M4OSA_NULL;
- free(pEncodingParams);
- pEncodingParams = M4OSA_NULL;
- return result;
- }
-
- // generate the path for temp 3gp output file
- pTemp3gpFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc (
- (strlen((const char*)pContext->initParams.pTempPath)
- + strlen((const char*)TEMP_MCS_OUT_FILE_PATH)) + 1 /* for null termination */ , 0x0,
- (M4OSA_Char*)"Malloc for temp 3gp file");
- if (pTemp3gpFilePath != M4OSA_NULL)
- {
- memset((void *)pTemp3gpFilePath ,0,
- strlen((const char*)pContext->initParams.pTempPath)
- + strlen((const char*)TEMP_MCS_OUT_FILE_PATH) + 1);
- strncat((char *)pTemp3gpFilePath,
- (const char *)pContext->initParams.pTempPath ,
- (size_t) ((M4OSA_Char*)pContext->initParams.pTempPath));
- strncat((char *)pTemp3gpFilePath , (const char *)TEMP_MCS_OUT_FILE_PATH,
- (size_t)strlen ((const char*)TEMP_MCS_OUT_FILE_PATH));
- }
- else {
- M4MCS_abort(mcsContext);
- free(pOutputParams);
- pOutputParams = M4OSA_NULL;
- free(pEncodingParams);
- pEncodingParams = M4OSA_NULL;
- return M4ERR_ALLOC;
- }
-
- pInputFile = (M4OSA_Char *) infilePath; //pContext->mAudioSettings->pFile;
- //Delete this file later
- pOutputFile = (M4OSA_Char *) pTemp3gpFilePath;
- // Temp folder path for VSS use = ProjectPath
- pTempPath = (M4OSA_Char *) pContext->initParams.pTempPath;
- pInputFileType = (M4VIDEOEDITING_FileType)pContext->mAudioSettings->fileType;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "TEMP_MCS_OUT_FILE_PATH len %d",
- strlen ((const char*)TEMP_MCS_OUT_FILE_PATH));
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "pTemp3gpFilePath %s",
- pOutputFile);
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_open()");
-
- result = M4MCS_open(mcsContext, pInputFile,
- (M4VIDEOEDITING_FileType)pInputFileType,
- pOutputFile, pTempPath);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
- if(needToBeLoaded == false) {
- free(pTemp3gpFilePath);
- pTemp3gpFilePath = M4OSA_NULL;
- M4MCS_abort(mcsContext);
- free(pOutputParams);
- pOutputParams = M4OSA_NULL;
- free(pEncodingParams);
- pEncodingParams = M4OSA_NULL;
- return result;
- }
-
- pOutputParams->OutputFileType
- = (M4VIDEOEDITING_FileType)M4VIDEOEDITING_kFileType_3GPP;
- // Set the video format.
- pOutputParams->OutputVideoFormat =
- (M4VIDEOEDITING_VideoFormat)M4VIDEOEDITING_kNoneVideo;//M4VIDEOEDITING_kNoneVideo;
- pOutputParams->outputVideoProfile = 1;
- pOutputParams->outputVideoLevel = 1;
- // Set the frame size.
- pOutputParams->OutputVideoFrameSize
- = (M4VIDEOEDITING_VideoFrameSize)M4VIDEOEDITING_kQCIF;
- // Set the frame rate.
- pOutputParams->OutputVideoFrameRate
- = (M4VIDEOEDITING_VideoFramerate)M4VIDEOEDITING_k5_FPS;
-
- // Set the audio format.
- pOutputParams->OutputAudioFormat
- = (M4VIDEOEDITING_AudioFormat)M4VIDEOEDITING_kAAC;
- // Set the audio sampling frequency.
- pOutputParams->OutputAudioSamplingFrequency =
- (M4VIDEOEDITING_AudioSamplingFrequency)M4VIDEOEDITING_k32000_ASF;
- // Set the audio mono.
- pOutputParams->bAudioMono = false;
- // Set the pcm file; null for now.
- pOutputParams->pOutputPCMfile = (M4OSA_Char *)pcmfilePath;
- //(M4OSA_Char *)"/sdcard/Output/AudioPcm.pcm";
- // Set the audio sampling frequency.
- pOutputParams->MediaRendering = (M4MCS_MediaRendering)M4MCS_kCropping;
- // new params after integrating MCS 2.0
- // Set the number of audio effects; 0 for now.
- pOutputParams->nbEffects = 0;
- // Set the audio effect; null for now.
- pOutputParams->pEffects = NULL;
- // Set the audio effect; null for now.
- pOutputParams->bDiscardExif = M4OSA_FALSE;
- // Set the audio effect; null for now.
- pOutputParams->bAdjustOrientation = M4OSA_FALSE;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_setOutputParams()");
- result = M4MCS_setOutputParams(mcsContext, pOutputParams);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
- if (needToBeLoaded == false) {
- free(pTemp3gpFilePath);
- pTemp3gpFilePath = M4OSA_NULL;
- M4MCS_abort(mcsContext);
- free(pOutputParams);
- pOutputParams = M4OSA_NULL;
- free(pEncodingParams);
- pEncodingParams = M4OSA_NULL;
- return result;
- }
- // Set the video bitrate.
- pEncodingParams->OutputVideoBitrate =
- (M4VIDEOEDITING_Bitrate)M4VIDEOEDITING_kUndefinedBitrate;
- // Set the audio bitrate.
- pEncodingParams->OutputAudioBitrate
- = (M4VIDEOEDITING_Bitrate)M4VIDEOEDITING_k128_KBPS;
- // Set the end cut time in milliseconds.
- pEncodingParams->BeginCutTime = 0;
- // Set the end cut time in milliseconds.
- pEncodingParams->EndCutTime = 0;
- // Set the output file size in bytes.
- pEncodingParams->OutputFileSize = 0;
- // Set video time scale.
- pEncodingParams->OutputVideoTimescale = 0;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "M4MCS_setEncodingParams()");
- result = M4MCS_setEncodingParams(mcsContext, pEncodingParams);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
- if (needToBeLoaded == false) {
- free(pTemp3gpFilePath);
- pTemp3gpFilePath = M4OSA_NULL;
- M4MCS_abort(mcsContext);
- free(pOutputParams);
- pOutputParams = M4OSA_NULL;
- free(pEncodingParams);
- pEncodingParams = M4OSA_NULL;
- return result;
- }
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "M4MCS_checkParamsAndStart()");
- result = M4MCS_checkParamsAndStart(mcsContext);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
- if (needToBeLoaded == false) {
- free(pTemp3gpFilePath);
- pTemp3gpFilePath = M4OSA_NULL;
- M4MCS_abort(mcsContext);
- free(pOutputParams);
- pOutputParams = M4OSA_NULL;
- free(pEncodingParams);
- pEncodingParams = M4OSA_NULL;
- return result;
- }
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_step()");
-
- /*+ PROGRESS CB */
- M4OSA_UInt8 curProgress = 0;
- int lastProgress = 0;
-
- ALOGV("LVME_generateAudio Current progress is =%d", curProgress);
- pEnv->CallVoidMethod(pContext->engine,
- pContext->onProgressUpdateMethodId, 1/*task status*/,
- curProgress/*progress*/);
- do {
- result = M4MCS_step(mcsContext, &curProgress);
-
- if (result != M4NO_ERROR) {
- ALOGV("LVME_generateAudio M4MCS_step returned 0x%x",result);
-
- if (result == M4MCS_WAR_TRANSCODING_DONE) {
- ALOGV("LVME_generateAudio MCS process ended");
-
- // Send a progress notification.
- curProgress = 100;
- pEnv->CallVoidMethod(pContext->engine,
- pContext->onProgressUpdateMethodId, 1/*task status*/,
- curProgress);
- ALOGV("LVME_generateAudio Current progress is =%d", curProgress);
- }
- } else {
- // Send a progress notification if needed
- if (curProgress != lastProgress) {
- lastProgress = curProgress;
- pEnv->CallVoidMethod(pContext->engine,
- pContext->onProgressUpdateMethodId, 0/*task status*/,
- curProgress/*progress*/);
- ALOGV("LVME_generateAudio Current progress is =%d",curProgress);
- }
- }
- } while (result == M4NO_ERROR);
- /*- PROGRESS CB */
-
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4MCS_WAR_TRANSCODING_DONE != result), result);
- if (needToBeLoaded == false) {
- free(pTemp3gpFilePath);
- pTemp3gpFilePath = M4OSA_NULL;
- M4MCS_abort(mcsContext);
- free(pOutputParams);
- pOutputParams = M4OSA_NULL;
- free(pEncodingParams);
- pEncodingParams = M4OSA_NULL;
- return result;
- }
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4MCS_abort()");
- result = M4MCS_abort(mcsContext);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
-
- //pContext->mAudioSettings->pFile = pOutputParams->pOutputPCMfile;
- remove((const char *) pTemp3gpFilePath);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_generateAudio() EXIT ");
-
- if (pTemp3gpFilePath != M4OSA_NULL) {
- free(pTemp3gpFilePath);
- }
- if (pOutputParams != M4OSA_NULL) {
- free(pOutputParams);
- }
- if(pEncodingParams != M4OSA_NULL) {
- free(pEncodingParams);
- }
- return result;
-}
-
-static int removeAlphafromRGB8888 (
- M4OSA_Char* pFramingFilePath,
- M4xVSS_FramingStruct *pFramingCtx)
-{
- M4OSA_UInt32 frameSize_argb = (pFramingCtx->width * pFramingCtx->height * 4); // aRGB data
- M4OSA_Context lImageFileFp = M4OSA_NULL;
- M4OSA_ERR err = M4NO_ERROR;
-
- ALOGV("removeAlphafromRGB8888: width %d", pFramingCtx->width);
-
- M4OSA_UInt8 *pTmpData = (M4OSA_UInt8*) M4OSA_32bitAlignedMalloc(frameSize_argb, M4VS, (M4OSA_Char*)"Image argb data");
- if (pTmpData == M4OSA_NULL) {
- ALOGE("Failed to allocate memory for Image clip");
- return M4ERR_ALLOC;
- }
-
- /** Read the argb data from the passed file. */
- M4OSA_ERR lerr = M4OSA_fileReadOpen(&lImageFileFp, (M4OSA_Void *) pFramingFilePath, M4OSA_kFileRead);
-
-
- if ((lerr != M4NO_ERROR) || (lImageFileFp == M4OSA_NULL))
- {
- ALOGE("removeAlphafromRGB8888: Can not open the file ");
- free(pTmpData);
- return M4ERR_FILE_NOT_FOUND;
- }
-
-
- lerr = M4OSA_fileReadData(lImageFileFp, (M4OSA_MemAddr8)pTmpData, &frameSize_argb);
- if (lerr != M4NO_ERROR)
- {
- ALOGE("removeAlphafromRGB8888: can not read the data ");
- M4OSA_fileReadClose(lImageFileFp);
- free(pTmpData);
- return lerr;
- }
- M4OSA_fileReadClose(lImageFileFp);
-
- M4OSA_UInt32 frameSize = (pFramingCtx->width * pFramingCtx->height * 3); //Size of RGB 888 data.
-
- pFramingCtx->FramingRgb = (M4VIFI_ImagePlane*)M4OSA_32bitAlignedMalloc(
- sizeof(M4VIFI_ImagePlane), M4VS, (M4OSA_Char*)"Image clip RGB888 data");
- pFramingCtx->FramingRgb->pac_data = (M4VIFI_UInt8*)M4OSA_32bitAlignedMalloc(
- frameSize, M4VS, (M4OSA_Char*)"Image clip RGB888 data");
-
- if (pFramingCtx->FramingRgb == M4OSA_NULL)
- {
- ALOGE("Failed to allocate memory for Image clip");
- free(pTmpData);
- return M4ERR_ALLOC;
- }
-
- /** Remove the alpha channel */
- for (size_t i = 0, j = 0; i < frameSize_argb; i++) {
- if ((i % 4) == 0) continue;
- pFramingCtx->FramingRgb->pac_data[j] = pTmpData[i];
- j++;
- }
- free(pTmpData);
- return M4NO_ERROR;
-}
-
-static void
-videoEditor_populateSettings(
- JNIEnv* pEnv,
- jobject thiz,
- jobject settings,
- jobject object,
- jobject audioSettingObject)
-{
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_populateSettings()");
-
- bool needToBeLoaded = true;
- ManualEditContext* pContext = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
- jstring strPath = M4OSA_NULL;
- jstring strPCMPath = M4OSA_NULL;
- jobjectArray propertiesClipsArray = M4OSA_NULL;
- jobject properties = M4OSA_NULL;
- jint* bitmapArray = M4OSA_NULL;
- jobjectArray effectSettingsArray = M4OSA_NULL;
- jobject effectSettings = M4OSA_NULL;
- jintArray pixelArray = M4OSA_NULL;
- int width = 0;
- int height = 0;
- int nbOverlays = 0;
- int i,j = 0;
- int *pOverlayIndex = M4OSA_NULL;
- M4OSA_Char* pTempChar = M4OSA_NULL;
-
- // Validate the settings parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
- (NULL == settings),
- "settings is null");
- // Get the context.
- pContext =
- (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext->mPreviewController),
- "not initialized");
- jclass mPreviewClipPropClazz = pEnv->FindClass(PREVIEW_PROPERTIES_CLASS_NAME);
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == mPreviewClipPropClazz),
- "not initialized");
-
- jfieldID fid = pEnv->GetFieldID(mPreviewClipPropClazz,"clipProperties",
- "[L"PROPERTIES_CLASS_NAME";" );
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == fid),
- "not initialized");
-
- propertiesClipsArray = (jobjectArray)pEnv->GetObjectField(object, fid);
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == propertiesClipsArray),
- "not initialized");
-
- jclass engineClass = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == engineClass),
- "not initialized");
-
- pContext->onPreviewProgressUpdateMethodId = pEnv->GetMethodID(engineClass,
- "onPreviewProgressUpdate", "(IZZLjava/lang/String;II)V");
- // Check if the context is valid (required because the context is dereferenced).
- if (needToBeLoaded) {
- // Make sure that we are in a correct state.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (pContext->state != ManualEditState_INITIALIZED),
- "settings already loaded");
- if (needToBeLoaded) {
- // Retrieve the edit settings.
- if (pContext->pEditSettings != M4OSA_NULL) {
- videoEditClasses_freeEditSettings(&pContext->pEditSettings);
- pContext->pEditSettings = M4OSA_NULL;
- }
- videoEditClasses_getEditSettings(&needToBeLoaded, pEnv,
- settings, &pContext->pEditSettings,false);
- }
- }
-
- if (needToBeLoaded == false) {
- j = 0;
- while (j < pContext->pEditSettings->nbEffects)
- {
- if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) {
- if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) {
- free(pContext->pEditSettings->\
- Effects[j].xVSS.pFramingBuffer);
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL;
- }
- }
- j++;
- }
- return;
- }
-
- M4OSA_TRACE1_0("videoEditorC_getEditSettings done");
-
- pContext->previewFrameEditInfoId = pEnv->GetMethodID(engineClass,
- "previewFrameEditInfo", "(Ljava/lang/String;I)V");
-
- if ( pContext->pEditSettings != NULL )
- {
- // Check if the edit settings could be retrieved.
- jclass mEditClazz = pEnv->FindClass(EDIT_SETTINGS_CLASS_NAME);
- if(mEditClazz == M4OSA_NULL)
- {
- M4OSA_TRACE1_0("cannot find object field for mEditClazz");
- goto videoEditor_populateSettings_cleanup;
- }
- jclass mEffectsClazz = pEnv->FindClass(EFFECT_SETTINGS_CLASS_NAME);
- if(mEffectsClazz == M4OSA_NULL)
- {
- M4OSA_TRACE1_0("cannot find object field for mEffectsClazz");
- goto videoEditor_populateSettings_cleanup;
- }
- fid = pEnv->GetFieldID(mEditClazz,"effectSettingsArray", "[L"EFFECT_SETTINGS_CLASS_NAME";" );
- if(fid == M4OSA_NULL)
- {
- M4OSA_TRACE1_0("cannot find field for effectSettingsArray Array");
- goto videoEditor_populateSettings_cleanup;
- }
- effectSettingsArray = (jobjectArray)pEnv->GetObjectField(settings, fid);
- if(effectSettingsArray == M4OSA_NULL)
- {
- M4OSA_TRACE1_0("cannot find object field for effectSettingsArray");
- goto videoEditor_populateSettings_cleanup;
- }
-
- //int overlayIndex[pContext->pEditSettings->nbEffects];
- if (pContext->pEditSettings->nbEffects > 0)
- {
- pOverlayIndex
- = (int*) M4OSA_32bitAlignedMalloc(pContext->pEditSettings->nbEffects * sizeof(int), 0,
- (M4OSA_Char*)"pOverlayIndex");
- if (pOverlayIndex == M4OSA_NULL) {
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- M4OSA_TRUE, M4ERR_ALLOC);
- goto videoEditor_populateSettings_cleanup;
- }
- }
-
- i = 0;
- j = 0;
- M4OSA_TRACE1_1("no of effects = %d",pContext->pEditSettings->nbEffects);
- while (j < pContext->pEditSettings->nbEffects)
- {
- if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL)
- {
- pOverlayIndex[nbOverlays] = j;
-
- M4xVSS_FramingStruct *aFramingCtx = M4OSA_NULL;
- aFramingCtx
- = (M4xVSS_FramingStruct*)M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_FramingStruct), M4VS,
- (M4OSA_Char*)"M4xVSS_internalDecodeGIF: Context of the framing effect");
- if (aFramingCtx == M4OSA_NULL)
- {
- M4OSA_TRACE1_0("Allocation error in videoEditor_populateSettings");
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- M4OSA_TRUE, M4ERR_ALLOC);
- goto videoEditor_populateSettings_cleanup;
- }
-
- aFramingCtx->pCurrent = M4OSA_NULL; /* Only used by the first element of the chain */
- aFramingCtx->previousClipTime = -1;
- aFramingCtx->FramingYuv = M4OSA_NULL;
- aFramingCtx->FramingRgb = M4OSA_NULL;
- aFramingCtx->topleft_x
- = pContext->pEditSettings->Effects[j].xVSS.topleft_x;
- aFramingCtx->topleft_y
- = pContext->pEditSettings->Effects[j].xVSS.topleft_y;
-
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF u_width %d",
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF u_height() %d",
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "OF rgbType() %d",
- pContext->pEditSettings->Effects[j].xVSS.rgbType);
-
- aFramingCtx->width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width;
- aFramingCtx->height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height;
-
- result = M4xVSS_internalConvertARGB888toYUV420_FrammingEffect(pContext->engineContext,
- &(pContext->pEditSettings->Effects[j]),aFramingCtx,
- pContext->pEditSettings->Effects[j].xVSS.framingScaledSize);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
- if (needToBeLoaded == false) {
- M4OSA_TRACE1_1("M4xVSS_internalConvertARGB888toYUV420_FrammingEffect returned 0x%x", result);
- if (aFramingCtx != M4OSA_NULL) {
- free(aFramingCtx);
- aFramingCtx = M4OSA_NULL;
- }
- goto videoEditor_populateSettings_cleanup;
- }
-
- //framing buffers are resized to fit the output video resolution.
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width =
- aFramingCtx->FramingRgb->u_width;
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height =
- aFramingCtx->FramingRgb->u_height;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "A framing Context aFramingCtx->width = %d",
- aFramingCtx->FramingRgb->u_width);
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "A framing Context aFramingCtx->height = %d",
- aFramingCtx->FramingRgb->u_height);
-
-
- width = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_width;
- height = pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_height;
-
- //RGB 565
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_stride = width * 2;
-
- //for RGB565
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->u_topleft = 0;
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data =
- (M4VIFI_UInt8 *)M4OSA_32bitAlignedMalloc(width*height*2,
- 0x00,(M4OSA_Char *)"pac_data buffer");
-
- if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer->pac_data == M4OSA_NULL) {
- M4OSA_TRACE1_0("Failed to allocate memory for framing buffer");
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- M4OSA_TRUE, M4ERR_ALLOC);
- goto videoEditor_populateSettings_cleanup;
- }
-
- memcpy((void *)&pContext->pEditSettings->\
- Effects[j].xVSS.pFramingBuffer->\
- pac_data[0],(void *)&aFramingCtx->FramingRgb->pac_data[0],(width*height*2));
-
- //As of now rgb type is 565
- pContext->pEditSettings->Effects[j].xVSS.rgbType =
- (M4VSS3GPP_RGBType) M4VSS3GPP_kRGB565;
-
- if (aFramingCtx->FramingYuv != M4OSA_NULL )
- {
- if (aFramingCtx->FramingYuv[0].pac_data != M4OSA_NULL) {
- free(aFramingCtx->FramingYuv[0].pac_data);
- aFramingCtx->FramingYuv[0].pac_data = M4OSA_NULL;
- }
- if (aFramingCtx->FramingYuv[1].pac_data != M4OSA_NULL) {
- free(aFramingCtx->FramingYuv[1].pac_data);
- aFramingCtx->FramingYuv[1].pac_data = M4OSA_NULL;
- }
- if (aFramingCtx->FramingYuv[2].pac_data != M4OSA_NULL) {
- free(aFramingCtx->FramingYuv[2].pac_data);
- aFramingCtx->FramingYuv[2].pac_data = M4OSA_NULL;
- }
-
- free(aFramingCtx->FramingYuv);
- aFramingCtx->FramingYuv = M4OSA_NULL;
- }
- if (aFramingCtx->FramingRgb->pac_data != M4OSA_NULL) {
- free(aFramingCtx->FramingRgb->pac_data);
- aFramingCtx->FramingRgb->pac_data = M4OSA_NULL;
- }
- if (aFramingCtx->FramingRgb != M4OSA_NULL) {
- free(aFramingCtx->FramingRgb);
- aFramingCtx->FramingRgb = M4OSA_NULL;
- }
- if (aFramingCtx != M4OSA_NULL) {
- free(aFramingCtx);
- aFramingCtx = M4OSA_NULL;
- }
- nbOverlays++;
- }
- j++;
- }
-
- // Check if the edit settings could be retrieved.
- M4OSA_TRACE1_1("total clips are = %d",pContext->pEditSettings->uiClipNumber);
- for (i = 0; i < pContext->pEditSettings->uiClipNumber; i++) {
- M4OSA_TRACE1_1("clip no = %d",i);
- properties = pEnv->GetObjectArrayElement(propertiesClipsArray, i);
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == properties),
- "not initialized");
- if (needToBeLoaded) {
- getClipSetting(pEnv,properties, pContext->pEditSettings->pClipList[i]);
- pEnv->DeleteLocalRef(properties);
- } else {
- pEnv->DeleteLocalRef(properties);
- goto videoEditor_populateSettings_cleanup;
- }
- }
-
- if (needToBeLoaded) {
- // Log the edit settings.
- VIDEOEDIT_LOG_EDIT_SETTINGS(pContext->pEditSettings);
- }
- }
- /* free previous allocations , if any */
- if (pContext->mAudioSettings != M4OSA_NULL) {
- if (pContext->mAudioSettings->pFile != NULL) {
- free(pContext->mAudioSettings->pFile);
- pContext->mAudioSettings->pFile = M4OSA_NULL;
- }
- if (pContext->mAudioSettings->pPCMFilePath != NULL) {
- free(pContext->mAudioSettings->pPCMFilePath);
- pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
- }
- }
-
- if (audioSettingObject != M4OSA_NULL) {
- jclass audioSettingClazz = pEnv->FindClass(AUDIO_SETTINGS_CLASS_NAME);
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == audioSettingClazz),
- "not initialized");
-
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext->mAudioSettings),
- "not initialized");
-
- if (needToBeLoaded == false) {
- goto videoEditor_populateSettings_cleanup;
- }
-
- fid = pEnv->GetFieldID(audioSettingClazz,"bRemoveOriginal","Z");
- pContext->mAudioSettings->bRemoveOriginal =
- pEnv->GetBooleanField(audioSettingObject,fid);
- M4OSA_TRACE1_1("bRemoveOriginal = %d",pContext->mAudioSettings->bRemoveOriginal);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"channels","I");
- pContext->mAudioSettings->uiNbChannels = pEnv->GetIntField(audioSettingObject,fid);
- M4OSA_TRACE1_1("uiNbChannels = %d",pContext->mAudioSettings->uiNbChannels);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"Fs","I");
- pContext->mAudioSettings->uiSamplingFrequency = pEnv->GetIntField(audioSettingObject,fid);
- M4OSA_TRACE1_1("uiSamplingFrequency = %d",pContext->mAudioSettings->uiSamplingFrequency);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"ExtendedFs","I");
- pContext->mAudioSettings->uiExtendedSamplingFrequency =
- pEnv->GetIntField(audioSettingObject,fid);
- M4OSA_TRACE1_1("uiExtendedSamplingFrequency = %d",
- pContext->mAudioSettings->uiExtendedSamplingFrequency);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"startMs","J");
- pContext->mAudioSettings->uiAddCts
- = pEnv->GetLongField(audioSettingObject,fid);
- M4OSA_TRACE1_1("uiAddCts = %d",pContext->mAudioSettings->uiAddCts);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"volume","I");
- pContext->mAudioSettings->uiAddVolume
- = pEnv->GetIntField(audioSettingObject,fid);
- M4OSA_TRACE1_1("uiAddVolume = %d",pContext->mAudioSettings->uiAddVolume);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"loop","Z");
- pContext->mAudioSettings->bLoop
- = pEnv->GetBooleanField(audioSettingObject,fid);
- M4OSA_TRACE1_1("bLoop = %d",pContext->mAudioSettings->bLoop);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"beginCutTime","J");
- pContext->mAudioSettings->beginCutMs
- = pEnv->GetLongField(audioSettingObject,fid);
- M4OSA_TRACE1_1("begin cut time = %d",pContext->mAudioSettings->beginCutMs);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"endCutTime","J");
- pContext->mAudioSettings->endCutMs
- = pEnv->GetLongField(audioSettingObject,fid);
- M4OSA_TRACE1_1("end cut time = %d",pContext->mAudioSettings->endCutMs);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"fileType","I");
- pContext->mAudioSettings->fileType
- = pEnv->GetIntField(audioSettingObject,fid);
- M4OSA_TRACE1_1("fileType = %d",pContext->mAudioSettings->fileType);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"pFile","Ljava/lang/String;");
- strPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid);
- pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPath, M4OSA_NULL);
- if (pTempChar != NULL) {
- pContext->mAudioSettings->pFile = (M4OSA_Char*) M4OSA_32bitAlignedMalloc(
- (M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0,
- (M4OSA_Char*)"strPath allocation " );
- if (pContext->mAudioSettings->pFile != M4OSA_NULL) {
- memcpy((void *)pContext->mAudioSettings->pFile ,
- (void *)pTempChar , strlen((const char*)pTempChar));
- ((M4OSA_Int8 *)(pContext->mAudioSettings->pFile))[strlen((const char*)pTempChar)] = '\0';
- pEnv->ReleaseStringUTFChars(strPath,(const char *)pTempChar);
- } else {
- pEnv->ReleaseStringUTFChars(strPath,(const char *)pTempChar);
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "regenerateAudio() Malloc failed for pContext->mAudioSettings->pFile ");
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- M4OSA_TRUE, M4ERR_ALLOC);
- goto videoEditor_populateSettings_cleanup;
- }
- }
- M4OSA_TRACE1_1("file name = %s",pContext->mAudioSettings->pFile);
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio() file name = %s",\
- pContext->mAudioSettings->pFile);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"pcmFilePath","Ljava/lang/String;");
- strPCMPath = (jstring)pEnv->GetObjectField(audioSettingObject,fid);
- pTempChar = (M4OSA_Char*)pEnv->GetStringUTFChars(strPCMPath, M4OSA_NULL);
- if (pTempChar != NULL) {
- pContext->mAudioSettings->pPCMFilePath = (M4OSA_Char*) M4OSA_32bitAlignedMalloc(
- (M4OSA_UInt32)(strlen((const char*)pTempChar))+1 /* +1 for NULL termination */, 0,
- (M4OSA_Char*)"strPCMPath allocation " );
- if (pContext->mAudioSettings->pPCMFilePath != M4OSA_NULL) {
- memcpy((void *)pContext->mAudioSettings->pPCMFilePath ,
- (void *)pTempChar , strlen((const char*)pTempChar));
- ((M4OSA_Int8 *)(pContext->mAudioSettings->pPCMFilePath))[strlen((const char*)pTempChar)] = '\0';
- pEnv->ReleaseStringUTFChars(strPCMPath,(const char *)pTempChar);
- } else {
- pEnv->ReleaseStringUTFChars(strPCMPath,(const char *)pTempChar);
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "regenerateAudio() Malloc failed for pContext->mAudioSettings->pPCMFilePath ");
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- M4OSA_TRUE, M4ERR_ALLOC);
- goto videoEditor_populateSettings_cleanup;
- }
- }
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "pPCMFilePath -- %s ",\
- pContext->mAudioSettings->pPCMFilePath);
-
- fid = pEnv->GetFieldID(engineClass,"mRegenerateAudio","Z");
- bool regenerateAudio = pEnv->GetBooleanField(thiz,fid);
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEOEDITOR", "regenerateAudio -- %d ",\
- regenerateAudio);
-
- if (regenerateAudio) {
- M4OSA_TRACE1_0("Calling Generate Audio now");
- result = videoEditor_generateAudio(pEnv,
- pContext,
- (M4OSA_Char*)pContext->mAudioSettings->pFile,
- (M4OSA_Char*)pContext->mAudioSettings->pPCMFilePath);
-
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
- if (needToBeLoaded == false) {
- goto videoEditor_populateSettings_cleanup;
- }
-
- regenerateAudio = false;
- pEnv->SetBooleanField(thiz,fid,regenerateAudio);
- }
-
- /* Audio mix and duck */
- fid = pEnv->GetFieldID(audioSettingClazz,"ducking_threshold","I");
- pContext->mAudioSettings->uiInDucking_threshold
- = pEnv->GetIntField(audioSettingObject,fid);
-
- M4OSA_TRACE1_1("ducking threshold = %d",
- pContext->mAudioSettings->uiInDucking_threshold);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"ducking_lowVolume","I");
- pContext->mAudioSettings->uiInDucking_lowVolume
- = pEnv->GetIntField(audioSettingObject,fid);
-
- M4OSA_TRACE1_1("ducking lowVolume = %d",
- pContext->mAudioSettings->uiInDucking_lowVolume);
-
- fid = pEnv->GetFieldID(audioSettingClazz,"bInDucking_enable","Z");
- pContext->mAudioSettings->bInDucking_enable
- = pEnv->GetBooleanField(audioSettingObject,fid);
- M4OSA_TRACE1_1("ducking lowVolume = %d",
- pContext->mAudioSettings->bInDucking_enable);
-
- } else {
- if (pContext->mAudioSettings != M4OSA_NULL) {
- pContext->mAudioSettings->pFile = M4OSA_NULL;
- pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
- pContext->mAudioSettings->bRemoveOriginal = 0;
- pContext->mAudioSettings->uiNbChannels = 0;
- pContext->mAudioSettings->uiSamplingFrequency = 0;
- pContext->mAudioSettings->uiExtendedSamplingFrequency = 0;
- pContext->mAudioSettings->uiAddCts = 0;
- pContext->mAudioSettings->uiAddVolume = 0;
- pContext->mAudioSettings->beginCutMs = 0;
- pContext->mAudioSettings->endCutMs = 0;
- pContext->mAudioSettings->fileType = 0;
- pContext->mAudioSettings->bLoop = 0;
- pContext->mAudioSettings->uiInDucking_lowVolume = 0;
- pContext->mAudioSettings->bInDucking_enable = 0;
- pContext->mAudioSettings->uiBTChannelCount = 0;
- pContext->mAudioSettings->uiInDucking_threshold = 0;
-
- fid = pEnv->GetFieldID(engineClass,"mRegenerateAudio","Z");
- bool regenerateAudio = pEnv->GetBooleanField(thiz,fid);
- if (!regenerateAudio) {
- regenerateAudio = true;
- pEnv->SetBooleanField(thiz,fid,regenerateAudio);
- }
- }
- }
-
- if (pContext->pEditSettings != NULL)
- {
- result = pContext->mPreviewController->loadEditSettings(pContext->pEditSettings,
- pContext->mAudioSettings);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
-
- if (needToBeLoaded) {
- pContext->mPreviewController->setJniCallback((void*)pContext,
- (jni_progress_callback_fct)jniPreviewProgressCallback);
- }
- }
-
-videoEditor_populateSettings_cleanup:
- j = 0;
- while (j < nbOverlays)
- {
- if (pContext->pEditSettings->Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data != \
- M4OSA_NULL) {
- free(pContext->pEditSettings->\
- Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data);
- pContext->pEditSettings->\
- Effects[pOverlayIndex[j]].xVSS.pFramingBuffer->pac_data = M4OSA_NULL;
- }
- j++;
- }
-
- j = 0;
- while (j < pContext->pEditSettings->nbEffects)
- {
- if (pContext->pEditSettings->Effects[j].xVSS.pFramingFilePath != M4OSA_NULL) {
- if (pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer != M4OSA_NULL) {
- free(pContext->pEditSettings->\
- Effects[j].xVSS.pFramingBuffer);
- pContext->pEditSettings->Effects[j].xVSS.pFramingBuffer = M4OSA_NULL;
- }
- }
- j++;
- }
-
- if (pOverlayIndex != M4OSA_NULL)
- {
- free(pOverlayIndex);
- pOverlayIndex = M4OSA_NULL;
- }
- return;
-}
-
-static void
-videoEditor_startPreview(
- JNIEnv* pEnv,
- jobject thiz,
- jobject mSurface,
- jlong fromMs,
- jlong toMs,
- jint callbackInterval,
- jboolean loop)
-{
- bool needToBeLoaded = true;
- M4OSA_ERR result = M4NO_ERROR;
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_startPreview()");
-
- ManualEditContext* pContext = M4OSA_NULL;
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext->mAudioSettings),
- "not initialized");
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext->mPreviewController),
- "not initialized");
-
- // Validate the mSurface parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
- (NULL == mSurface),
- "mSurface is null");
-
- sp<Surface> previewSurface = android_view_Surface_getSurface(pEnv, mSurface);
-
- // Validate the mSurface's mNativeSurface field
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (NULL == previewSurface.get()),
- "mNativeSurface is null");
-
- result = pContext->mPreviewController->setSurface(previewSurface);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv,
- (M4NO_ERROR != result), result);
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "fromMs=%ld, toMs=%ld",
- (M4OSA_UInt32)fromMs, (M4OSA_Int32)toMs);
-
- result = pContext->mPreviewController->startPreview((M4OSA_UInt32)fromMs,
- (M4OSA_Int32)toMs,
- (M4OSA_UInt16)callbackInterval,
- (M4OSA_Bool)loop);
- videoEditJava_checkAndThrowRuntimeException(&needToBeLoaded, pEnv, (M4NO_ERROR != result), result);
-}
-
-
-static jobject
-videoEditor_getProperties(
- JNIEnv* pEnv,
- jobject thiz,
- jstring file)
-{
- jobject object = M4OSA_NULL;
- jclass clazz = pEnv->FindClass(PROPERTIES_CLASS_NAME);
- jfieldID fid;
- bool needToBeLoaded = true;
- ManualEditContext* pContext = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
- int profile = 0;
- int level = 0;
- int videoFormat = 0;
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
-
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == clazz),
- "not initialized");
-
- object = videoEditProp_getProperties(pEnv,thiz,file);
-
- if (object != M4OSA_NULL) {
- fid = pEnv->GetFieldID(clazz,"profile","I");
- profile = pEnv->GetIntField(object,fid);
- fid = pEnv->GetFieldID(clazz,"level","I");
- level = pEnv->GetIntField(object,fid);
- fid = pEnv->GetFieldID(clazz,"videoFormat","I");
- videoFormat = pEnv->GetIntField(object,fid);
-
- result = checkClipVideoProfileAndLevel(pContext->decoders, videoFormat, profile, level);
-
- fid = pEnv->GetFieldID(clazz,"profileSupported","Z");
- if (M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_PROFILE == result) {
- pEnv->SetBooleanField(object,fid,false);
- }
-
- fid = pEnv->GetFieldID(clazz,"levelSupported","Z");
- if (M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_LEVEL == result) {
- pEnv->SetBooleanField(object,fid,false);
- }
- }
- return object;
-
-}
-static jint videoEditor_getPixels(
- JNIEnv* env,
- jobject thiz,
- jstring path,
- jintArray pixelArray,
- M4OSA_UInt32 width,
- M4OSA_UInt32 height,
- M4OSA_UInt32 timeMS)
-{
-
- M4OSA_ERR err = M4NO_ERROR;
- M4OSA_Context mContext = M4OSA_NULL;
- jint* m_dst32 = M4OSA_NULL;
-
- const char *pString = env->GetStringUTFChars(path, NULL);
- if (pString == M4OSA_NULL) {
- if (env != NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Input string null");
- }
- return M4ERR_ALLOC;
- }
-
- err = ThumbnailOpen(&mContext,(const M4OSA_Char*)pString, M4OSA_FALSE);
- if (err != M4NO_ERROR || mContext == M4OSA_NULL) {
- if (pString != NULL) {
- env->ReleaseStringUTFChars(path, pString);
- }
- if (env != NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "ThumbnailOpen failed");
- }
- }
-
- m_dst32 = env->GetIntArrayElements(pixelArray, NULL);
-
- err = ThumbnailGetPixels32(mContext, (M4OSA_Int32 *)m_dst32, width,height,&timeMS,0);
- if (err != M4NO_ERROR ) {
- if (env != NULL) {
- jniThrowException(env, "java/lang/RuntimeException",\
- "ThumbnailGetPixels32 failed");
- }
- }
- env->ReleaseIntArrayElements(pixelArray, m_dst32, 0);
-
- ThumbnailClose(mContext);
- if (pString != NULL) {
- env->ReleaseStringUTFChars(path, pString);
- }
-
- return (jint)timeMS;
-}
-
-static jint videoEditor_getPixelsList(
- JNIEnv* env,
- jobject thiz,
- jstring path,
- jintArray pixelArray,
- M4OSA_UInt32 width,
- M4OSA_UInt32 height,
- M4OSA_UInt32 noOfThumbnails,
- jlong startTime,
- jlong endTime,
- jintArray indexArray,
- jobject callback)
-{
-
- M4OSA_ERR err = M4NO_ERROR;
- M4OSA_Context mContext = M4OSA_NULL;
-
- const char *pString = env->GetStringUTFChars(path, NULL);
- if (pString == M4OSA_NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Input string null");
- return (jint)M4ERR_ALLOC;
- }
-
- err = ThumbnailOpen(&mContext,(const M4OSA_Char*)pString, M4OSA_FALSE);
- if (err != M4NO_ERROR || mContext == M4OSA_NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "ThumbnailOpen failed");
- if (pString != NULL) {
- env->ReleaseStringUTFChars(path, pString);
- }
- return (jint)err;
- }
-
- jlong duration = (endTime - startTime);
- M4OSA_UInt32 tolerance = duration / (2 * noOfThumbnails);
- jint* m_dst32 = env->GetIntArrayElements(pixelArray, NULL);
- jint* indices = env->GetIntArrayElements(indexArray, NULL);
- jsize len = env->GetArrayLength(indexArray);
-
- jclass cls = env->GetObjectClass(callback);
- jmethodID mid = env->GetMethodID(cls, "onThumbnail", "(I)V");
-
- for (int i = 0; i < len; i++) {
- int k = indices[i];
- M4OSA_UInt32 timeMS = startTime;
- timeMS += (2 * k + 1) * duration / (2 * noOfThumbnails);
- err = ThumbnailGetPixels32(mContext, ((M4OSA_Int32 *)m_dst32),
- width, height, &timeMS, tolerance);
- if (err != M4NO_ERROR) {
- break;
- }
- env->CallVoidMethod(callback, mid, (jint)k);
- if (env->ExceptionCheck()) {
- err = M4ERR_ALLOC;
- break;
- }
- }
-
- env->ReleaseIntArrayElements(pixelArray, m_dst32, 0);
- env->ReleaseIntArrayElements(indexArray, indices, 0);
-
- ThumbnailClose(mContext);
- if (pString != NULL) {
- env->ReleaseStringUTFChars(path, pString);
- }
-
- if (err != M4NO_ERROR && !env->ExceptionCheck()) {
- jniThrowException(env, "java/lang/RuntimeException",\
- "ThumbnailGetPixels32 failed");
- }
-
- return (jint)err;
-}
-
-static M4OSA_ERR
-videoEditor_toUTF8Fct(
- M4OSA_Void* pBufferIn,
- M4OSA_UInt8* pBufferOut,
- M4OSA_UInt32* bufferOutSize)
-{
- M4OSA_ERR result = M4NO_ERROR;
- M4OSA_UInt32 length = 0;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_toUTF8Fct()");
-
- // Determine the length of the input buffer.
- if (M4OSA_NULL != pBufferIn)
- {
- length = strlen((const char *)pBufferIn);
- }
-
- // Check if the output buffer is large enough to hold the input buffer.
- if ((*bufferOutSize) > length)
- {
- // Check if the input buffer is not M4OSA_NULL.
- if (M4OSA_NULL != pBufferIn)
- {
- // Copy the temp path, ignore the result.
- M4OSA_chrNCopy((M4OSA_Char *)pBufferOut, (M4OSA_Char *)pBufferIn, length);
- }
- else
- {
- // Set the output buffer to an empty string.
- (*(M4OSA_Char *)pBufferOut) = 0;
- }
- }
- else
- {
- // The buffer is too small.
- result = M4xVSSWAR_BUFFER_OUT_TOO_SMALL;
- }
-
- // Return the buffer output size.
- (*bufferOutSize) = length + 1;
-
- // Return the result.
- return(result);
-}
-
-static M4OSA_ERR
-videoEditor_fromUTF8Fct(
- M4OSA_UInt8* pBufferIn,
- M4OSA_Void* pBufferOut,
- M4OSA_UInt32* bufferOutSize)
-{
- M4OSA_ERR result = M4NO_ERROR;
- M4OSA_UInt32 length = 0;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_fromUTF8Fct()");
-
- // Determine the length of the input buffer.
- if (M4OSA_NULL != pBufferIn)
- {
- length = strlen((const char *)pBufferIn);
- }
-
- // Check if the output buffer is large enough to hold the input buffer.
- if ((*bufferOutSize) > length)
- {
- // Check if the input buffer is not M4OSA_NULL.
- if (M4OSA_NULL != pBufferIn)
- {
- // Copy the temp path, ignore the result.
- M4OSA_chrNCopy((M4OSA_Char *)pBufferOut, (M4OSA_Char *)pBufferIn, length);
- }
- else
- {
- // Set the output buffer to an empty string.
- (*(M4OSA_Char *)pBufferOut) = 0;
- }
- }
- else
- {
- // The buffer is too small.
- result = M4xVSSWAR_BUFFER_OUT_TOO_SMALL;
- }
-
- // Return the buffer output size.
- (*bufferOutSize) = length + 1;
-
- // Return the result.
- return(result);
-}
-
-static M4OSA_ERR
-videoEditor_getTextRgbBufferFct(
- M4OSA_Void* pRenderingData,
- M4OSA_Void* pTextBuffer,
- M4OSA_UInt32 textBufferSize,
- M4VIFI_ImagePlane** pOutputPlane)
-{
- M4OSA_ERR result = M4NO_ERROR;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getTextRgbBufferFct()");
-
- // Return the result.
- return(result);
-}
-
-static void
-videoEditor_callOnProgressUpdate(
- ManualEditContext* pContext,
- int task,
- int progress)
-{
- JNIEnv* pEnv = NULL;
-
-
- // Attach the current thread.
- pContext->pVM->AttachCurrentThread(&pEnv, NULL);
-
-
- // Call the on completion callback.
- pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId,
- videoEditJava_getEngineCToJava(task), progress);
-
-
- // Detach the current thread.
- pContext->pVM->DetachCurrentThread();
-}
-
-static void
-videoEditor_freeContext(
- JNIEnv* pEnv,
- ManualEditContext** ppContext)
-{
- ManualEditContext* pContext = M4OSA_NULL;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_freeContext");
-
- // Set the context pointer.
- pContext = (*ppContext);
-
- // Check if the context was set.
- if (M4OSA_NULL != pContext)
- {
- // Check if a global reference to the engine object was set.
- if (NULL != pContext->engine)
- {
- // Free the global reference.
- pEnv->DeleteGlobalRef(pContext->engine);
- pContext->engine = NULL;
- }
-
- // Check if the temp path was set.
- if (M4OSA_NULL != pContext->initParams.pTempPath)
- {
- // Free the memory allocated for the temp path.
- videoEditOsal_free(pContext->initParams.pTempPath);
- pContext->initParams.pTempPath = M4OSA_NULL;
- }
-
- // Check if the file writer was set.
- if (M4OSA_NULL != pContext->initParams.pFileWritePtr)
- {
- // Free the memory allocated for the file writer.
- videoEditOsal_free(pContext->initParams.pFileWritePtr);
- pContext->initParams.pFileWritePtr = M4OSA_NULL;
- }
-
- // Check if the file reader was set.
- if (M4OSA_NULL != pContext->initParams.pFileReadPtr)
- {
- // Free the memory allocated for the file reader.
- videoEditOsal_free(pContext->initParams.pFileReadPtr);
- pContext->initParams.pFileReadPtr = M4OSA_NULL;
- }
-
- // Free the memory allocated for the context.
- videoEditOsal_free(pContext);
- pContext = M4OSA_NULL;
-
- // Reset the context pointer.
- (*ppContext) = M4OSA_NULL;
- }
-}
-
-static jobject
-videoEditor_getVersion(
- JNIEnv* pEnv,
- jobject thiz)
-{
- bool isSuccessful = true;
- jobject version = NULL;
- M4_VersionInfo versionInfo = {0, 0, 0, 0};
- M4OSA_ERR result = M4NO_ERROR;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getVersion()");
-
- versionInfo.m_structSize = sizeof(versionInfo);
- versionInfo.m_major = VIDEOEDITOR_VERSION_MAJOR;
- versionInfo.m_minor = VIDEOEDITOR_VERSION_MINOR;
- versionInfo.m_revision = VIDEOEDITOR_VERSION_REVISION;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_getVersion() major %d,\
- minor %d, revision %d", versionInfo.m_major, versionInfo.m_minor, versionInfo.m_revision);
-
- // Create a version object.
- videoEditClasses_createVersion(&isSuccessful, pEnv, &versionInfo, &version);
-
- // Return the version object.
- return(version);
-}
-
-static void
-videoEditor_init(
- JNIEnv* pEnv,
- jobject thiz,
- jstring tempPath,
- jstring libraryPath)
-{
- bool initialized = true;
- ManualEditContext* pContext = M4OSA_NULL;
- VideoEditJava_EngineMethodIds methodIds = {NULL};
- M4OSA_Char* pLibraryPath = M4OSA_NULL;
- M4OSA_Char* pTextRendererPath = M4OSA_NULL;
- M4OSA_UInt32 textRendererPathLength = 0;
- M4OSA_ERR result = M4NO_ERROR;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_init()");
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&initialized, pEnv, thiz);
-
- // Get the engine method ids.
- videoEditJava_getEngineMethodIds(&initialized, pEnv, &methodIds);
-
- // Validate the tempPath parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(&initialized, pEnv,
- (NULL == tempPath),
- "tempPath is null");
-
- // Make sure that the context was not set already.
- videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
- (M4OSA_NULL != pContext),
- "already initialized");
-
- // Check if the initialization succeeded (required because of dereferencing of psContext,
- // and freeing when initialization fails).
- if (initialized)
- {
- // Allocate a new context.
- pContext = new ManualEditContext;
-
- // Check if the initialization succeeded (required because of dereferencing of psContext).
- //if (initialized)
- if (pContext != NULL)
- {
- // Set the state to not initialized.
- pContext->state = ManualEditState_NOT_INITIALIZED;
-
- // Allocate a file read pointer structure.
- pContext->initParams.pFileReadPtr =
- (M4OSA_FileReadPointer*)videoEditOsal_alloc(&initialized, pEnv,
- sizeof(M4OSA_FileReadPointer), "FileReadPointer");
-
- // Allocate a file write pointer structure.
- pContext->initParams.pFileWritePtr =
- (M4OSA_FileWriterPointer*)videoEditOsal_alloc(&initialized, pEnv,
- sizeof(M4OSA_FileWriterPointer), "FileWriterPointer");
-
- // Get the temp path.
- M4OSA_Char* tmpString =
- (M4OSA_Char *)videoEditJava_getString(&initialized, pEnv, tempPath,
- NULL, M4OSA_NULL);
- M4OSA_UInt32 length = strlen((const char *)tmpString);
- // Malloc additional 2 bytes for beginning and tail separator.
- M4OSA_UInt32 pathLength = length + 2;
-
- pContext->initParams.pTempPath = (M4OSA_Char *)
- M4OSA_32bitAlignedMalloc(pathLength, 0x0, (M4OSA_Char *)"tempPath");
-
- //initialize the first char. so that strcat works.
- M4OSA_Char *ptmpChar = (M4OSA_Char*)pContext->initParams.pTempPath;
- ptmpChar[0] = 0x00;
- strncat((char *)pContext->initParams.pTempPath, (const char *)tmpString,
- length);
- strncat((char *)pContext->initParams.pTempPath, (const char *)"/", (size_t)1);
- free(tmpString);
- tmpString = NULL;
- pContext->mIsUpdateOverlay = false;
- pContext->mOverlayFileName = NULL;
- pContext->decoders = NULL;
- }
-
- // Check if the initialization succeeded
- // (required because of dereferencing of pContext, pFileReadPtr and pFileWritePtr).
- if (initialized)
- {
-
- // Initialize the OSAL file system function pointers.
- videoEditOsal_getFilePointers(pContext->initParams.pFileReadPtr ,
- pContext->initParams.pFileWritePtr);
-
- // Set the UTF8 conversion functions.
- pContext->initParams.pConvToUTF8Fct = videoEditor_toUTF8Fct;
- pContext->initParams.pConvFromUTF8Fct = videoEditor_fromUTF8Fct;
-
- // Set the callback method ids.
- pContext->onProgressUpdateMethodId = methodIds.onProgressUpdate;
-
- // Set the virtual machine.
- pEnv->GetJavaVM(&(pContext->pVM));
-
- // Create a global reference to the engine object.
- pContext->engine = pEnv->NewGlobalRef(thiz);
-
- // Check if the global reference could be created.
- videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv,
- (NULL == pContext->engine), M4NO_ERROR);
- }
-
- // Check if the initialization succeeded (required because of dereferencing of pContext).
- if (initialized)
- {
- // Log the API call.
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "M4xVSS_Init()");
-
- // Initialize the visual studio library.
- result = M4xVSS_Init(&pContext->engineContext, &pContext->initParams);
-
- // Log the result.
- VIDEOEDIT_LOG_RESULT(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- videoEditOsal_getResultString(result));
-
- // Check if the library could be initialized.
- videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv,
- (M4NO_ERROR != result), result);
-
- // Get platform video decoder capablities.
- result = M4xVSS_getVideoDecoderCapabilities(&pContext->decoders);
-
- videoEditJava_checkAndThrowRuntimeException(&initialized, pEnv,
- (M4NO_ERROR != result), result);
- }
-
- if(initialized)
- {
- pContext->mPreviewController = new VideoEditorPreviewController();
- videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
- (M4OSA_NULL == pContext->mPreviewController),
- "not initialized");
- pContext->mAudioSettings =
- (M4xVSS_AudioMixingSettings *)
- M4OSA_32bitAlignedMalloc(sizeof(M4xVSS_AudioMixingSettings),0x0,
- (M4OSA_Char *)"mAudioSettings");
- videoEditJava_checkAndThrowIllegalStateException(&initialized, pEnv,
- (M4OSA_NULL == pContext->mAudioSettings),
- "not initialized");
- pContext->mAudioSettings->pFile = M4OSA_NULL;
- pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
- pContext->mAudioSettings->bRemoveOriginal = 0;
- pContext->mAudioSettings->uiNbChannels = 0;
- pContext->mAudioSettings->uiSamplingFrequency = 0;
- pContext->mAudioSettings->uiExtendedSamplingFrequency = 0;
- pContext->mAudioSettings->uiAddCts = 0;
- pContext->mAudioSettings->uiAddVolume = 0;
- pContext->mAudioSettings->beginCutMs = 0;
- pContext->mAudioSettings->endCutMs = 0;
- pContext->mAudioSettings->fileType = 0;
- pContext->mAudioSettings->bLoop = 0;
- pContext->mAudioSettings->uiInDucking_lowVolume = 0;
- pContext->mAudioSettings->bInDucking_enable = 0;
- pContext->mAudioSettings->uiBTChannelCount = 0;
- pContext->mAudioSettings->uiInDucking_threshold = 0;
- }
- // Check if the library could be initialized.
- if (initialized)
- {
- // Set the state to initialized.
- pContext->state = ManualEditState_INITIALIZED;
- }
-
- // Set the context.
- videoEditClasses_setContext(&initialized, pEnv, thiz, (void* )pContext);
- pLibraryPath = M4OSA_NULL;
-
- pContext->pEditSettings = M4OSA_NULL;
- // Cleanup if anything went wrong during initialization.
- if (!initialized)
- {
- // Free the context.
- videoEditor_freeContext(pEnv, &pContext);
- }
- }
-}
-
-/*+ PROGRESS CB */
-static
-M4OSA_ERR videoEditor_processClip(
- JNIEnv* pEnv,
- jobject thiz,
- int unuseditemID) {
-
- bool loaded = true;
- ManualEditContext* pContext = NULL;
- M4OSA_UInt8 progress = 0;
- M4OSA_UInt8 progressBase = 0;
- M4OSA_UInt8 lastProgress = 0;
- M4OSA_ERR result = M4NO_ERROR;
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&loaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- // We start in Analyzing state
- pContext->state = ManualEditState_INITIALIZED;
- M4OSA_ERR completionResult = M4VSS3GPP_WAR_ANALYZING_DONE;
- ManualEditState completionState = ManualEditState_OPENED;
- ManualEditState errorState = ManualEditState_ANALYZING_ERROR;
-
- // While analyzing progress goes from 0 to 10 (except Kenburn clip
- // generation, which goes from 0 to 50)
- progressBase = 0;
-
- // Set the text rendering function.
- if (M4OSA_NULL != pContext->pTextRendererFunction)
- {
- // Use the text renderer function in the library.
- pContext->pEditSettings->xVSS.pTextRenderingFct = pContext->pTextRendererFunction;
- }
- else
- {
- // Use the internal text renderer function.
- pContext->pEditSettings->xVSS.pTextRenderingFct = videoEditor_getTextRgbBufferFct;
- }
-
- // Send the command.
- ALOGV("videoEditor_processClip ITEM %d Calling M4xVSS_SendCommand()", unuseditemID);
- result = M4xVSS_SendCommand(pContext->engineContext, pContext->pEditSettings);
- ALOGV("videoEditor_processClip ITEM %d M4xVSS_SendCommand() returned 0x%x",
- unuseditemID, (unsigned int) result);
-
- // Remove warnings indications (we only care about errors here)
- if ((result == M4VSS3GPP_WAR_TRANSCODING_NECESSARY)
- || (result == M4VSS3GPP_WAR_OUTPUTFILESIZE_EXCEED)) {
- result = M4NO_ERROR;
- }
-
- // Send the first progress indication (=0)
- ALOGV("VERY FIRST PROGRESS videoEditor_processClip ITEM %d Progress indication %d",
- unuseditemID, progress);
- pEnv->CallVoidMethod(pContext->engine, pContext->onProgressUpdateMethodId,
- unuseditemID, progress);
-
- // Check if a task is being performed.
- // ??? ADD STOPPING MECHANISM
- ALOGV("videoEditor_processClip Entering processing loop");
- M4OSA_UInt8 prevReportedProgress = 0;
- while((result == M4NO_ERROR)
- &&(pContext->state!=ManualEditState_SAVED)
- &&(pContext->state!=ManualEditState_STOPPING)) {
-
- // Perform the next processing step.
- //ALOGV("LVME_processClip Entering M4xVSS_Step()");
- result = M4xVSS_Step(pContext->engineContext, &progress);
-
- if (progress != prevReportedProgress) {
- prevReportedProgress = progress;
- // Log the 1 % .. 100 % progress after processing.
- if (M4OSA_TRUE ==
- pContext->pEditSettings->pClipList[0]->xVSS.isPanZoom) {
- // For KenBurn clip generation, return 0 to 50
- // for Analysis phase and 50 to 100 for Saving phase
- progress = progressBase + progress/2;
- } else {
- // For export/transition clips, 0 to 10 for Analysis phase
- // and 10 to 100 for Saving phase
- if (ManualEditState_INITIALIZED == pContext->state) {
- progress = 0.1*progress;
- } else {
- progress = progressBase + 0.9*progress;
- }
- }
-
- if (progress > lastProgress)
- {
- // Send a progress notification.
- ALOGV("videoEditor_processClip ITEM %d Progress indication %d",
- unuseditemID, progress);
- pEnv->CallVoidMethod(pContext->engine,
- pContext->onProgressUpdateMethodId,
- unuseditemID, progress);
- lastProgress = progress;
- }
- }
-
- // Check if processing has been completed.
- if (result == completionResult)
- {
- // Set the state to the completions state.
- pContext->state = completionState;
- ALOGV("videoEditor_processClip ITEM %d STATE changed to %d",
- unuseditemID, pContext->state);
-
- // Reset progress indication, as we switch to next state
- lastProgress = 0;
-
- // Reset error code, as we start a new round of processing
- result = M4NO_ERROR;
-
- // Check if we are analyzing input
- if (pContext->state == ManualEditState_OPENED) {
- // File is opened, we must start saving it
- ALOGV("videoEditor_processClip Calling M4xVSS_SaveStart()");
- result = M4xVSS_SaveStart(pContext->engineContext,
- (M4OSA_Char*)pContext->pEditSettings->pOutputFile,
- (M4OSA_UInt32)pContext->pEditSettings->uiOutputPathSize);
- ALOGV("videoEditor_processClip ITEM %d SaveStart() returned 0x%x",
- unuseditemID, (unsigned int) result);
-
- // Set the state to saving.
- pContext->state = ManualEditState_SAVING;
- completionState = ManualEditState_SAVED;
- completionResult = M4VSS3GPP_WAR_SAVING_DONE;
- errorState = ManualEditState_SAVING_ERROR;
-
- // While saving, progress goes from 10 to 100
- // except for Kenburn clip which goes from 50 to 100
- if (M4OSA_TRUE ==
- pContext->pEditSettings->pClipList[0]->xVSS.isPanZoom) {
- progressBase = 50;
- } else {
- progressBase = 10;
- }
- }
- // Check if we encoding is ongoing
- else if (pContext->state == ManualEditState_SAVED) {
-
- // Send a progress notification.
- progress = 100;
- ALOGV("videoEditor_processClip ITEM %d Last progress indication %d",
- unuseditemID, progress);
- pEnv->CallVoidMethod(pContext->engine,
- pContext->onProgressUpdateMethodId,
- unuseditemID, progress);
-
-
- // Stop the encoding.
- ALOGV("videoEditor_processClip Calling M4xVSS_SaveStop()");
- result = M4xVSS_SaveStop(pContext->engineContext);
- ALOGV("videoEditor_processClip M4xVSS_SaveStop() returned 0x%x", result);
- }
- // Other states are unexpected
- else {
- result = M4ERR_STATE;
- ALOGE("videoEditor_processClip ITEM %d State ERROR 0x%x",
- unuseditemID, (unsigned int) result);
- }
- }
-
- // Check if an error occurred.
- if (result != M4NO_ERROR)
- {
- // Set the state to the error state.
- pContext->state = errorState;
-
- // Log the result.
- ALOGE("videoEditor_processClip ITEM %d Processing ERROR 0x%x",
- unuseditemID, (unsigned int) result);
- }
- }
-
- // Return the error result
- ALOGE("videoEditor_processClip ITEM %d END 0x%x", unuseditemID, (unsigned int) result);
- return result;
-}
-/*+ PROGRESS CB */
-
-static jint
-videoEditor_generateClip(
- JNIEnv* pEnv,
- jobject thiz,
- jobject settings) {
- bool loaded = true;
- ManualEditContext* pContext = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
-
- ALOGV("videoEditor_generateClip START");
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&loaded, pEnv, thiz);
-
- Mutex::Autolock autoLock(pContext->mLock);
-
- // Validate the settings parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(&loaded, pEnv,
- (NULL == settings),
- "settings is null");
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&loaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- // Load the clip settings
- ALOGV("videoEditor_generateClip Calling videoEditor_loadSettings");
- videoEditor_loadSettings(pEnv, thiz, settings);
- ALOGV("videoEditor_generateClip videoEditor_loadSettings returned");
-
- // Generate the clip
- ALOGV("videoEditor_generateClip Calling LVME_processClip");
- result = videoEditor_processClip(pEnv, thiz, 0 /*item id is unused*/);
- ALOGV("videoEditor_generateClip videoEditor_processClip returned 0x%x", result);
-
- if (pContext->state != ManualEditState_INITIALIZED) {
- // Free up memory (whatever the result)
- videoEditor_unloadSettings(pEnv, thiz);
- }
-
- ALOGV("videoEditor_generateClip END 0x%x", (unsigned int) result);
- return (jint)result;
-}
-
-static void
-videoEditor_loadSettings(
- JNIEnv* pEnv,
- jobject thiz,
- jobject settings)
-{
- bool needToBeLoaded = true;
- ManualEditContext* pContext = M4OSA_NULL;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_loadSettings()");
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded,
- pEnv, thiz);
-
- // Validate the settings parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(&needToBeLoaded, pEnv,
- (NULL == settings),
- "settings is null");
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- // Check if the context is valid (required because the context is dereferenced).
- if (needToBeLoaded)
- {
- // Make sure that we are in a correct state.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeLoaded, pEnv,
- (pContext->state != ManualEditState_INITIALIZED),
- "settings already loaded");
-
- // Retrieve the edit settings.
- if(pContext->pEditSettings != M4OSA_NULL) {
- videoEditClasses_freeEditSettings(&pContext->pEditSettings);
- pContext->pEditSettings = M4OSA_NULL;
- }
- videoEditClasses_getEditSettings(&needToBeLoaded, pEnv, settings,
- &pContext->pEditSettings,true);
- }
-
- // Check if the edit settings could be retrieved.
- if (needToBeLoaded)
- {
- // Log the edit settings.
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "inside load settings");
- VIDEOEDIT_LOG_EDIT_SETTINGS(pContext->pEditSettings);
- }
- ALOGV("videoEditor_loadSettings END");
-}
-
-
-
-static void
-videoEditor_unloadSettings(
- JNIEnv* pEnv,
- jobject thiz)
-{
- bool needToBeUnLoaded = true;
- ManualEditContext* pContext = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_unloadSettings()");
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeUnLoaded, pEnv, thiz);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeUnLoaded, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- // Check if the context is valid (required because the context is dereferenced).
- if (needToBeUnLoaded)
- {
- ALOGV("videoEditor_unloadSettings state %d", pContext->state);
- // Make sure that we are in a correct state.
- videoEditJava_checkAndThrowIllegalStateException(&needToBeUnLoaded, pEnv,
- ((pContext->state != ManualEditState_ANALYZING ) &&
- (pContext->state != ManualEditState_ANALYZING_ERROR) &&
- (pContext->state != ManualEditState_OPENED ) &&
- (pContext->state != ManualEditState_SAVING_ERROR ) &&
- (pContext->state != ManualEditState_SAVED ) &&
- (pContext->state != ManualEditState_STOPPING ) ),
- "videoEditor_unloadSettings no load settings in progress");
- }
-
- // Check if we are in a correct state.
- if (needToBeUnLoaded)
- {
- // Check if the thread could be stopped.
- if (needToBeUnLoaded)
- {
- // Close the command.
- ALOGV("videoEditor_unloadSettings Calling M4xVSS_CloseCommand()");
- result = M4xVSS_CloseCommand(pContext->engineContext);
- ALOGV("videoEditor_unloadSettings M4xVSS_CloseCommand() returned 0x%x",
- (unsigned int)result);
-
- // Check if the command could be closed.
- videoEditJava_checkAndThrowRuntimeException(&needToBeUnLoaded, pEnv,
- (M4NO_ERROR != result), result);
- }
-
- // Check if the command could be closed.
- if (needToBeUnLoaded)
- {
- // Free the edit settings.
- //videoEditClasses_freeEditSettings(&pContext->pEditSettings);
-
- // Reset the thread result.
- pContext->threadResult = M4NO_ERROR;
-
- // Reset the thread progress.
- pContext->threadProgress = 0;
-
- // Set the state to initialized.
- pContext->state = ManualEditState_INITIALIZED;
- }
- }
-}
-
-static void
-videoEditor_stopEncoding(
- JNIEnv* pEnv,
- jobject thiz)
-{
- bool stopped = true;
- ManualEditContext* pContext = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
-
- ALOGV("videoEditor_stopEncoding START");
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&stopped, pEnv, thiz);
-
- // Change state and get Lock
- // This will ensure the generateClip function exits
- pContext->state = ManualEditState_STOPPING;
- Mutex::Autolock autoLock(pContext->mLock);
-
- // Make sure that the context was set.
- videoEditJava_checkAndThrowIllegalStateException(&stopped, pEnv,
- (M4OSA_NULL == pContext),
- "not initialized");
-
- if (stopped) {
-
- // Check if the command should be closed.
- if (pContext->state != ManualEditState_INITIALIZED)
- {
- // Close the command.
- ALOGV("videoEditor_stopEncoding Calling M4xVSS_CloseCommand()");
- result = M4xVSS_CloseCommand(pContext->engineContext);
- ALOGV("videoEditor_stopEncoding M4xVSS_CloseCommand() returned 0x%x",
- (unsigned int)result);
- }
-
- // Check if the command could be closed.
- videoEditJava_checkAndThrowRuntimeException(&stopped, pEnv,
- (M4NO_ERROR != result), result);
-
- // Free the edit settings.
- videoEditClasses_freeEditSettings(&pContext->pEditSettings);
-
- // Set the state to initialized.
- pContext->state = ManualEditState_INITIALIZED;
- }
-
-}
-
-static void
-videoEditor_release(
- JNIEnv* pEnv,
- jobject thiz)
-{
- bool released = true;
- ManualEditContext* pContext = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "videoEditor_release()");
-
- // Get the context.
- pContext = (ManualEditContext*)videoEditClasses_getContext(&released, pEnv, thiz);
-
- // If context is not set, return (we consider release already happened)
- if (pContext == NULL) {
- ALOGV("videoEditor_release Nothing to do, context is aleady NULL");
- return;
- }
-
-
- // Check if the context is valid (required because the context is dereferenced).
- if (released)
- {
- if (pContext->state != ManualEditState_INITIALIZED)
- {
- // Change state and get Lock
- // This will ensure the generateClip function exits if it is running
- pContext->state = ManualEditState_STOPPING;
- Mutex::Autolock autoLock(pContext->mLock);
- }
-
- // Reset the context.
- videoEditClasses_setContext(&released, pEnv, thiz, (void *)M4OSA_NULL);
-
- // Check if the command should be closed.
- if (pContext->state != ManualEditState_INITIALIZED)
- {
- // Close the command.
- ALOGV("videoEditor_release Calling M4xVSS_CloseCommand() state =%d",
- pContext->state);
- result = M4xVSS_CloseCommand(pContext->engineContext);
- ALOGV("videoEditor_release M4xVSS_CloseCommand() returned 0x%x",
- (unsigned int)result);
-
- // Check if the command could be closed.
- videoEditJava_checkAndThrowRuntimeException(&released, pEnv,
- (M4NO_ERROR != result), result);
- }
-
- // Cleanup the engine.
- ALOGV("videoEditor_release Calling M4xVSS_CleanUp()");
- result = M4xVSS_CleanUp(pContext->engineContext);
- ALOGV("videoEditor_release M4xVSS_CleanUp() returned 0x%x", (unsigned int)result);
-
- // Check if the cleanup succeeded.
- videoEditJava_checkAndThrowRuntimeException(&released, pEnv,
- (M4NO_ERROR != result), result);
-
- // Free the edit settings.
- videoEditClasses_freeEditSettings(&pContext->pEditSettings);
- pContext->pEditSettings = M4OSA_NULL;
-
-
- if(pContext->mPreviewController != M4OSA_NULL)
- {
- delete pContext->mPreviewController;
- pContext->mPreviewController = M4OSA_NULL;
- }
-
- // Free the mAudioSettings context.
- if(pContext->mAudioSettings != M4OSA_NULL)
- {
- if (pContext->mAudioSettings->pFile != NULL) {
- free(pContext->mAudioSettings->pFile);
- pContext->mAudioSettings->pFile = M4OSA_NULL;
- }
- if (pContext->mAudioSettings->pPCMFilePath != NULL) {
- free(pContext->mAudioSettings->pPCMFilePath);
- pContext->mAudioSettings->pPCMFilePath = M4OSA_NULL;
- }
-
- free(pContext->mAudioSettings);
- pContext->mAudioSettings = M4OSA_NULL;
- }
- // Free video Decoders capabilities
- if (pContext->decoders != M4OSA_NULL) {
- VideoDecoder *pDecoder = NULL;
- VideoComponentCapabilities *pComponents = NULL;
- int32_t decoderNumber = pContext->decoders->decoderNumber;
- if (pContext->decoders->decoder != NULL &&
- decoderNumber > 0) {
- pDecoder = pContext->decoders->decoder;
- for (int32_t k = 0; k < decoderNumber; k++) {
- // free each component
- ALOGV("decoder index :%d",k);
- if (pDecoder != NULL &&
- pDecoder->component != NULL &&
- pDecoder->componentNumber > 0) {
- ALOGV("component number %d",pDecoder->componentNumber);
- int32_t componentNumber =
- pDecoder->componentNumber;
-
- pComponents = pDecoder->component;
- for (int32_t i = 0; i< componentNumber; i++) {
- ALOGV("component index :%d",i);
- if (pComponents != NULL &&
- pComponents->profileLevel != NULL) {
- free(pComponents->profileLevel);
- pComponents->profileLevel = NULL;
- }
- pComponents++;
- }
- free(pDecoder->component);
- pDecoder->component = NULL;
- }
-
- pDecoder++;
- }
- free(pContext->decoders->decoder);
- pContext->decoders->decoder = NULL;
- }
- free(pContext->decoders);
- pContext->decoders = NULL;
- }
-
- videoEditor_freeContext(pEnv, &pContext);
- }
-}
-
-static int
-videoEditor_registerManualEditMethods(
- JNIEnv* pEnv)
-{
- int result = -1;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_registerManualEditMethods()");
-
- // Look up the engine class
- jclass engineClazz = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
-
- // Clear any resulting exceptions.
- pEnv->ExceptionClear();
-
- // Check if the engine class was found.
- if (NULL != engineClazz)
- {
- // Register all the methods.
- if (pEnv->RegisterNatives(engineClazz, gManualEditMethods,
- sizeof(gManualEditMethods) / sizeof(gManualEditMethods[0])) == JNI_OK)
- {
- // Success.
- result = 0;
- }
- }
-
- // Return the result.
- return(result);
-}
-
-/*******Audio Graph*******/
-
-static M4OSA_UInt32 getDecibelSound(M4OSA_UInt32 value)
-{
- int dbSound = 1;
-
- if (value == 0) return 0;
-
- if (value > 0x4000 && value <= 0x8000) // 32768
- dbSound = 90;
- else if (value > 0x2000 && value <= 0x4000) // 16384
- dbSound = 84;
- else if (value > 0x1000 && value <= 0x2000) // 8192
- dbSound = 78;
- else if (value > 0x0800 && value <= 0x1000) // 4028
- dbSound = 72;
- else if (value > 0x0400 && value <= 0x0800) // 2048
- dbSound = 66;
- else if (value > 0x0200 && value <= 0x0400) // 1024
- dbSound = 60;
- else if (value > 0x0100 && value <= 0x0200) // 512
- dbSound = 54;
- else if (value > 0x0080 && value <= 0x0100) // 256
- dbSound = 48;
- else if (value > 0x0040 && value <= 0x0080) // 128
- dbSound = 42;
- else if (value > 0x0020 && value <= 0x0040) // 64
- dbSound = 36;
- else if (value > 0x0010 && value <= 0x0020) // 32
- dbSound = 30;
- else if (value > 0x0008 && value <= 0x0010) //16
- dbSound = 24;
- else if (value > 0x0007 && value <= 0x0008) //8
- dbSound = 24;
- else if (value > 0x0003 && value <= 0x0007) // 4
- dbSound = 18;
- else if (value > 0x0001 && value <= 0x0003) //2
- dbSound = 12;
- else if (value > 0x000 && value == 0x0001) // 1
- dbSound = 6;
- else
- dbSound = 0;
-
- return dbSound;
-}
-
-typedef struct
-{
- M4OSA_UInt8 *m_dataAddress;
- M4OSA_UInt32 m_bufferSize;
-} M4AM_Buffer;
-
-
-M4OSA_UInt8 logLookUp[256] = {
-0,120,137,146,154,159,163,167,171,173,176,178,181,182,184,186,188,189,190,192,193,
-194,195,196,198,199,199,200,201,202,203,204,205,205,206,207,207,208,209,209,210,
-211,211,212,212,213,213,214,215,215,216,216,216,217,217,218,218,219,219,220,220,
-220,221,221,222,222,222,223,223,223,224,224,224,225,225,225,226,226,226,227,227,
-227,228,228,228,229,229,229,229,230,230,230,230,231,231,231,232,232,232,232,233,
-233,233,233,233,234,234,234,234,235,235,235,235,236,236,236,236,236,237,237,237,
-237,237,238,238,238,238,238,239,239,239,239,239,240,240,240,240,240,240,241,241,
-241,241,241,241,242,242,242,242,242,242,243,243,243,243,243,243,244,244,244,244,
-244,244,245,245,245,245,245,245,245,246,246,246,246,246,246,246,247,247,247,247,
-247,247,247,247,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,250,
-250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,252,252,252,252,
-252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,
-254,254,254,254,255,255,255,255,255,255,255,255,255,255,255};
-
-M4OSA_ERR M4MA_generateAudioGraphFile(JNIEnv* pEnv, M4OSA_Char* pInputFileURL,
- M4OSA_Char* pOutFileURL,
- M4OSA_UInt32 samplesPerValue,
- M4OSA_UInt32 channels,
- M4OSA_UInt32 frameDuration,
- ManualEditContext* pContext)
-{
- M4OSA_ERR err;
- M4OSA_Context outFileHandle = M4OSA_NULL;
- M4OSA_Context inputFileHandle = M4OSA_NULL;
- M4AM_Buffer bufferIn = {0, 0};
- M4OSA_UInt32 peakVolumeDbValue = 0;
- M4OSA_UInt32 samplesCountInBytes= 0 , numBytesToRead = 0, index = 0;
- M4OSA_UInt32 writeCount = 0, samplesCountBigEndian = 0, volumeValuesCount = 0;
- M4OSA_Int32 seekPos = 0;
- M4OSA_UInt32 fileSize = 0;
- M4OSA_UInt32 totalBytesRead = 0;
- M4OSA_UInt32 prevProgress = 0;
- bool threadStarted = true;
-
- int dbValue = 0;
- M4OSA_Int16 *ptr16 ;
-
- jclass engineClass = pEnv->FindClass(MANUAL_EDIT_ENGINE_CLASS_NAME);
- videoEditJava_checkAndThrowIllegalStateException(&threadStarted, pEnv,
- (M4OSA_NULL == engineClass),
- "not initialized");
-
- /* register the call back function pointer */
- pContext->onAudioGraphProgressUpdateMethodId =
- pEnv->GetMethodID(engineClass, "onAudioGraphExtractProgressUpdate", "(IZ)V");
-
-
- /* ENTER */
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "ENTER - M4MA_generateAudioGraphFile");
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "Audio Graph samplesPerValue %d channels %d", samplesPerValue, channels);
-
- /******************************************************************************
- OPEN INPUT AND OUTPUT FILES
- *******************************************************************************/
- err = M4OSA_fileReadOpen (&inputFileHandle, pInputFileURL, M4OSA_kFileRead);
- if (inputFileHandle == M4OSA_NULL) {
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "M4MA_generateAudioGraphFile: Cannot open input file 0x%" PRIx32, err);
- return err;
- }
-
- /* get the file size for progress */
- err = M4OSA_fileReadGetOption(inputFileHandle, M4OSA_kFileReadGetFileSize,
- (M4OSA_Void**)&fileSize);
- if ( err != M4NO_ERROR) {
- //LVMEL_LOG_ERROR("M4MA_generateAudioGraphFile : File write failed \n");
- jniThrowException(pEnv, "java/lang/IOException", "file size get option failed");
- //return -1;
- }
-
- err = M4OSA_fileWriteOpen (&outFileHandle,(M4OSA_Char*) pOutFileURL,
- M4OSA_kFileCreate | M4OSA_kFileWrite);
- if (outFileHandle == M4OSA_NULL) {
- if (inputFileHandle != NULL)
- {
- M4OSA_fileReadClose(inputFileHandle);
- }
- return err;
- }
-
- /******************************************************************************
- PROCESS THE SAMPLES
- *******************************************************************************/
- samplesCountInBytes = (samplesPerValue * sizeof(M4OSA_UInt16) * channels);
-
- bufferIn.m_dataAddress = (M4OSA_UInt8*)M4OSA_32bitAlignedMalloc(samplesCountInBytes*sizeof(M4OSA_UInt16), 0,
- (M4OSA_Char*)"AudioGraph" );
- if ( bufferIn.m_dataAddress != M4OSA_NULL) {
- bufferIn.m_bufferSize = samplesCountInBytes*sizeof(M4OSA_UInt16);
- } else {
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "M4MA_generateAudioGraphFile: Malloc failed for bufferIn.m_dataAddress 0x%" PRIx32,
- M4ERR_ALLOC);
- return M4ERR_ALLOC;
- }
- /* sample to be converted to BIG endian ; store the frame duration */
- samplesCountBigEndian = ((frameDuration>>24)&0xff) | // move byte 3 to byte 0
- ((frameDuration<<8)&0xff0000) | // move byte 1 to byte 2
- ((frameDuration>>8)&0xff00) | // move byte 2 to byte 1
- ((frameDuration<<24)&0xff000000); // byte 0 to byte 3
-
- /* write the samples per value supplied to out file */
- err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&samplesCountBigEndian,
- sizeof(M4OSA_UInt32) );
- if (err != M4NO_ERROR) {
- jniThrowException(pEnv, "java/lang/IOException", "file write failed");
- }
-
-
- /* write UIn32 value 0 for no of values as place holder */
- samplesCountBigEndian = 0; /* reusing local var */
- err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&samplesCountBigEndian,
- sizeof(M4OSA_UInt32) );
- if (err != M4NO_ERROR) {
- jniThrowException(pEnv, "java/lang/IOException", "file write failed");
- }
-
- /* loop until EOF */
- do
- {
- memset((void *)bufferIn.m_dataAddress,0,bufferIn.m_bufferSize);
-
- numBytesToRead = samplesCountInBytes;
-
- err = M4OSA_fileReadData( inputFileHandle,
- (M4OSA_MemAddr8)bufferIn.m_dataAddress,
- &numBytesToRead );
-
- if (err != M4NO_ERROR) {
- // if out value of bytes-read is 0, break
- if ( numBytesToRead == 0) {
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "numBytesToRead 0x%" PRIx32,
- numBytesToRead);
- break; /* stop if file is empty or EOF */
- }
- }
-
- ptr16 = (M4OSA_Int16*)bufferIn.m_dataAddress;
-
- peakVolumeDbValue = 0;
- index = 0;
-
- // loop through half the lenght frame bytes read 'cause its 16 bits samples
- while (index < (numBytesToRead / 2)) {
- /* absolute values of 16 bit sample */
- if (ptr16[index] < 0) {
- ptr16[index] = -(ptr16[index]);
- }
- peakVolumeDbValue = (peakVolumeDbValue > (M4OSA_UInt32)ptr16[index] ?\
- peakVolumeDbValue : (M4OSA_UInt32)ptr16[index]);
- index++;
- }
-
- // move 7 bits , ignore sign bit
- dbValue = (peakVolumeDbValue >> 7);
- dbValue = logLookUp[(M4OSA_UInt8)dbValue];
-
- err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&dbValue, sizeof(M4OSA_UInt8) );
- if (err != M4NO_ERROR) {
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "M4MA_generateAudioGraphFile : File write failed");
- break;
- }
-
- volumeValuesCount ++;
- totalBytesRead += numBytesToRead;
-
- if ((((totalBytesRead*100)/fileSize)) != prevProgress) {
- if ( (pContext->threadProgress != prevProgress) && (prevProgress != 0 )) {
- //pContext->threadProgress = prevProgress;
- //onWveformProgressUpdateMethodId(prevProgress, 0);
- //LVME_callAudioGraphOnProgressUpdate(pContext, 0, prevProgress);
- pEnv->CallVoidMethod(pContext->engine,
- pContext->onAudioGraphProgressUpdateMethodId,
- prevProgress, 0);
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "pContext->threadProgress %d",
- prevProgress);
- }
- }
- prevProgress = (((totalBytesRead*100)/fileSize));
-
- } while (numBytesToRead != 0);
-
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_INFO, "VIDEO_EDITOR", "loop 0x%" PRIx32, volumeValuesCount);
-
- /* if some error occured in fwrite */
- if (numBytesToRead != 0) {
- //err = -1;
- jniThrowException(pEnv, "java/lang/IOException", "numBytesToRead != 0 ; file write failed");
- }
-
- /* write the count in place holder after seek */
- seekPos = sizeof(M4OSA_UInt32);
- err = M4OSA_fileWriteSeek(outFileHandle, M4OSA_kFileSeekBeginning,
- &seekPos /* after samples per value */);
- if ( err != M4NO_ERROR) {
- jniThrowException(pEnv, "java/lang/IOException", "file seek failed");
- } else {
- volumeValuesCount = ((volumeValuesCount>>24)&0xff) | // move byte 3 to byte 0
- ((volumeValuesCount<<8)&0xff0000) | // move byte 1 to byte 2
- ((volumeValuesCount>>8)&0xff00) | // move byte 2 to byte 1
- ((volumeValuesCount<<24)&0xff000000); // byte 0 to byte 3
-
- err = M4OSA_fileWriteData (outFileHandle, (M4OSA_MemAddr8)&volumeValuesCount,
- sizeof(M4OSA_UInt32) );
- if ( err != M4NO_ERROR) {
- jniThrowException(pEnv, "java/lang/IOException", "file write failed");
- }
- }
-
- /******************************************************************************
- CLOSE AND FREE ALLOCATIONS
- *******************************************************************************/
- free(bufferIn.m_dataAddress);
- M4OSA_fileReadClose(inputFileHandle);
- M4OSA_fileWriteClose(outFileHandle);
- /* final finish callback */
- pEnv->CallVoidMethod(pContext->engine, pContext->onAudioGraphProgressUpdateMethodId, 100, 0);
-
- /* EXIT */
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR", "EXIT - M4MA_generateAudioGraphFile");
-
- return err;
-}
-
-static jint videoEditor_generateAudioWaveFormSync (JNIEnv* pEnv, jobject thiz,
- jstring pcmfilePath,
- jstring outGraphfilePath,
- jint frameDuration, jint channels,
- jint samplesCount)
-{
- M4OSA_ERR result = M4NO_ERROR;
- ManualEditContext* pContext = M4OSA_NULL;
- bool needToBeLoaded = true;
- const char *pPCMFilePath, *pStringOutAudioGraphFile;
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_generateAudioWaveFormSync() ");
-
- /* Get the context. */
- pContext = (ManualEditContext*)videoEditClasses_getContext(&needToBeLoaded, pEnv, thiz);
- if (pContext == M4OSA_NULL) {
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_generateAudioWaveFormSync() - pContext is NULL ");
- }
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_generateAudioWaveFormSync Retrieving pStringOutAudioGraphFile");
-
- pPCMFilePath = pEnv->GetStringUTFChars(pcmfilePath, NULL);
- if (pPCMFilePath == M4OSA_NULL) {
- jniThrowException(pEnv, "java/lang/RuntimeException",
- "Input string PCMFilePath is null");
- result = M4ERR_PARAMETER;
- goto out;
- }
-
- pStringOutAudioGraphFile = pEnv->GetStringUTFChars(outGraphfilePath, NULL);
- if (pStringOutAudioGraphFile == M4OSA_NULL) {
- jniThrowException(pEnv, "java/lang/RuntimeException",
- "Input string outGraphfilePath is null");
- result = M4ERR_PARAMETER;
- goto out2;
- }
-
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_generateAudioWaveFormSync Generate the waveform data %s %d %d %d",
- pStringOutAudioGraphFile, frameDuration, channels, samplesCount);
-
- /* Generate the waveform */
- result = M4MA_generateAudioGraphFile(pEnv, (M4OSA_Char*) pPCMFilePath,
- (M4OSA_Char*) pStringOutAudioGraphFile,
- (M4OSA_UInt32) samplesCount,
- (M4OSA_UInt32) channels,
- (M4OSA_UInt32)frameDuration,
- pContext);
-
- pEnv->ReleaseStringUTFChars(outGraphfilePath, pStringOutAudioGraphFile);
-
-out2:
- if (pPCMFilePath != NULL) {
- pEnv->ReleaseStringUTFChars(pcmfilePath, pPCMFilePath);
- }
-
-out:
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR",
- "videoEditor_generateAudioWaveFormSync pContext->bSkipState ");
-
- return (jint)result;
-}
-
-/******** End Audio Graph *******/
-jint JNI_OnLoad(
- JavaVM* pVm,
- void* pReserved)
-{
- void* pEnv = NULL;
- bool needToBeInitialized = true;
- jint result = -1;
-
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR", "JNI_OnLoad()");
-
- // Check the JNI version.
- if (pVm->GetEnv(&pEnv, JNI_VERSION_1_4) == JNI_OK)
- {
- // Register the manual edit JNI methods.
- if (videoEditor_registerManualEditMethods((JNIEnv*)pEnv) == 0)
- {
- // Initialize the classes.
- videoEditClasses_init(&needToBeInitialized, (JNIEnv*)pEnv);
- if (needToBeInitialized)
- {
- // Success, return valid version number.
- result = JNI_VERSION_1_4;
- }
- }
- }
-
- // Return the result.
- return(result);
-}
-
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
deleted file mode 100644
index c12b1f5..0000000
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VideoEditorOsal"
-
-#include <VideoEditorJava.h>
-#include <VideoEditorLogging.h>
-#include <VideoEditorOsal.h>
-
-extern "C" {
-#include <M4OSA_Clock.h>
-#include <M4OSA_CharStar.h>
-#include <M4OSA_FileCommon.h>
-#include <M4OSA_FileReader.h>
-#include <M4OSA_FileWriter.h>
-#include <M4OSA_Memory.h>
-#include <M4OSA_Thread.h>
-#include <M4xVSS_API.h>
-#include <M4VSS3GPP_ErrorCodes.h>
-#include <M4MCS_ErrorCodes.h>
-#include <M4READER_Common.h>
-#include <M4WRITER_common.h>
-#include <M4VSS3GPP_API.h>
-#include <M4DECODER_Common.h>
-};
-
-
-#define VIDEOEDIT_OSAL_RESULT_STRING_MAX (32)
-
-#define VIDEOEDIT_OSAL_RESULT_INIT(m_result) { m_result, #m_result }
-
-
-typedef struct
-{
- M4OSA_ERR result;
- const char* pName;
-} VideoEdit_Osal_Result;
-
-static const VideoEdit_Osal_Result gkRESULTS[] =
-{
- // M4OSA_Clock.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_TIMESCALE_TOO_BIG ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_CLOCK_BAD_REF_YEAR ),
-
- // M4OSA_Error.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4NO_ERROR ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_PARAMETER ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_STATE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_ALLOC ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_BAD_CONTEXT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_CONTEXT_FAILED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_BAD_STREAM_ID ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_BAD_OPTION_ID ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_WRITE_ONLY ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_READ_ONLY ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_NOT_IMPLEMENTED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_UNSUPPORTED_MEDIA_TYPE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_NO_DATA_YET ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_NO_MORE_STREAM ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_INVALID_TIME ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_NO_MORE_AU ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_TIME_OUT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_BUFFER_FULL ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_REDIRECT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_TOO_MUCH_STREAMS ),
-
- // M4OSA_FileCommon.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_NOT_FOUND ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_LOCKED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_BAD_MODE_ACCESS ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_FILE_INVALID_POSITION ),
-
- // M4OSA_Thread.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_THREAD_NOT_STARTED ),
-
- // M4xVSS_API.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_ANALYZING_DONE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_PREVIEW_READY ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_SAVING_DONE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_TRANSCODING_NECESSARY ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_OUTPUTFILESIZE_EXCEED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_JPG_TOO_BIG ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4xVSSWAR_BUFFER_OUT_TOO_SMALL ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4xVSSERR_NO_MORE_SPACE ),
-
- // M4VSS3GPP_ErrorCodes.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_FILE_TYPE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_EFFECT_KIND ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_VIDEO_EFFECT_TYPE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_AUDIO_EFFECT_TYPE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_VIDEO_TRANSITION_TYPE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_AUDIO_TRANSITION_TYPE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_VIDEO_ENCODING_FRAME_RATE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EXTERNAL_EFFECT_NULL ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EXTERNAL_TRANSITION_NULL ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_DURATION ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_BEGIN_CUT_LARGER_THAN_END_CUT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_OVERLAPPING_TRANSITIONS ),
-#ifdef M4VSS3GPP_ERR_ANALYSIS_DATA_SIZE_TOO_SMALL
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ANALYSIS_DATA_SIZE_TOO_SMALL ),
-#endif
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_3GPP_FILE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AMR_EDITING_UNSUPPORTED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_VIDEO_AU_TOO_LARGE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_AUDIO_AU_TOO_LARGE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AU ),
-#ifdef M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AMR_AU
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_AUDIO_CORRUPTED_AMR_AU ),
-#endif
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ENCODER_ACCES_UNIT_ERROR ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_H263_PROFILE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_MPEG4_RVLC ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_VERSION ),
-#ifdef M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_PLATFORM
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INVALID_CLIP_ANALYSIS_PLATFORM ),
-#endif
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FORMAT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_TIME_SCALE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNSUPPORTED_MP3_ASSEMBLY ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_STREAM_TYPE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_NB_OF_CHANNELS ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_SAMPLING_FREQUENCY ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_NO_SUPPORTED_STREAM_IN_FILE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ADDVOLUME_EQUALS_ZERO ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_UNSUPPORTED_ADDED_AUDIO_STREAM ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_MIXING_UNSUPPORTED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_CANNOT_BE_MIXED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INPUT_CLIP_IS_NOT_A_3GPP ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_BEGINLOOP_HIGHER_ENDLOOP ),
-#ifdef M4VSS3GPP_ERR_AUDIO_MIXING_MP3_UNSUPPORTED
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_MIXING_MP3_UNSUPPORTED ),
-#endif
-#ifdef M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AAC
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_AAC ),
-#endif
-#ifdef M4VSS3GPP_ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED ),
-#endif
-#ifdef M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_EVRC
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_FEATURE_UNSUPPORTED_WITH_EVRC ),
-#endif
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_H263_PROFILE_NOT_SUPPORTED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INTERNAL_STATE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_LUMA_FILTER_ERROR ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_TRANSITION_FILTER_ERROR ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_DECODER_INIT_FAILED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_DECODED_PCM_SIZE_ISSUE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_OUTPUT_FILE_TYPE_ERROR ),
-
- // M4MCS_ErrorCodes.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_WAR_TRANSCODING_DONE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_WAR_MEDIATYPE_NOT_SUPPORTED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INVALID_INPUT_FILE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INVALID_VIDEO_FRAME_SIZE_FOR_H263 ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INVALID_VIDEO_FRAME_RATE_FOR_H263 ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_DURATION_IS_NULL ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_H263_FORBIDDEN_IN_MP4_FILE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_H263_PROFILE_NOT_SUPPORTED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_INVALID_AAC_SAMPLING_FREQUENCY ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIO_CONVERSION_FAILED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_BEGIN_CUT_LARGER_THAN_DURATION ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_BEGIN_CUT_EQUALS_END_CUT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_END_CUT_SMALLER_THAN_BEGIN_CUT ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_MAXFILESIZE_TOO_SMALL ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_VIDEOBITRATE_TOO_LOW ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIOBITRATE_TOO_LOW ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_VIDEOBITRATE_TOO_HIGH ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIOBITRATE_TOO_HIGH ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_NOMORE_SPACE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_FILE_DRM_PROTECTED ),
-
- // M4READER_Common.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_READER_UNKNOWN_STREAM_TYPE ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_READER_NO_METADATA ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_READER_INFORMATION_NOT_PRESENT ),
-
- // M4WRITER_Common.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_WRITER_STOP_REQ ),
- // M4DECODER_Common.h
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_VIDEORENDERER_NO_NEW_FRAME ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4WAR_DEBLOCKING_FILTER_NOT_IMPLEMENTED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_DECODER_H263_PROFILE_NOT_SUPPORTED ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_DECODER_H263_NOT_BASELINE )
-};
-
-static const int gkRESULTS_COUNT = (sizeof(gkRESULTS) / sizeof(VideoEdit_Osal_Result));
-
-#ifdef OSAL_MEM_LEAK_DEBUG
-static int gAllocatedBlockCount = 0;
-#endif
-
-const char*
-videoEditOsal_getResultString(
- M4OSA_ERR result)
-{
- static char string[VIDEOEDIT_OSAL_RESULT_STRING_MAX] = "";
- const char* pString = M4OSA_NULL;
- int index = 0;
-
- // Loop over the list with constants.
- for (index = 0;
- ((M4OSA_NULL == pString) && (index < gkRESULTS_COUNT));
- index++)
- {
- // Check if the specified result matches.
- if (result == gkRESULTS[index].result)
- {
- // Set the description.
- pString = gkRESULTS[index].pName;
- }
- }
-
- // Check if no result was found.
- if (M4OSA_NULL == pString)
- {
- // Set the description to a default value.
- M4OSA_chrSPrintf((M4OSA_Char *)string, sizeof(string) - 1,
- (M4OSA_Char*)"<unknown(0x%08X)>", result);
- pString = string;
- }
-
- // Return the result.
- return(pString);
-}
-
-void *
-videoEditOsal_alloc(
- bool* pResult,
- JNIEnv* pEnv,
- size_t size,
- const char* pDescription)
-{
- void *pData = M4OSA_NULL;
-
- // Check if the previous action succeeded.
- if (*pResult)
- {
- // Allocate memory for the settings.
- pData = (M4VSS3GPP_EditSettings*)M4OSA_32bitAlignedMalloc(size, 0, (M4OSA_Char*)pDescription);
- if (M4OSA_NULL != pData)
- {
- // Reset the allocated memory.
- memset((void *)pData, 0,size);
-#ifdef OSAL_MEM_LEAK_DEBUG
- // Update the allocated block count.
- gAllocatedBlockCount++;
-#endif
- }
- else
- {
- // Reset the result flag.
- (*pResult) = false;
-
- // Log the error.
- VIDEOEDIT_LOG_ERROR(ANDROID_LOG_ERROR, "VIDEO_EDITOR_OSAL", "videoEditOsal_alloc,\
- error: unable to allocate memory for %s", pDescription);
-
- // Throw an exception.
- jniThrowException(pEnv, "java/lang/OutOfMemoryError", "unable to allocate memory");
- }
- }
-
- // Return the allocated memory.
- return(pData);
-}
-
-void
-videoEditOsal_free(
- void* pData)
-{
- // Check if memory was allocated.
- if (M4OSA_NULL != pData)
- {
- VIDEOEDIT_LOG_FUNCTION(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "videoEditOsal_free()");
-
- // Log the API call.
- VIDEOEDIT_LOG_API(ANDROID_LOG_INFO, "VIDEO_EDITOR_OSAL", "free");
-
- // Free the memory.
- free(pData);
-#ifdef OSAL_MEM_LEAK_DEBUG
- // Update the allocated block count.
- gAllocatedBlockCount--;
-
- // Log the number of allocated blocks.
- VIDEOEDIT_LOG_ALLOCATION(ANDROID_LOG_ERROR, "VIDEO_EDITOR_OSAL", "allocated, %d blocks",\
- gAllocatedBlockCount);
-#endif
- }
-}
-
-
-void
-videoEditOsal_getFilePointers ( M4OSA_FileReadPointer *pOsaFileReadPtr,
- M4OSA_FileWriterPointer *pOsaFileWritePtr)
-{
- if (pOsaFileReadPtr != M4OSA_NULL)
- {
- // Initialize the filereader function pointers.
- pOsaFileReadPtr->openRead = M4OSA_fileReadOpen;
- pOsaFileReadPtr->readData = M4OSA_fileReadData;
- pOsaFileReadPtr->seek = M4OSA_fileReadSeek;
- pOsaFileReadPtr->closeRead = M4OSA_fileReadClose;
- pOsaFileReadPtr->setOption = M4OSA_fileReadSetOption;
- pOsaFileReadPtr->getOption = M4OSA_fileReadGetOption;
- }
-
- if (pOsaFileWritePtr != M4OSA_NULL)
- {
- // Initialize the filewriter function pointers.
- pOsaFileWritePtr->openWrite = M4OSA_fileWriteOpen;
- pOsaFileWritePtr->writeData = M4OSA_fileWriteData;
- pOsaFileWritePtr->seek = M4OSA_fileWriteSeek;
- pOsaFileWritePtr->Flush = M4OSA_fileWriteFlush;
- pOsaFileWritePtr->closeWrite = M4OSA_fileWriteClose;
- pOsaFileWritePtr->setOption = M4OSA_fileWriteSetOption;
- pOsaFileWritePtr->getOption = M4OSA_fileWriteGetOption;
- }
-}
-
diff --git a/media/jni/mediaeditor/VideoEditorOsal.h b/media/jni/mediaeditor/VideoEditorOsal.h
deleted file mode 100644
index 7a6f5ea..0000000
--- a/media/jni/mediaeditor/VideoEditorOsal.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VIDEO_EDITOR_OSAL_H
-#define VIDEO_EDITOR_OSAL_H
-
-#include <jni.h>
-#include <JNIHelp.h>
-
-extern "C" {
-#include <M4OSA_Error.h>
-#include <M4OSA_Thread.h>
-#include <M4OSA_FileReader.h>
-#include <M4OSA_FileWriter.h>
-};
-
-const char*
-videoEditOsal_getResultString(
- M4OSA_ERR result);
-
-void*
-videoEditOsal_alloc(
- bool* pResult,
- JNIEnv* pEnv,
- size_t size,
- const char* pDescription);
-
-void
-videoEditOsal_free(
- void* pData);
-
-void
-videoEditOsal_startThread(
- bool* pResult,
- JNIEnv* pEnv,
- int stackSize,
- M4OSA_ThreadDoIt callback,
- M4OSA_Context* pContext,
- void* pParam);
-
-void
-videoEditOsal_stopThread(
- bool* pResult,
- JNIEnv* pEnv,
- M4OSA_Context* pContext);
-
-void
-videoEditOsal_getFilePointers ( M4OSA_FileReadPointer *pOsaFileReadPtr,
- M4OSA_FileWriterPointer *pOsaFileWritePtr);
-
-#endif // VIDEO_EDITOR_OSAL_H
-
diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
deleted file mode 100644
index ae1a80e..0000000
--- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VideoEditorPropertiesMain"
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <VideoEditorClasses.h>
-#include <VideoEditorJava.h>
-#include <VideoEditorOsal.h>
-#include <VideoEditorLogging.h>
-#include <VideoEditorOsal.h>
-
-extern "C" {
-#include <M4OSA_Clock.h>
-#include <M4OSA_CharStar.h>
-#include <M4OSA_Error.h>
-#include <M4OSA_FileCommon.h>
-#include <M4OSA_FileReader.h>
-#include <M4OSA_FileWriter.h>
-#include <M4OSA_Memory.h>
-#include <M4OSA_Thread.h>
-#include <M4VSS3GPP_API.h>
-#include <M4VSS3GPP_ErrorCodes.h>
-#include <M4MCS_API.h>
-#include <M4MCS_ErrorCodes.h>
-#include <M4READER_Common.h>
-#include <M4WRITER_common.h>
-#include <M4DECODER_Common.h>
-#include <M4AD_Common.h>
-};
-
-extern "C" M4OSA_ERR M4MCS_open_normalMode(
- M4MCS_Context pContext,
- M4OSA_Void* pFileIn,
- M4VIDEOEDITING_FileType InputFileType,
- M4OSA_Void* pFileOut,
- M4OSA_Void* pTempFile);
-
-jobject videoEditProp_getProperties(
- JNIEnv* pEnv,
- jobject thiz,
- jstring file);
-
-static void
-getFileAndMediaTypeFromExtension (
- M4OSA_Char* pExtension,
- VideoEditClasses_FileType *pFileType,
- M4VIDEOEDITING_FileType *pClipType);
-
-static M4OSA_ERR
-getClipProperties( JNIEnv* pEnv,
- jobject thiz,
- M4OSA_Char* pFile,
- M4VIDEOEDITING_FileType clipType,
- M4VIDEOEDITING_ClipProperties* pClipProperties);
-
-M4OSA_UInt32
-VideoEdit_chrCompare(M4OSA_Char* pStrIn1,
- M4OSA_Char* pStrIn2,
- M4OSA_Int32* pCmpResult);
-
-jobject videoEditProp_getProperties(
- JNIEnv* pEnv,
- jobject thiz,
- jstring file)
-{
- bool gotten = true;
- M4OSA_Char* pFile = M4OSA_NULL;
- M4OSA_Char* pExtension = M4OSA_NULL;
- M4OSA_UInt32 index = 0;
- M4OSA_Int32 cmpResult = 0;
- VideoEditPropClass_Properties* pProperties = M4OSA_NULL;
- M4VIDEOEDITING_ClipProperties* pClipProperties = M4OSA_NULL;
- M4OSA_ERR result = M4NO_ERROR;
- M4MCS_Context context = M4OSA_NULL;
- M4OSA_FilePosition size = 0;
- M4OSA_UInt32 width = 0;
- M4OSA_UInt32 height = 0;
- jobject properties = NULL;
- M4OSA_Context pOMXContext = M4OSA_NULL;
- M4DECODER_VideoInterface* pOMXVidDecoderInterface = M4OSA_NULL;
- M4AD_Interface* pOMXAudDecoderInterface = M4OSA_NULL;
-
- bool initialized = true;
- VideoEditClasses_FileType fileType = VideoEditClasses_kFileType_Unsupported;
- M4VIDEOEDITING_FileType clipType = M4VIDEOEDITING_kFileType_Unsupported;
-
- VIDEOEDIT_LOG_API(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
- "videoEditProp_getProperties()");
-
- // Initialize the classes.
- videoEditPropClass_init(&initialized, (JNIEnv*)pEnv);
-
- // Validate the tempPath parameter.
- videoEditJava_checkAndThrowIllegalArgumentException(
- &gotten, pEnv, (NULL == file), "file is null");
-
- // Get the file path.
- pFile = (M4OSA_Char *)videoEditJava_getString(
- &gotten, pEnv, file, NULL, M4OSA_NULL);
-
- result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);
-
- if(M4NO_ERROR != result) {
- // Free the file path.
- videoEditOsal_free(pFile);
- pFile = M4OSA_NULL;
- }
-
- videoEditJava_checkAndThrowIllegalArgumentException(&gotten, pEnv,
- (M4NO_ERROR != result), "file not found");
-
- // Close the file and free the file context
- if (context != NULL) {
- result = M4OSA_fileReadClose(context);
- context = M4OSA_NULL;
- }
-
- // Return if Error
- if (M4NO_ERROR != result) {
- return (properties); // NULL
- }
-
- // Check if the file path is valid.
- if (gotten)
- {
- // Retrieve the extension.
- pExtension = (M4OSA_Char *)strrchr((const char *)pFile, (int)'.');
- if (M4OSA_NULL != pExtension)
- {
- // Skip the dot.
- pExtension++;
-
- // Get the file type and Media type from extension
- getFileAndMediaTypeFromExtension(
- pExtension ,&fileType, &clipType);
- }
- }
-
- // Check if the file type could be determined.
- videoEditJava_checkAndThrowIllegalArgumentException(
- &gotten, pEnv,
- (VideoEditClasses_kFileType_Unsupported == fileType),
- "file type is not supported");
-
- // Allocate a new properties structure.
- pProperties = (VideoEditPropClass_Properties*)videoEditOsal_alloc(
- &gotten, pEnv,
- sizeof(VideoEditPropClass_Properties), "Properties");
-
- // Check if the context is valid and allocation succeeded
- // (required because of dereferencing of pProperties).
- if (gotten)
- {
- // Check if this type of file needs to be analyzed using MCS.
- if ((VideoEditClasses_kFileType_MP3 == fileType) ||
- (VideoEditClasses_kFileType_MP4 == fileType) ||
- (VideoEditClasses_kFileType_3GPP == fileType) ||
- (VideoEditClasses_kFileType_AMR == fileType) ||
- (VideoEditClasses_kFileType_PCM == fileType) ||
- (VideoEditClasses_kFileType_M4V == fileType))
- {
- // Allocate a new clip properties structure.
- pClipProperties =
- (M4VIDEOEDITING_ClipProperties*)videoEditOsal_alloc(
- &gotten, pEnv,
- sizeof(M4VIDEOEDITING_ClipProperties), "ClipProperties");
-
- // Check if allocation succeeded (required because of
- // dereferencing of pClipProperties).
- if (gotten)
- {
- // Log the API call.
- VIDEOEDIT_LOG_API(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
- "getClipProperties");
-
- // Get Video clip properties
- result = getClipProperties(
- pEnv, thiz, pFile, clipType, pClipProperties);
-
- if (M4MCS_ERR_FILE_DRM_PROTECTED == result) {
- // Check if the creation succeeded.
- videoEditJava_checkAndThrowIllegalArgumentException(
- &gotten, pEnv,(M4NO_ERROR != result),
- "Invalid File - DRM Protected ");
- } else {
- // Check if the creation succeeded.
- videoEditJava_checkAndThrowIllegalArgumentException(
- &gotten, pEnv,(M4NO_ERROR != result),
- "Invalid File or File not found ");
- }
-
-#ifdef USE_SOFTWARE_DECODER
- /**
- * Input clip with non-multiples of 16 is not supported.
- */
- if ( (pClipProperties->uiVideoWidth %16)
- || (pClipProperties->uiVideoHeight %16) )
- {
- result = M4MCS_ERR_INPUT_VIDEO_SIZE_NON_X16;
- videoEditJava_checkAndThrowIllegalArgumentException(
- &gotten, pEnv, (M4NO_ERROR != result),
- "non x16 input video frame size is not supported");
- }
-#endif /* USE_SOFTWARE_DECODER */
- }
-
- // Check if the properties could be retrieved.
- if (gotten)
- {
- // Set the properties.
- pProperties->uiClipDuration = pClipProperties->uiClipDuration;
- if (M4VIDEOEDITING_kFileType_Unsupported == pClipProperties->FileType)
- {
- pProperties->FileType = VideoEditClasses_kFileType_Unsupported;
- }
- else
- {
- pProperties->FileType = fileType;
- }
- pProperties->VideoStreamType = pClipProperties->VideoStreamType;
- pProperties->uiClipVideoDuration = pClipProperties->uiClipVideoDuration;
- pProperties->uiVideoBitrate = pClipProperties->uiVideoBitrate;
- pProperties->uiVideoWidth = pClipProperties->uiVideoWidth;
- pProperties->uiVideoHeight = pClipProperties->uiVideoHeight;
- pProperties->fAverageFrameRate = pClipProperties->fAverageFrameRate;
- pProperties->uiVideoProfile = pClipProperties->uiVideoProfile;
- pProperties->uiVideoLevel = pClipProperties->uiVideoLevel;
- // Set profile and level support to TRUE, pending check
- pProperties->bProfileSupported = M4OSA_TRUE;
- pProperties->bLevelSupported = M4OSA_TRUE;
- pProperties->AudioStreamType = pClipProperties->AudioStreamType;
- pProperties->uiClipAudioDuration = pClipProperties->uiClipAudioDuration;
- pProperties->uiAudioBitrate = pClipProperties->uiAudioBitrate;
- pProperties->uiNbChannels = pClipProperties->uiNbChannels;
- pProperties->uiSamplingFrequency = pClipProperties->uiSamplingFrequency;
- pProperties->uiRotation = pClipProperties->videoRotationDegrees;
-
- }
-
- // Free the clip properties.
- videoEditOsal_free(pClipProperties);
- pClipProperties = M4OSA_NULL;
- }
- else if ((VideoEditClasses_kFileType_JPG == fileType) ||
- (VideoEditClasses_kFileType_GIF == fileType) ||
- (VideoEditClasses_kFileType_PNG == fileType))
- {
- pProperties->uiClipDuration = 0;
- pProperties->FileType = fileType;
- pProperties->VideoStreamType = M4VIDEOEDITING_kNoneVideo;
- pProperties->uiClipVideoDuration = 0;
- pProperties->uiVideoBitrate = 0;
- pProperties->uiVideoWidth = width;
- pProperties->uiVideoHeight = height;
- pProperties->fAverageFrameRate = 0.0f;
- pProperties->uiVideoProfile = M4VIDEOEDITING_VIDEO_UNKNOWN_PROFILE;
- pProperties->uiVideoLevel = M4VIDEOEDITING_VIDEO_UNKNOWN_LEVEL;
- pProperties->AudioStreamType = M4VIDEOEDITING_kNoneAudio;
- pProperties->uiClipAudioDuration = 0;
- pProperties->uiAudioBitrate = 0;
- pProperties->uiNbChannels = 0;
- pProperties->uiSamplingFrequency = 0;
-
- // Added for Handling invalid paths and non existent image files
- // Open the file for reading.
- result = M4OSA_fileReadOpen(&context, (M4OSA_Void*)pFile, M4OSA_kFileRead);
- if (M4NO_ERROR != result)
- {
- pProperties->FileType = VideoEditClasses_kFileType_Unsupported;
- }
- result = M4OSA_fileReadClose(context);
- context = M4OSA_NULL;
- }
- }
-
- if (M4NO_ERROR == result) {
- // Create a properties object.
- videoEditPropClass_createProperties(&gotten, pEnv, pProperties, &properties);
-
- // Log the properties.
- VIDEOEDIT_PROP_LOG_PROPERTIES(pProperties);
- }
-
- // Free the properties.
- videoEditOsal_free(pProperties);
- pProperties = M4OSA_NULL;
-
- // Free the file path.
- videoEditOsal_free(pFile);
- pFile = M4OSA_NULL;
-
- // Return the Properties object.
- return(properties);
-}
-
-static void getFileAndMediaTypeFromExtension (
- M4OSA_Char *pExtension,
- VideoEditClasses_FileType *pFileType,
- M4VIDEOEDITING_FileType *pClipType)
-{
- M4OSA_Char extension[5] = {0, 0, 0, 0, 0};
- VideoEditClasses_FileType fileType =
- VideoEditClasses_kFileType_Unsupported;
-
- M4VIDEOEDITING_FileType clipType =
- M4VIDEOEDITING_kFileType_Unsupported;
-
- M4OSA_UInt32 index = 0;
- M4OSA_ERR result = M4NO_ERROR;
- M4OSA_Int32 cmpResult = 0;
- M4OSA_UInt32 extLength = strlen((const char *)pExtension);
-
- // Assign default
- *pFileType = VideoEditClasses_kFileType_Unsupported;
- *pClipType = M4VIDEOEDITING_kFileType_Unsupported;
-
- // Check if the length of the extension is valid.
- if ((3 == extLength) || (4 == extLength))
- {
- // Convert the extension to lowercase.
- for (index = 0; index < extLength ; index++)
- {
- extension[index] = tolower((int)pExtension[index]);
- }
-
- // Check if the extension is ".mp3".
- if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"mp3", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_MP3;
- *pClipType = M4VIDEOEDITING_kFileType_MP3;
- }
- // Check if the extension is ".mp4".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"mp4", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_MP4;
- *pClipType = M4VIDEOEDITING_kFileType_MP4;
- }
- // Check if the extension is ".3gp".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"3gp", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_3GPP;
- *pClipType = M4VIDEOEDITING_kFileType_3GPP;
- }
- // Check if the extension is ".m4a".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"m4a", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_3GPP;
- *pClipType = M4VIDEOEDITING_kFileType_3GPP;
- }
- // Check if the extension is ".3gpp".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"3gpp", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_3GPP;
- *pClipType = M4VIDEOEDITING_kFileType_3GPP;
- }
- // Check if the extension is ".amr".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"amr", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_AMR;
- *pClipType = M4VIDEOEDITING_kFileType_AMR;
- }
- // Check if the extension is ".pcm".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"pcm", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_PCM;
- *pClipType = M4VIDEOEDITING_kFileType_PCM;
- }
- // Check if the extension is ".jpg".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"jpg", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_JPG;
- }
- // Check if the extension is ".jpeg".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"jpeg", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_JPG;
- }
- // Check if the extension is ".gif".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"gif", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_GIF;
- }
- // Check if the extension is ".png".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"png", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_PNG;
- }
- // Check if the extension is ".m4v".
- else if (!(VideoEdit_chrCompare(extension, (M4OSA_Char*)"m4v", &cmpResult)))
- {
- *pFileType = VideoEditClasses_kFileType_M4V;
- *pClipType = M4VIDEOEDITING_kFileType_M4V;
- }
- }
-}
-
-static M4OSA_ERR getClipProperties(
- JNIEnv* pEnv,
- jobject thiz,
- M4OSA_Char* pFile,
- M4VIDEOEDITING_FileType clipType,
- M4VIDEOEDITING_ClipProperties* pClipProperties)
-{
- bool gotten = true;
- M4OSA_ERR result = M4NO_ERROR;
- M4OSA_ERR resultAbort = M4NO_ERROR;
- M4MCS_Context context = M4OSA_NULL;
-
- M4OSA_FileReadPointer fileReadPtr =
- { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
- M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };
-
- M4OSA_FileWriterPointer fileWritePtr =
- { M4OSA_NULL, M4OSA_NULL, M4OSA_NULL,
- M4OSA_NULL, M4OSA_NULL, M4OSA_NULL, M4OSA_NULL };
-
- // Initialize the OSAL file system function pointers.
- videoEditOsal_getFilePointers(&fileReadPtr , &fileWritePtr);
-
- // Log the API call.
- VIDEOEDIT_LOG_API(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",\
- "getClipProperties - M4MCS_init()");
-
- // Initialize the MCS context.
- result = M4MCS_init(&context, &fileReadPtr, &fileWritePtr);
-
- // Log the result.
- VIDEOEDIT_PROP_LOG_RESULT(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
- videoEditOsal_getResultString(result));
-
- // Check if the creation succeeded.
- videoEditJava_checkAndThrowRuntimeException(
- &gotten, pEnv, (M4NO_ERROR != result), result);
-
- // Check if opening the MCS context succeeded.
- if (gotten)
- {
- // Log the API call.
- VIDEOEDIT_LOG_API(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
- "getClipProperties - M4MCS_open_normalMode()");
-
- // Open the MCS in the normal opening mode to
- // retrieve the exact duration
- result = M4MCS_open_normalMode(
- context, pFile, clipType, M4OSA_NULL, M4OSA_NULL);
-
- // Log the result.
- VIDEOEDIT_PROP_LOG_RESULT(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
- videoEditOsal_getResultString(result));
-
- // Check if the creation succeeded.
- videoEditJava_checkAndThrowRuntimeException(
- &gotten, pEnv, (M4NO_ERROR != result), result);
-
- // Check if the MCS could be opened.
- if (gotten)
- {
- // Log the API call.
- VIDEOEDIT_LOG_API(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
- "getClipProperties - M4MCS_getInputFileProperties()");
-
- // Get the properties.
- result = M4MCS_getInputFileProperties(context, pClipProperties);
-
- // Log the result.
- VIDEOEDIT_PROP_LOG_RESULT(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
- videoEditOsal_getResultString(result));
-
- // Check if the creation succeeded.
- videoEditJava_checkAndThrowRuntimeException(
- &gotten, pEnv, (M4NO_ERROR != result), result);
- }
-
- // Log the API call.
- VIDEOEDIT_LOG_API(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES",
- "getClipProperties - M4MCS_abort()");
-
- // Close the MCS session.
- resultAbort = M4MCS_abort(context);
-
- if (result == M4NO_ERROR) {
- // Log the result.
- VIDEOEDIT_PROP_LOG_RESULT(
- ANDROID_LOG_INFO, "VIDEO_EDITOR_PROPERTIES", "%s",
- videoEditOsal_getResultString(resultAbort));
-
- // Check if the abort succeeded.
- videoEditJava_checkAndThrowRuntimeException(
- &gotten, pEnv, (M4NO_ERROR != resultAbort), resultAbort);
- result = resultAbort;
- }
- }
-
- return result;
-}
-
-M4OSA_UInt32
-VideoEdit_chrCompare(M4OSA_Char* pStrIn1,
- M4OSA_Char* pStrIn2,
- M4OSA_Int32* pCmpResult)
-{
- *pCmpResult = strcmp((const char *)pStrIn1, (const char *)pStrIn2);
- return *pCmpResult;
-}
-
-
diff --git a/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp b/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp
deleted file mode 100644
index 1508246..0000000
--- a/media/jni/mediaeditor/VideoEditorThumbnailMain.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include <jni.h>
-#include <JNIHelp.h>
-#include <utils/Log.h>
-#include "VideoBrowserMain.h"
-#include "VideoBrowserInternal.h"
-
-#if (M4OSA_TRACE_LEVEL >= 1)
-#undef M4OSA_TRACE1_0
-#undef M4OSA_TRACE1_1
-#undef M4OSA_TRACE1_2
-#undef M4OSA_TRACE1_3
-
-#define M4OSA_TRACE1_0(a) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a);
-#define M4OSA_TRACE1_1(a,b) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b);
-#define M4OSA_TRACE1_2(a,b,c) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b,c);
-#define M4OSA_TRACE1_3(a,b,c,d) __android_log_print(ANDROID_LOG_INFO, "Thumbnail", a,b,c,d);
-#endif
-
-/*
- * Memory format of 'ARGB8888' in skia is RGBA, so ABGR in 32bit little-endian packed format
- * bitmap format is rgb565
- */
-// RED GREEN BLUE ALPHA
-#define RGB565toSKCOLOR(c) ( (((c)&0xF800)>>8) | (((c)&0x7E0)<<5) | (((c)&0x1F)<<19) | 0xFF000000)
-
-#define GetIntField(env, obj, name) env->GetIntField(obj,\
-env->GetFieldID(env->GetObjectClass(obj), name, "I"))
-
-extern "C" M4OSA_ERR NXPSW_FileReaderOptim_init(M4OSA_Void *lowLevel_functionPointers,
- M4OSA_Void *optimized_functionPointers);
-
-/*
- * Video Browser execution context.
- * Based on request for RGB565 or RGB888, m_dst16 or m_dst32
- * will be initialized and used
- */
-typedef struct
-{
- M4OSA_Context m_pVideoBrowser;
- M4OSA_UInt32 m_previousTime;
- M4OSA_Int32* m_dst32;
- M4OSA_Int16* m_dst16;
- unsigned int m_width;
- unsigned int m_height;
- M4OSA_Bool m_bRender;
-} ThumbnailContext;
-
-/**
- ************************************************************************
- * @brief Interface to retrieve the thumbnail pixels
- * @param pContext (IN) Thumbnail Context.
- * @param width (IN) Width of thumbnail
- * @param height (IN) Height of thumbnail
- * @param pTimeMS (IN/OUT)Time stamp at which thumbnail is retrieved.
- ************************************************************************
-*/
-M4OSA_ERR ThumbnailGetPixels(const M4OSA_Context pContext,
- M4OSA_Int32* pixelArray,
- M4OSA_UInt32 width, M4OSA_UInt32 height,
- M4OSA_UInt32* pTimeMS, M4OSA_UInt32 tolerance);
-
-
-/**
- ************************************************************************
- * @brief Video browser callback, called when a frame must be displayed
- * @param pInstance (IN) Thumbnail context.
- * @param notificationID (IN) Id of the callback which generated the error
- * @param errCode (IN) Error code from the Core
- * @param pCbData (IN) pointer to data associated wit the callback.
- * @param pCbUserData (IN) pointer to application user data passed in init.
- * @note This callback mechanism is used to request display of an image
- ************************************************************************
-*/
-M4OSA_Void VBcallback( M4OSA_Context pInstance,
- VideoBrowser_Notification notificationID,
- M4OSA_ERR errCode, M4OSA_Void* pCbData,
- M4OSA_Void* pCallbackUserData)
-{
- M4OSA_UInt32 i, j;
- M4OSA_ERR err;
-
- M4OSA_TRACE3_0("inside VBcallback");
- M4VIFI_ImagePlane* pPlane=NULL;
- M4OSA_UInt16* src=NULL;
- ThumbnailContext* pC = NULL;
-
- CHECK_PTR(VBcallback, pCbData, err, M4ERR_PARAMETER);
- CHECK_PTR(VBcallback, pInstance,err, M4ERR_PARAMETER);
-
- pC = (ThumbnailContext*)pCallbackUserData ;
- CHECK_PTR(VBcallback, pC->m_pVideoBrowser, err, M4ERR_PARAMETER);
-
- pPlane = (M4VIFI_ImagePlane*)pCbData;
- src = (M4OSA_UInt16*)pPlane->pac_data;
-
- if (pC->m_dst32 != NULL)
- {
- M4OSA_Int32* dst = pC->m_dst32;
-
- for (j = 0; j < pPlane->u_height; j++)
- {
- for (i = 0; i < pPlane->u_width; i++)
- {
- dst[i] = RGB565toSKCOLOR(src[i]);
- }
- for (i = pPlane->u_width; i < pC->m_width; i++)
- {
- dst[i] = 0;
- }
- src = (M4OSA_UInt16*)((M4OSA_UInt8*)src + pPlane->u_stride);
- dst += pC->m_width;
- }
- }
- else if (pC->m_dst16 != NULL)
- {
- M4OSA_Int16* dst = pC->m_dst16;
-
- for (j = 0; j < pPlane->u_height; j++)
- {
- memcpy((void * )dst, (void * )src, pPlane->u_stride);
- for (i = pPlane->u_width; i < pC->m_width; i++)
- {
- dst[i] = 0;
- }
- src = (M4OSA_UInt16*)((M4OSA_UInt8*)src + pPlane->u_stride);
- dst += pC->m_width;
- }
- }
- else
- {
- CHECK_PTR(VBcallback, NULL, err, M4ERR_PARAMETER);
- }
-
-VBcallback_cleanUp:
-
- return;
-}
-
-M4OSA_ERR ThumbnailOpen(M4OSA_Context *pPContext,
- const M4OSA_Char *pString,
- M4OSA_Bool bRender)
-{
-
- M4OSA_ERR err;
- ThumbnailContext *pContext = M4OSA_NULL;
- VideoBrowser_VideoColorType vbColorType;
-
- CHECK_PTR(ThumbnailOpen, pString, err, M4ERR_BAD_CONTEXT);
-
- /*--- Create context ---*/
- pContext = (ThumbnailContext*)M4OSA_32bitAlignedMalloc(sizeof(ThumbnailContext), VIDEOBROWSER,
- (M4OSA_Char*)"Thumbnail context") ;
- M4OSA_TRACE3_1("context value is = %d",pContext);
- CHECK_PTR(ThumbnailOpen, pContext, err, M4ERR_ALLOC);
-
- memset((void *)pContext, 0,sizeof(ThumbnailContext));
-
- M4OSA_FileReadPointer optFP;
- M4OSA_FileReadPointer llFP;
-
- NXPSW_FileReaderOptim_init(&llFP, &optFP);
- M4OSA_TRACE1_2("ThumbnailOpen: entering videoBrowserCreate with 0x%x %s",
- &pContext->m_pVideoBrowser, pString) ;
-
- pContext->m_bRender = bRender;
- if (bRender == M4OSA_TRUE) {
- //Open is called for rendering the frame.
- //So set YUV420 as the output color format.
- vbColorType = VideoBrowser_kYUV420;
- } else {
- //Open is called for thumbnail Extraction
- //So set BGR565 as the output.
- vbColorType = VideoBrowser_kGB565;
- }
-
- err = videoBrowserCreate(&pContext->m_pVideoBrowser, (M4OSA_Char*)pString,
- VideoBrowser_kVBNormalBliting, &optFP, VBcallback, pContext, vbColorType);
-
- M4OSA_TRACE1_1("err value is = 0x%x",err);
- CHECK_ERR(ThumbnailOpen, err);
- CHECK_PTR(ThumbnailOpen, pContext->m_pVideoBrowser, err, M4ERR_ALLOC);
-
- *pPContext = pContext;
- M4OSA_TRACE1_1("context value is = %d",*pPContext);
-
- return M4NO_ERROR;
-
-ThumbnailOpen_cleanUp:
-
- M4OSA_TRACE1_0("i am inside cleanUP");
- if (M4OSA_NULL != pContext)
- {
- if (M4OSA_NULL != pContext->m_pVideoBrowser)
- {
- videoBrowserCleanUp(pContext->m_pVideoBrowser) ;
- }
- free(pContext) ;
- }
- return err;
-}
-
-M4OSA_ERR ThumbnailGetPixels(const M4OSA_Context pContext,
- M4OSA_Int32* pixelArray,
- M4OSA_UInt32 width, M4OSA_UInt32 height,
- M4OSA_UInt32* pTimeMS, M4OSA_UInt32 tolerance)
-{
- M4OSA_ERR err;
-
- ThumbnailContext* pC = (ThumbnailContext*)pContext;
-
- if ((pC->m_width != width) || (pC->m_height != height))
- {
- err = videoBrowserSetWindow(pC->m_pVideoBrowser, pixelArray,
- 0, 0, width, height);
- CHECK_ERR(ThumbnailGetPixels, err);
- pC->m_width = width;
- pC->m_height = height;
- }
-
- // Alter the pTimeMS to a valid value at which a frame is found
- // m_currentCTS has the actual frame time stamp just ahead of the
- // pTimeMS supplied.
- if ((((VideoBrowserContext*)pC->m_pVideoBrowser)->m_currentCTS != 0) &&
- (*pTimeMS >= pC->m_previousTime) &&
- (*pTimeMS < ((VideoBrowserContext*)pC->m_pVideoBrowser)->m_currentCTS))
- {
- pC->m_previousTime = *pTimeMS;
- *pTimeMS = ((VideoBrowserContext*)pC->m_pVideoBrowser)->m_currentCTS;
- }
- else
- {
- pC->m_previousTime = *pTimeMS;
- }
-
- err = videoBrowserPrepareFrame(pC->m_pVideoBrowser, pTimeMS, tolerance);
- CHECK_ERR(ThumbnailGetPixels, err);
-
- if (pC->m_bRender != M4OSA_TRUE) {
- err = videoBrowserDisplayCurrentFrame(pC->m_pVideoBrowser);
- CHECK_ERR(ThumbnailGetPixels, err);
- }
-
-ThumbnailGetPixels_cleanUp:
-
- return err;
-}
-
-M4OSA_ERR ThumbnailGetPixels32(const M4OSA_Context pContext,
- M4OSA_Int32* pixelArray, M4OSA_UInt32 width,
- M4OSA_UInt32 height, M4OSA_UInt32* timeMS,
- M4OSA_UInt32 tolerance)
-{
-
- M4OSA_ERR err = M4NO_ERROR;
-
- ThumbnailContext* pC = (ThumbnailContext*)pContext;
-
- CHECK_PTR(ThumbnailGetPixels32, pC->m_pVideoBrowser, err, M4ERR_ALLOC) ;
- CHECK_PTR(ThumbnailGetPixels32, pixelArray, err, M4ERR_ALLOC) ;
-
- pC->m_dst16 = NULL;
- pC->m_dst32 = pixelArray;
-
- err = ThumbnailGetPixels(pContext, pixelArray, width, height, timeMS, tolerance);
-
-ThumbnailGetPixels32_cleanUp:
-
- return err;
-}
-
-M4OSA_ERR ThumbnailGetPixels16(const M4OSA_Context pContext,
- M4OSA_Int16* pixelArray, M4OSA_UInt32 width,
- M4OSA_UInt32 height, M4OSA_UInt32* timeMS,
- M4OSA_UInt32 tolerance)
-{
- M4OSA_ERR err = M4NO_ERROR;
-
- ThumbnailContext* pC = (ThumbnailContext*)pContext;
-
- CHECK_PTR(ThumbnailGetPixels16, pC->m_pVideoBrowser, err, M4ERR_ALLOC);
- CHECK_PTR(ThumbnailGetPixels16, pixelArray, err, M4ERR_ALLOC);
-
- pC->m_dst16 = pixelArray;
- pC->m_dst32 = NULL;
-
- err = ThumbnailGetPixels(pContext, (M4OSA_Int32*)pixelArray, width, height,
- timeMS, tolerance);
-
-ThumbnailGetPixels16_cleanUp:
-
- return err;
-}
-
-
-void ThumbnailClose(const M4OSA_Context pContext)
-{
- M4OSA_ERR err;
-
- ThumbnailContext* pC = (ThumbnailContext*)pContext;
-
- CHECK_PTR(ThumbnailClose, pC, err, M4ERR_ALLOC);
-
- if (M4OSA_NULL != pC)
- {
- if (M4OSA_NULL != pC->m_pVideoBrowser)
- {
- videoBrowserCleanUp(pC->m_pVideoBrowser);
- }
- free(pC);
- }
-
-ThumbnailClose_cleanUp:
-
- return;
-}
-
diff --git a/media/jni/mediaeditor/VideoEditorThumbnailMain.h b/media/jni/mediaeditor/VideoEditorThumbnailMain.h
deleted file mode 100644
index 0b3b0c8..0000000
--- a/media/jni/mediaeditor/VideoEditorThumbnailMain.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VIDEOEDITOR_THUMBNAIL_MAIN_H
-#define VIDEOEDITOR_THUMBNAIL_MAIN_H
-
-/**
- ************************************************************************
- * @file VideoEditorThumbnailMain.h
- * @brief Thumbnail extract interface.
- ************************************************************************
-*/
-
-/**
- ************************************************************************
- * @brief Interface to open a Thumbnail session.
- * @param pContext (OUT) Thumbnail Context.
- * @param pString (IN) File path from which thumbnail will be
- * retrieved
- * @param M4OSA_Bool (IN) true if this is for rendering at native layer.
- ************************************************************************
-*/
-M4OSA_ERR ThumbnailOpen(M4OSA_Context *pPContext,
- const M4OSA_Char *pString,
- M4OSA_Bool bRender);
-
-/**
- ************************************************************************
- * @brief Interface to retrieve a RGB888 format thumbnail pixels
- * @param pContext (IN) Thumbnail Context.
- * @param pixelArray (OUT) Pointer to array in which pixels data to return
- * @param width (IN) Width of thumbnail
- * @param height (IN) Height of thumbnail
- * @param pTimeMS (IN/OUT)Time stamp at which thumbnail is retrieved.
- ************************************************************************
-*/
-M4OSA_ERR ThumbnailGetPixels32(const M4OSA_Context pContext,
- M4OSA_Int32* pixelArray, M4OSA_UInt32 width,
- M4OSA_UInt32 height, M4OSA_UInt32 *timeMS,
- M4OSA_UInt32 tolerance);
-
-/**
- ************************************************************************
- * @brief Interface to retrieve a RGB565 format thumbnail pixels
- * @param pContext (IN) Thumbnail Context.
- * @param pixelArray (OUT) Pointer to array in which pixcel data to return
- * @param width (IN) Width of thumbnail
- * @param height (IN) Height of thumbnail
- * @param pTimeMS (IN/OUT)Time stamp at which thumbnail is retrieved.
- ************************************************************************
-*/
-M4OSA_ERR ThumbnailGetPixels16(const M4OSA_Context pContext,
- M4OSA_Int16* pixelArray, M4OSA_UInt32 width,
- M4OSA_UInt32 height, M4OSA_UInt32 *timeMS,
- M4OSA_UInt32 tolerance);
-
-/**
- ************************************************************************
- * @brief Interface to close the Thumbnail session.
- * @param pContext (IN) Thumbnail Context.
- ************************************************************************
-*/
-void ThumbnailClose(const M4OSA_Context pContext);
-
-#endif // VIDEOEDITOR_THUMBNAIL_MAIN_H
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
index 3d5905d..cfc0881 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPerfTestRunner.java
@@ -17,8 +17,6 @@
package com.android.mediaframeworktest;
import com.android.mediaframeworktest.performance.MediaPlayerPerformance;
-/*Video Editor performance Test cases*/
-import com.android.mediaframeworktest.performance.VideoEditorPerformance;
import junit.framework.TestSuite;
import android.os.Bundle;
@@ -44,8 +42,6 @@
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(MediaPlayerPerformance.class);
- /* Video Editor performance Test cases */
- suite.addTestSuite(VideoEditorPerformance.class);
return suite;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
index cbb6642..a9dc886 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTestRunner.java
@@ -32,11 +32,6 @@
import com.android.mediaframeworktest.functional.audio.MediaPresetReverbTest;
import com.android.mediaframeworktest.functional.audio.MediaVirtualizerTest;
import com.android.mediaframeworktest.functional.audio.MediaVisualizerTest;
-import com.android.mediaframeworktest.functional.videoeditor.MediaItemThumbnailTest;
-import com.android.mediaframeworktest.functional.videoeditor.MediaPropertiesTest;
-import com.android.mediaframeworktest.functional.videoeditor.VideoEditorAPITest;
-import com.android.mediaframeworktest.functional.videoeditor.VideoEditorExportTest;
-import com.android.mediaframeworktest.functional.videoeditor.VideoEditorPreviewTest;
import junit.framework.TestSuite;
import android.os.Bundle;
@@ -76,12 +71,6 @@
suite.addTestSuite(MediaPresetReverbTest.class);
suite.addTestSuite(MediaVirtualizerTest.class);
suite.addTestSuite(MediaVisualizerTest.class);
- /*Test for Video Editor*/
- suite.addTestSuite(MediaItemThumbnailTest.class);
- suite.addTestSuite(MediaPropertiesTest.class);
- suite.addTestSuite(VideoEditorAPITest.class);
- suite.addTestSuite(VideoEditorExportTest.class);
- suite.addTestSuite(VideoEditorPreviewTest.class);
return suite;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaPlayerStressTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaPlayerStressTestRunner.java
index 0cd784c..5438061 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaPlayerStressTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaPlayerStressTestRunner.java
@@ -19,8 +19,6 @@
import android.test.InstrumentationTestRunner;
import android.test.InstrumentationTestSuite;
import com.android.mediaframeworktest.stress.MediaPlayerStressTest;
-/** Import for Video Editor Stress Test cases*/
-import com.android.mediaframeworktest.stress.VideoEditorStressTest;
import junit.framework.TestSuite;
@@ -30,8 +28,6 @@
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(MediaPlayerStressTest.class);
- /** Video Editor Stress Test cases*/
- suite.addTestSuite(VideoEditorStressTest.class);
return suite;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/VideoEditorHelper.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/VideoEditorHelper.java
deleted file mode 100644
index dd7c4c6..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/VideoEditorHelper.java
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Random;
-
-import junit.framework.Assert;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.media.videoeditor.AudioTrack;
-import android.media.videoeditor.EffectColor;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.videoeditor.MediaVideoItem;
-import android.media.videoeditor.OverlayFrame;
-import android.media.videoeditor.TransitionAlpha;
-import android.media.videoeditor.TransitionCrossfade;
-import android.media.videoeditor.TransitionFadeBlack;
-import android.media.videoeditor.TransitionSliding;
-import android.media.videoeditor.VideoEditor;
-import android.media.videoeditor.VideoEditorFactory;
-import android.util.Log;
-import android.os.Environment;
-
-/**
- * This class has the names of the all the activity name and variables in the
- * instrumentation test.
- */
-public class VideoEditorHelper extends Assert {
-
- private final String TAG = "VideoEditorMediaNames";
-
- public VideoEditorHelper() {
-
- }
-
- public static final String PROJECT_LOCATION_COMMON =
- Environment.getExternalStorageDirectory().toString() + "/";
-
- public static final String INPUT_FILE_PATH_COMMON = PROJECT_LOCATION_COMMON +
- "media_api/videoeditor/";
-
- // -----------------------------------------------------------------
- // HELPER METHODS
- // -----------------------------------------------------------------
-
- /**
- * This method creates an object of VideoEditor
- *
- * @param projectPath the directory where all files related to project will
- * be stored
- * @param className The class which implements the VideoEditor Class
- * @return the object of VideoEditor
- */
- public VideoEditor createVideoEditor(String projectPath) {
- VideoEditor mVideoEditor = null;
- try {
- mVideoEditor = VideoEditorFactory.create(projectPath);
- assertNotNull("VideoEditor", mVideoEditor);
- } catch (Exception e) {
- fail("Unable to create Video Editor");
- }
- return mVideoEditor;
- }
-
- /**
- *This method deletes the VideoEditor object created using
- * createVideoEditor method
- *
- * @param videoEditor the VideoEditor object which needs to be cleaned up
- */
- public void destroyVideoEditor(VideoEditor videoEditor) {
- // Release VideoEditor
- if (videoEditor != null) {
- try {
- videoEditor.release();
- } catch (Exception e) {
- fail("Unable to destory Video Editor");
- }
- }
- }
-
- /**
- *This Method checks the Range in "RangePercent" (say 10)
- *
- * @param int Expected data
- * @param actual data
- * @return boolean flag which confirms the range matching
- */
- public boolean checkRange(long expected, long actual, long rangePercent) {
- long range = 0;
- range = (100 * actual) / expected;
-
- Log.i("checkRange", "Range = " + range);
- if ((range > (100 - rangePercent)) && (range < (100 + rangePercent))) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- *This Method Creates a Bitmap with the given input file
- *
- * @param file the Input whose Bitmap has top be extracted
- * @return an Object of EffectColor
- */
- public Bitmap getBitmap(String file, int width, int height) throws IOException {
- assertNotNull("Bitmap File is Null", file);
- FileInputStream inputStream = null;
- Bitmap overlayBmp = null;
- if (!new File(file).exists())
- throw new IOException("File not Found " + file);
- try {
- final BitmapFactory.Options dbo = new BitmapFactory.Options();
- dbo.inJustDecodeBounds = true;
- dbo.outWidth = width;
- dbo.outHeight = height;
- File flPtr = new File(file);
- inputStream = new FileInputStream(flPtr);
- final Bitmap srcBitmap = BitmapFactory.decodeStream(inputStream);
- overlayBmp = Bitmap.createBitmap(srcBitmap);
- assertNotNull("Bitmap 1", srcBitmap);
- assertNotNull("Bitmap 2", overlayBmp);
- inputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return overlayBmp;
- }
-
- /**
- *This Method Create a Media Video Item with the specified params
- *
- * @return an Object of MediaVideoItem
- */
- public MediaVideoItem createMediaItem(VideoEditor videoEditor,
- String MediaId, String filename, int renderingMode) {
- MediaVideoItem mvi = null;
- try {
- mvi = new MediaVideoItem(videoEditor, MediaId, filename,
- renderingMode);
- assertNotNull("Can not create an object of MediaVideoItem", mvi);
- } catch (IllegalArgumentException e) {
- throw new IllegalArgumentException
- ("Can not create an object of Media Video Item with file name = "
- + filename + " Issue = " + e.toString());
- } catch (IOException e) {
- assertTrue
- ("Can not create an object of Media Video Item with file name = "
- + filename + " Issue = " + e.toString(), false);
- }
- return mvi;
- }
-
- /**
- *This Method Create a Media Image Item with the specified params
- *
- * @return an Object of MediaImageItem
- */
- public MediaImageItem createMediaItem(VideoEditor videoEditor,
- String MediaId, String filename, long duration, int renderingMode) {
- MediaImageItem mii = null;
- try {
- mii = new MediaImageItem(videoEditor, MediaId, filename, duration,
- renderingMode);
- assertNotNull("Can not create an object of MediaImageItem", mii);
-
- } catch (IllegalArgumentException e) {
- assertTrue("Can not create an object of Media Image with file name = "
- + filename + " Issue = " + e.toString(), false);
- } catch (IOException e) {
- assertTrue("Can not create an object of Media Image with file name = "
- + filename + " Issue = " + e.toString(), false);
- }
- return mii;
- }
-
- /**
- *This Method Create a Effect with the specified params
- *
- * @return an Object of EffectColor
- */
- public EffectColor createEffectItem(MediaItem mediaItem, String effectId,
- long startTime, long duration, int effectType, int colorType) {
- EffectColor effectonMVI = null;
- effectonMVI = new EffectColor(mediaItem, effectId, startTime,
- duration, effectType, colorType);
- return effectonMVI;
- }
-
- /**
- *This Method creates object of Type Transition Cross fade
- *
- * @return TransitionCrossfade object
- */
- public TransitionCrossfade createTCrossFade(String transitionId,
- MediaItem afterMediaItem, MediaItem beforeMediaItem, long durationMs,
- int behavior) {
- Log.i("TransitionCrossfade Details === ", "Transid ID = " + transitionId +
- " Duration= " + durationMs + " Behaviour " + behavior);
-
- TransitionCrossfade transitionCF = null;
- transitionCF = new TransitionCrossfade(transitionId, afterMediaItem,
- beforeMediaItem, durationMs, behavior);
- return transitionCF;
- }
-
- /**
- *This Method creates object of Type TransitionFadeBlack
- *
- * @return TransitionFadeBlack object
- */
- public TransitionFadeBlack createTFadeBlack(String transitionId,
- MediaItem afterMediaItem, MediaItem beforeMediaItem, long durationMs,
- int behavior) {
- TransitionFadeBlack transitionFB = null;
-
- transitionFB = new TransitionFadeBlack(transitionId, afterMediaItem,
- beforeMediaItem, durationMs, behavior);
- return transitionFB;
- }
-
- /**
- *This Method creates object of Type TransitionSliding
- *
- * @return TransitionSliding object
- */
- public TransitionSliding createTSliding(String transitionId,
- MediaItem afterMediaItem, MediaItem beforeMediaItem, long durationMs,
- int behavior, int direction) {
- TransitionSliding transSlide = null;
- transSlide = new TransitionSliding(transitionId, afterMediaItem,
- beforeMediaItem, durationMs, behavior, direction);
- return transSlide;
- }
-
- /**
- *This Method creates object of Type TranistionAlpha
- *
- * @return TranistionAlpha object
- */
-
- public TransitionAlpha createTAlpha(String transitionId,
- MediaItem afterMediaItem, MediaItem beforeMediaItem, long durationMs,
- int behavior, String maskFilename, int blendingPercent, boolean invert) {
- TransitionAlpha transA = null;
- transA = new TransitionAlpha(transitionId, afterMediaItem,
- beforeMediaItem, durationMs, behavior, maskFilename,
- blendingPercent, invert);
- return transA;
- }
-
- /**
- *This Method creates object of Type OverlayFrame
- *
- * @return OverlayFrame object
- */
-
- public OverlayFrame createOverlay(MediaItem mediaItem, String overlayId,
- Bitmap bitmap, long startTimeMs, long durationMs) {
- OverlayFrame overLayFrame = null;
- overLayFrame = new OverlayFrame(mediaItem, overlayId, bitmap,
- startTimeMs, durationMs);
- return overLayFrame;
- }
-
- /**
- *This Method creates object of Type AudioTrack
- *
- * @return OverlayFrame object
- */
- public AudioTrack createAudio(VideoEditor videoEditor, String audioTrackId,
- String filename) {
- AudioTrack audio = null;
- try {
- audio = new AudioTrack(videoEditor, audioTrackId, filename);
- assertNotNull("Cant not create an object of an AudioTrack " +
- audioTrackId, audio);
- } catch (IllegalArgumentException e) {
- assertTrue("Can not create object of an AudioTrack " +
- audioTrackId + " Issue = " + e.toString(), false);
- } catch (IOException e) {
- assertTrue("Can not create object of an AudioTrack " +
- audioTrackId + " Issue = " + e.toString(), false);
- }
- return audio;
- }
-
- /**
- *This Method validates the Exported Movie,as per the specified params
- * during Export
- */
-
- public void validateExport(VideoEditor videoEditor, String fileName,
- int export_height, int startTime, long endTime, int vCodec, int aCodec) {
- File tempFile = new File(fileName);
- assertEquals("Exported FileName", tempFile.exists(), true);
- final MediaVideoItem mvi = createMediaItem(videoEditor, "m1", fileName,
- MediaItem.RENDERING_MODE_BLACK_BORDER);
-
- Log.i(TAG, "VideoCodec for file = " + fileName +
- "\tExpected Video Codec = " + vCodec + "\tActual Video Codec = " +
- mvi.getVideoType());
- assertEquals("Export: Video Codec Mismatch for file = " + fileName +
- "\t<expected> " + vCodec + "\t<actual> " + mvi.getVideoType(),
- vCodec, mvi.getVideoType());
-
- Log.i(TAG, "Height for file = " + fileName + "\tExpected Height = " +
- export_height + "\tActual VideoHeight = " + mvi.getHeight());
- assertEquals("Export height Mismatch for file " + fileName +
- "\t<expected> " + export_height + "\t<actual> " + mvi.getHeight(),
- export_height, mvi.getHeight());
- if (startTime == 0) {
- if (endTime != 0) {
- Log.i(TAG, "TimeLine Expected = " + (startTime + endTime) +
- "\t VideoTime= " + mvi.getTimelineDuration());
- assertTrue("Timeline Duration Mismatch for file " + fileName +
- "<expected> " + (startTime + endTime) + "\t<actual> " +
- mvi.getTimelineDuration(), checkRange((startTime +
- endTime), mvi.getTimelineDuration(), 10));
- }
- } else {
- Log.i(TAG, "TimeLine Expected = " + (endTime - startTime) +
- "\t VideoTime= " + mvi.getTimelineDuration());
- assertTrue("Timeline Duration Mismatch for file " + fileName +
- "<expected> " + (endTime - startTime) + "\t<actual> " +
- mvi.getTimelineDuration(), checkRange((endTime -
- startTime), (int)mvi.getTimelineDuration(), 10));
- }
- }
-
- /**
- * @param videoEditor
- * @param fileName
- * @param export_bitrate
- * @param export_height
- * @param startTime
- * @param endTime
- * @param vCodec
- * @param aCodec
- */
- public void validateExport(VideoEditor videoEditor, String fileName,
- int export_height, int startTime, int endTime, int vCodec, int aCodec) {
- File tempFile = new File(fileName);
- assertEquals("Exported FileName", tempFile.exists(), true);
- final MediaVideoItem mvi = createMediaItem(videoEditor, "m1", fileName,
- MediaItem.RENDERING_MODE_BLACK_BORDER);
- Log.i(TAG, "VideoCodec for file = " + fileName +
- "\tExpected Video Codec = " + vCodec + "\tActual Video Codec = " +
- mvi.getVideoType());
- assertEquals("Export: Video Codec Mismatch for file = " + fileName +
- "\t<expected> " + vCodec + "\t<actual> " + mvi.getVideoType(),
- vCodec, mvi.getVideoType());
-
- Log.i(TAG, "AudioCodec for file = " + fileName +
- "\tExpected Audio Codec = " + aCodec + "\tActual Audio Codec = " +
- mvi.getAudioType());
- assertEquals("Export: Audio Codec Mismatch for file = " + fileName +
- "\t<expected> " + aCodec + "\t<actual> " + mvi.getAudioType(),
- aCodec, mvi.getAudioType());
-
- Log.i(TAG, "Height for file = " + fileName + "\tExpected Height = " +
- export_height + "\tActual VideoHeight = " + mvi.getHeight());
- assertEquals("Export: height Mismatch for file " + fileName +
- "\t<expected> " + export_height + "\t<actual> " + mvi.getHeight(),
- export_height, mvi.getHeight());
- if (startTime == 0) {
- if (endTime != 0) {
- Log.i(TAG, "TimeLine Expected = " + (startTime + endTime) +
- "\t VideoTime= " + mvi.getTimelineDuration());
- assertTrue("Export :Timeline Duration Mismatch for file " +
- fileName + "<expected> " + (startTime + endTime) +
- "\t<actual> " + mvi.getTimelineDuration(),
- checkRange((startTime + endTime), mvi.getTimelineDuration(), 10));
- }
- } else {
- Log.i(TAG, "TimeLine Expected = " + (endTime-startTime) +
- "\t VideoTime= " + mvi.getTimelineDuration());
- assertTrue("Timeline Duration Mismatch for file " + fileName +
- "<expected> " + (endTime - startTime) + "\t<actual> " +
- mvi.getTimelineDuration(), checkRange((endTime -
- startTime), mvi.getTimelineDuration(), 10));
- }
- }
-
- /**
- * Check file and deletes it.
- *
- * @param filename
- */
- public void checkDeleteExistingFile(String filename) {
- Log.i(TAG, ">>>>>>>>>>>>>>>>>>checkDeleteExistingFile = " + filename);
- if (filename != null) {
- File temp = new File(filename);
- if (temp != null && temp.exists()) {
- temp.delete();
- }
- }
- }
-
- /**
- * This method creates a Directory and filename
- *
- * @param location This is path where the file is to be created
- * "/sdcard/Output/"
- * @return Path in form of /sdcard/Output/200910100000
- */
- public String createRandomFile(String location) {
- Random randomGenerator = new Random();
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssS");
- Date date = new Date();
- final String filePath = location + dateFormat.format(date) +
- randomGenerator.nextInt(10);
- Log.i(TAG, ">>>>>>>>>>>>>>>>createRandomFile Location= " + location +
- "\t FilePath = " + filePath);
- return filePath;
- }
-
- /**
- * This method recursively deletes all the file and directory
- *
- * @param directory where the files are located Example = "/sdcard/Input"
- * @return boolean True if deletion is successful else False
- */
- public boolean deleteProject(File directory) {
- Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>>>>deleteProject directory= " +
- directory.toString());
- if (directory.isDirectory()) {
- String[] filesInDirecory = directory.list();
- for (int i = 0; i < filesInDirecory.length; i++) {
- boolean success = deleteProject(new File(directory,
- filesInDirecory[i]));
- if (!success) {
- return false;
- }
- }
- }
- return directory.delete();
- }
-
- /**
- * This method compares the array of Integer from 0 - 100
- *
- * @param data set of integer values received as progress
- * @return true if sucess else false
- */
- public boolean checkProgressCBValues(int[] data) {
- boolean retFlag = false;
- for (int i = 0; i < 100; i++) {
- if (data[i] == 100) {
- retFlag = true;
- break;
- } else {
- retFlag = false;
- }
- }
- return retFlag;
- }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaItemThumbnailTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaItemThumbnailTest.java
deleted file mode 100644
index 7dfab7d..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaItemThumbnailTest.java
+++ /dev/null
@@ -1,921 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.mediaframeworktest.functional.videoeditor;
-
-import java.io.File;
-import java.io.IOException;
-
-import android.graphics.Bitmap;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.videoeditor.MediaVideoItem;
-import android.media.videoeditor.VideoEditor;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.VideoEditorHelper;
-
-public class MediaItemThumbnailTest extends
- ActivityInstrumentationTestCase<MediaFrameworkTest> {
- private final String TAG = "MediaItemThumbailTest";
-
- private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
-
- private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
-
- private VideoEditor mVideoEditor;
-
- private VideoEditorHelper mVideoEditorHelper;
-
- public MediaItemThumbnailTest() {
- super("com.android.mediaframeworktest", MediaFrameworkTest.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- // setup for each test case.
- super.setUp();
- mVideoEditorHelper = new VideoEditorHelper();
- // Create a random String which will be used as project path, where all
- // project related files will be stored.
- final String projectPath = mVideoEditorHelper.
- createRandomFile(PROJECT_LOCATION);
- mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
- // Clean the directory created as project path
- mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
- System.gc();
- super.tearDown();
- }
-
- protected void validateThumbnail(Bitmap thumbNailBmp, int outWidth,
- int outHeight) throws Exception {
- assertNotNull("Thumbnail Retrived is Null", thumbNailBmp);
- assertEquals("Thumbnail Height", outHeight, thumbNailBmp.getHeight());
- assertEquals("Thumbnail Width", outWidth, thumbNailBmp.getWidth());
- thumbNailBmp.recycle();
- }
-
- // -----------------------------------------------------------------
- // THUMBNAIL
- // -----------------------------------------------------------------
- /**
- * To test thumbnail / frame extraction on H.263 QCIF.
- */
- @LargeTest
- public void testThumbnailForH263QCIF() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final int atTime = 0;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = mediaVideoItem.getHeight();
-
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on MPEG4 VGA .
- */
- @LargeTest
- public void testThumbnailForMPEG4VGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_30fps_512Kbps_0_23.3gp";
- final int atTime = 0;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = mediaVideoItem.getHeight();
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on MPEG4 NTSC.
- */
- @LargeTest
- public void testThumbnailForMPEG4NTSC() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
- final int atTime = 0;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth() / 2;
- final int outHeight = mediaVideoItem.getHeight() / 2;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on MPEG4 WVGA.
- */
- @LargeTest
- public void testThumbnailForMPEG4WVGA() throws Exception {
-
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_800x480_515kbps_15fps_AMR_NB_8KHz_12.2kbps_m_0_26.mp4";
- final int atTime = 0;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth() * 2;
- final int outHeight = mediaVideoItem.getHeight();
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on MPEG4 QCIF.
- */
- @LargeTest
- public void testThumbnailForMPEG4QCIF() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- final int atTime = 0;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth();
- final int outHeight = mediaVideoItem.getHeight() * 2;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on H264 QCIF.
- */
- @LargeTest
- public void testThumbnailForH264QCIF() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H264_BP_176x144_15fps_144kbps_AMRNB_8kHz_12.2kbps_m_1_17.3gp";
-
- final int atTime = 0;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth() * 2;
- final int outHeight = mediaVideoItem.getHeight() * 2;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on H264 VGA.
- */
- @LargeTest
- public void testThumbnailForH264VGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final int outWidth = 32;
- final int outHeight = 32;
- final int atTime = 0;
-
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
- /**
- * To test thumbnail / frame extraction on H264 WVGA.
- */
- @LargeTest
- public void testThumbnailForH264WVGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4";
- final int outWidth = 64;
- final int outHeight = 64;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final long atTime = mediaVideoItem.getDuration() / 2;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on H264 854x480.
- */
- @LargeTest
- public void testThumbnailForH264854_480() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_854x480_15fps_256kbps_AACLC_16khz_48kbps_s_0_26.mp4";
- final int outWidth = 128;
- final int outHeight = 128;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- MediaVideoItem mediaVideoItem = null;
- mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final long atTime = mediaVideoItem.getDuration() - 1000;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on H264 960x720.
- */
- @LargeTest
- public void testThumbnailForH264HD960() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_960x720_25fps_800kbps_AACLC_48Khz_192Kbps_s_1_17.mp4";
- final int outWidth = 75;
- final int outHeight = 75;
-
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final long atTime = mediaVideoItem.getDuration() - 1000;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on H264 1080x720 .
- */
- @LargeTest
- public void testThumbnailForH264HD1080() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth() / 2;
- final int outHeight = mediaVideoItem.getHeight() / 2;
- final long atTime = mediaVideoItem.getDuration() / 4;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * Check the thumbnail / frame extraction precision at 0,100 and 200 ms
- */
- @LargeTest
- public void testThumbnailForH264VGADifferentDuration() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final int atTime = 0;
- final int atTime1 = 100;
- final int atTime2 = 200;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth();
- final int outHeight = mediaVideoItem.getHeight();
-
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
-
- // get Thumbnail @ 100ms
- final Bitmap thumbNailBmpAt100 =
- mediaVideoItem.getThumbnail(outWidth, outHeight, atTime1);
- validateThumbnail(thumbNailBmpAt100, outWidth, outHeight);
-
- // get Thumbnail @ 200ms
- final Bitmap thumbNailBmpAt200 = mediaVideoItem.getThumbnail(
- outWidth, outHeight, atTime2);
- validateThumbnail(thumbNailBmpAt200, outWidth, outHeight);
- }
-
- /**
- *Check the thumbnail / frame extraction precision at
- * FileDuration,FileDuration/2 + 100 andFileDuration/2 + 200 ms
- */
- @LargeTest
- public void testThumbnailForMP4VGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_256kbps_0_30.mp4";
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, MediaItem.RENDERING_MODE_BLACK_BORDER);
-
- final int outWidth = mediaVideoItem.getWidth();
- final int outHeight = mediaVideoItem.getHeight();
- final long atTime = mediaVideoItem.getDuration() / 2;
- final long atTime1 = atTime + 100;
- final long atTime2 = atTime + 200;
-
- // get Thumbnail @ duration/2
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
-
- // get Thumbnail @ duration/2 + 100ms
- final Bitmap thumbNailBmpAt100 = mediaVideoItem.getThumbnail(
- outWidth, outHeight, atTime1);
- validateThumbnail(thumbNailBmpAt100, outWidth, outHeight);
-
- // get Thumbnail @ duration/2 + 200ms
- final Bitmap thumbNailBmpAt200 = mediaVideoItem.getThumbnail(
- outWidth, outHeight, atTime2);
- validateThumbnail(thumbNailBmpAt200, outWidth, outHeight);
- }
-
- /**
- * Check the thumbnail / frame extraction on JPEG file
- */
- @LargeTest
- public void testThumbnailForImage() throws Exception {
- final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int mediaDuration = 1000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- int outWidth = 0;
- int outHeight = 0;
-
- final MediaImageItem mii = mVideoEditorHelper.createMediaItem(
- mVideoEditor, "m1", imageItemFilename, mediaDuration, renderingMode);
- assertNotNull("Media Image Item is Null", mii);
- outWidth = mii.getWidth() / 2;
- outHeight = mii.getHeight() / 2;
-
- final Bitmap thumbNailBmp = mii.getThumbnail(outWidth,
- outHeight, mediaDuration);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
- /**
- *To test ThumbnailList for H263 QCIF
- */
- @LargeTest
- public void testThumbnailListH263QCIF() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_1_17.3gp";
- final int startTime = 0;
- final int tnCount = 10;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- final int outWidth = mediaVideoItem.getWidth() / 4;
- final int outHeight = mediaVideoItem.getHeight() / 4;
- final long endTime = mediaVideoItem.getDuration() / 2;
-
- final Bitmap thumbNailBmp[] = mediaVideoItem.getThumbnailList(
- outWidth, outHeight, startTime, endTime, tnCount);
- assertNotNull("Thumbnail Retrived is Null", thumbNailBmp);
- assertEquals("Thumbnail Count", tnCount, thumbNailBmp.length);
-
- for (int i = 0; i < thumbNailBmp.length; i++) {
- validateThumbnail(thumbNailBmp[i], outWidth, outHeight);
- thumbNailBmp[i] = null;
- }
- }
-
- /**
- *To test ThumbnailList for MPEG4 QCIF
- */
- @LargeTest
- public void testThumbnailListMPEG4QCIF() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- final int tnCount = 10;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- final int outWidth = mediaVideoItem.getWidth() / 2;
- final int outHeight = mediaVideoItem.getHeight() / 2;
- final long startTime = mediaVideoItem.getDuration() / 2;
- final long endTime = mediaVideoItem.getDuration();
-
- final Bitmap thumbNailBmp[] = mediaVideoItem.getThumbnailList(
- outWidth, outHeight, startTime, endTime, tnCount);
-
- assertNotNull("Thumbnail Retrived is Null", thumbNailBmp);
- assertEquals("Thumbnail Count", tnCount, thumbNailBmp.length);
- for (int i = 0; i < thumbNailBmp.length; i++) {
- validateThumbnail(thumbNailBmp[i], outWidth, outHeight);
- thumbNailBmp[i] = null;
- }
- }
-
- /**
- *To test ThumbnailList for H264 VGA
- */
- @LargeTest
- public void testThumbnailListH264VGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final int tnCount = 10;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- final int outWidth = mediaVideoItem.getWidth() / 2;
- final int outHeight = mediaVideoItem.getHeight() / 2;
- final long startTime = mediaVideoItem.getDuration() / 3;
- final long endTime = mediaVideoItem.getDuration() / 2;
-
- final Bitmap thumbNailBmp[] = mediaVideoItem.getThumbnailList(
- outWidth, outHeight, startTime, endTime, tnCount);
- assertNotNull("Thumbnail Retrived is Null", thumbNailBmp);
- assertEquals("Thumbnail Count", tnCount, thumbNailBmp.length);
- for (int i = 0; i < thumbNailBmp.length; i++) {
- validateThumbnail(thumbNailBmp[i], outWidth, outHeight);
- thumbNailBmp[i] = null;
- }
- }
-
- /**
- *To test ThumbnailList for H264 WVGA
- */
- @LargeTest
- public void testThumbnailListH264WVGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4";
- final int tnCount = 10;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- final int outWidth = mediaVideoItem.getWidth() / 2;
- final int outHeight = mediaVideoItem.getHeight() / 2;
- final long startTime = mediaVideoItem.getDuration() / 3;
- final long endTime = mediaVideoItem.getDuration() / 2;
-
- final Bitmap thumbNailBmp[] = mediaVideoItem.getThumbnailList(
- outWidth, outHeight, startTime, endTime, tnCount);
- assertNotNull("Thumbnail Retrived is Null", thumbNailBmp);
- assertEquals("Thumbnail Count", tnCount, thumbNailBmp.length);
- for (int i = 0; i < thumbNailBmp.length; i++) {
- validateThumbnail(thumbNailBmp[i], outWidth, outHeight);
- thumbNailBmp[i] = null;
- }
- }
-
- /**
- *To test ThumbnailList for H264 VGA ,Time exceeding file duration
- */
- @LargeTest
- public void testThumbnailH264VGAExceedingFileDuration() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- boolean flagForException = false;
- int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- try {
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth() / 2;
- final int outHeight = mediaVideoItem.getHeight() / 2;
- final long atTime = mediaVideoItem.getDuration() + 2000;
- mediaVideoItem.getThumbnail(outWidth, outHeight, atTime);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Exception in Extracting thumbanil with Invalid Time",
- flagForException);
- }
-
- /**
- *To test ThumbnailList for VGA Image
- */
- @LargeTest
- public void testThumbnailListVGAImage() throws Exception {
- final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int imageItemDuration = 10000;
- final int startTime = 0;
- final int endTime = 0;
- final int tnCount = 10;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- imageItemFilename, imageItemDuration, renderingMode);
- final int outWidth = mediaImageItem.getWidth() / 2;
- final int outHeight = mediaImageItem.getHeight() / 2;
-
- final Bitmap thumbNailBmp[] = mediaImageItem.getThumbnailList
- (outWidth, outHeight, startTime, endTime, tnCount);
- assertNotNull("Thumbnail Retrived is Null", thumbNailBmp);
- assertEquals("Thumbnail Count", tnCount, thumbNailBmp.length);
- for (int i = 0; i < thumbNailBmp.length; i++) {
- validateThumbnail(thumbNailBmp[i], outWidth, outHeight);
- thumbNailBmp[i] = null;
- }
- }
-
- /**
- *To test ThumbnailList for Invalid file path
- */
- @LargeTest
- public void testThumbnailForInvalidFilePath() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "/sdcard/abc.jpg";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- try{
- final MediaImageItem mii = new MediaImageItem(mVideoEditor, "m1",
- imageItemFileName, 3000, renderingMode);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- } catch (IOException e) {
- flagForException = true;
- }
- assertTrue(" Invalid File Path", flagForException);
- }
-
- /**
- * To test thumbnail / frame extraction with setBoundaries
- */
- @LargeTest
- public void testThumbnailForMPEG4WVGAWithSetBoundaries() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "MPEG4_SP_800x480_515kbps_15fps_AMR_NB_8KHz_12.2kbps_m_0_26.mp4";
- final int atTime = 10000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- mediaVideoItem.setExtractBoundaries(1000,
- (mediaVideoItem.getDuration() - 21000));
-
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = (mediaVideoItem.getHeight() / 2);
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail(outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- *To test ThumbnailList for H264 WVGA with setExtractboundaries
- */
- @LargeTest
- public void testThumbnailListForH264WVGAWithSetBoundaries() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_1_17.mp4";
- final int thumbNailStartTime = 10000;
- final int thumbNailEndTime = 12000;
- final int tnCount = 10;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = (mediaVideoItem.getHeight() / 2);
-
- mediaVideoItem.setExtractBoundaries(10000, 12000);
-
- final Bitmap thumbNailBmp[] = mediaVideoItem.getThumbnailList
- (outWidth, outHeight, thumbNailStartTime, thumbNailEndTime,
- tnCount);
- assertNotNull("Thumbnail Retrived is Null", thumbNailBmp);
- assertTrue("Thumbnail Size", (thumbNailBmp.length > 0) ? true : false);
- for (int i = 0; i < thumbNailBmp.length; i++) {
- validateThumbnail(thumbNailBmp[i], outWidth, outHeight);
- thumbNailBmp[i] = null;
- }
- }
-
- /**
- *To test ThumbnailList for H264 WVGA with count > frame available
- */
- @LargeTest
- public void testThumbnailListForH264WVGAWithCount() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4";
- final int tnCount = 70;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
-
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = (mediaVideoItem.getHeight() / 2);
- final long thumbNailStartTime = mediaVideoItem.getDuration() / 2;
- final long thumbNailEndTime = thumbNailStartTime + 4000;
- Bitmap thumbNailBmp[] = null;
- boolean flagForException = false;
- try{
- thumbNailBmp = mediaVideoItem.getThumbnailList(outWidth, outHeight,
- thumbNailStartTime, thumbNailEndTime, tnCount);
- }catch (Exception e){
- assertTrue("Unable to get Thumbnail list", flagForException);
- }
- if (thumbNailBmp.length <= tnCount) {
- flagForException = true;
- }
- assertTrue("Thumbnail count more than asked", flagForException);
- }
-
- /**
- *To test ThumbnailList for H264 WVGA with startTime > End Time
- */
- @LargeTest
- public void testThumbnailListH264WVGAWithStartGreaterEnd() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int tnCount = 10;
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = (mediaVideoItem.getHeight() / 2);
- final long thumbNailStartTime = mediaVideoItem.getDuration() / 2;
- final long thumbNailEndTime = thumbNailStartTime - 1000;
- try{
- mediaVideoItem.getThumbnailList(outWidth, outHeight,
- thumbNailStartTime, thumbNailEndTime, tnCount);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Thumbnail Extraction where start time > end time",
- flagForException);
- }
-
- /**
- *To test ThumbnailList for H264 WVGA with startTime = End Time
- */
- @LargeTest
- public void testThumbnailListH264WVGAWithStartEqualEnd() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4";
- final int tnCount = 1;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = (mediaVideoItem.getHeight() / 2);
- final long thumbNailStartTime = mediaVideoItem.getDuration() / 2;
- final long thumbNailEndTime = thumbNailStartTime;
- final Bitmap thumbNailBmp[] = mediaVideoItem.getThumbnailList(outWidth,
- outHeight, thumbNailStartTime, thumbNailEndTime, tnCount);
- assertNotNull("Thumbnail Retrived is Null", thumbNailBmp);
- assertEquals("Thumbnail Count", tnCount, thumbNailBmp.length);
- for (int i = 0; i < thumbNailBmp.length; i++) {
- validateThumbnail(thumbNailBmp[i], outWidth, outHeight);
- thumbNailBmp[i] = null;
- }
- }
-
- /**
- *To test ThumbnailList for file where video duration is less
- * than file duration.
- */
- @LargeTest
- public void testThumbnailForVideoDurationLessFileDuration() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H264_BP_640x480_15fps_1200Kbps_AACLC_48KHz_64kps_m_0_27.3gp";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = (mediaVideoItem.getHeight() / 2);
- final long atTime = mediaVideoItem.getDuration() - 2000;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail (outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
-
- }
-
- /**
- *To test ThumbnailList for file which has video part corrupted
- */
- @LargeTest
- public void testThumbnailWithCorruptedVideoPart() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "corrupted_H264_BP_640x480_12.5fps_256kbps_AACLC_16khz_24kbps_s_0_26.mp4";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
-
- try {
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth();
- final int outHeight = mediaVideoItem.getHeight() * 2;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail
- (outWidth, outHeight, mediaVideoItem.getDuration()/2);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Corrupted File cannot be read", flagForException);
- }
-
- /**
- * Check the thumbnail / frame list extraction for Height as Negative Value
- */
- @LargeTest
- public void testThumbnailWithNegativeHeight() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- final int tnCount = 10;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- try {
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = -1;
- final long thumbNailStartTime =
- mediaVideoItem.getBoundaryBeginTime()/2;
- final long thumbNailEndTime = mediaVideoItem.getBoundaryEndTime();
- mediaVideoItem.getThumbnailList(outWidth, outHeight,
- thumbNailStartTime, thumbNailEndTime, tnCount);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Thumbnail List with negative Height", flagForException);
- }
-
- /**
- * Check the thumbnail for Height as Zero
- */
- @LargeTest
- public void testThumbnailWithHeightAsZero() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- final int atTime = 100;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- try {
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = -1;
- mediaVideoItem.getThumbnail(outWidth, outHeight, atTime);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Thumbnail List with Zero Height", flagForException);
- }
-
- /**
- * Check the thumbnail for Height = 10
- */
- @LargeTest
- public void testThumbnailWithHeight() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- final int atTime = 1000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = (mediaVideoItem.getWidth() / 2);
- final int outHeight = 10;
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail (outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * Check the thumbnail / frame list extraction for Width as Negative Value
- */
- @LargeTest
- public void testThumbnailWithNegativeWidth() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- final int tnCount = 10;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- try {
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = -1;
- final int outHeight = mediaVideoItem.getHeight();
- final long thumbNailStartTime =
- mediaVideoItem.getBoundaryBeginTime()/2;
- final long thumbNailEndTime = mediaVideoItem.getBoundaryEndTime();
- mediaVideoItem.getThumbnailList(outWidth, outHeight, thumbNailStartTime,
- thumbNailEndTime, tnCount);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Thumbnail List with negative Height", flagForException);
- }
-
- /**
- * Check the thumbnail / frame list extraction for Width zero
- */
- @LargeTest
- public void testThumbnailWithWidthAsZero() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- final int atTime = 1000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- try {
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = 0;
- final int outHeight = mediaVideoItem.getHeight() / 2;
- mediaVideoItem.getThumbnail(outWidth, outHeight, atTime);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Thumbnail List with Zero Width", flagForException);
- }
-
- /**
- * Check the thumbnail for Width = 10
- */
- @LargeTest
- public void testThumbnailWithWidth() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- final int atTime = 1000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = 10;
- final int outHeight = mediaVideoItem.getHeight();
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail (outWidth,
- outHeight, atTime);
- validateThumbnail(thumbNailBmp, outWidth, outHeight);
- }
-
- /**
- * To test thumbnail / frame extraction on MPEG4 (time beyond file duration).
- */
- @LargeTest
- public void testThumbnailMPEG4withMorethanFileDuration() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_30fps_256kbps_AACLC_44.1kHz_96kbps_s_1_17.3gp";
- boolean flagForException = false;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename, renderingMode);
- final int outWidth = mediaVideoItem.getWidth()/2;
- final int outHeight = mediaVideoItem.getHeight()/2;
- final long atTime = mediaVideoItem.getDuration() + 100;
- try{
- final Bitmap thumbNailBmp = mediaVideoItem.getThumbnail (outWidth,
- outHeight, atTime);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Thumbnail duration is more than file duration",
- flagForException);
- }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaPropertiesTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaPropertiesTest.java
deleted file mode 100644
index 34cf9f0..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaPropertiesTest.java
+++ /dev/null
@@ -1,750 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.functional.videoeditor;
-
-import java.io.File;
-import java.io.IOException;
-
-import android.media.videoeditor.AudioTrack;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.videoeditor.MediaProperties;
-import android.media.videoeditor.MediaVideoItem;
-import android.media.videoeditor.VideoEditor;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import com.android.mediaframeworktest.VideoEditorHelper;
-import com.android.mediaframeworktest.MediaProfileReader;
-
-public class MediaPropertiesTest extends
- ActivityInstrumentationTestCase<MediaFrameworkTest> {
- private final String TAG = "MediaPropertiesTest";
-
- private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
-
- private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
-
- private VideoEditor mVideoEditor;
-
- private VideoEditorHelper mVideoEditorHelper;
-
- public MediaPropertiesTest() {
- super("com.android.mediaframeworktest", MediaFrameworkTest.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- // setup for each test case.
- super.setUp();
- mVideoEditorHelper = new VideoEditorHelper();
- // Create a random String which will be used as project path,
- // where all project related files will be stored.
- final String projectPath = mVideoEditorHelper.
- createRandomFile(PROJECT_LOCATION);
- mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
- // Clean the directory created as project path
- mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
- System.gc();
- super.tearDown();
- }
-
- protected void validateVideoProperties(int aspectRatio, int fileType,
- int videoCodecType, int duration, int videoBitrate, int fps,
- int videoProfile, int videoLevel, int width, int height, int audioCodecType,
- int audioSamplingFrequency, int audioChannel, int audioBitrate,
- MediaVideoItem mvi) throws Exception {
- assertEquals("Aspect Ratio Mismatch", aspectRatio, mvi.getAspectRatio());
- assertEquals("File Type Mismatch", fileType, mvi.getFileType());
- assertEquals("VideoCodec Mismatch", videoCodecType, mvi.getVideoType());
-
- assertTrue("Video duration Mismatch", mVideoEditorHelper.checkRange (
- duration, mvi.getDuration(), 10));
- assertEquals("Video Profile " + mvi.getVideoProfile(), videoProfile,
- mvi.getVideoProfile());
- assertEquals("Video Level " + mvi.getVideoLevel(), videoLevel,
- mvi.getVideoLevel());
- assertEquals("Video height " + mvi.getHeight(), height, mvi.getHeight());
- assertEquals("Video width " + mvi.getWidth(), width, mvi.getWidth());
- /** Check FPS with 10% range */
- assertTrue("fps Mismatch" + mvi.getFps(),
- mVideoEditorHelper.checkRange(fps, mvi.getFps(), 10));
-
- assertEquals("AudioType Mismatch ", audioCodecType, mvi.getAudioType());
- assertEquals("Audio Sampling " + mvi.getAudioSamplingFrequency(),
- audioSamplingFrequency, mvi.getAudioSamplingFrequency());
- // PV SW AAC codec always returns number of channels as Stereo.
- // So we do not assert for number of audio channels for AAC_LC
- if ( audioCodecType != MediaProperties.ACODEC_AAC_LC ) {
- assertEquals("Audio Channels " + mvi.getAudioChannels(), audioChannel,
- mvi.getAudioChannels());
- }
- }
-
- protected void validateAudioProperties(int audioCodecType, int duration,
- int audioSamplingFrequency, int audioChannel, int audioBitrate,
- AudioTrack aT) throws Exception {
- assertEquals("AudioType Mismatch ", audioCodecType, aT.getAudioType());
- assertTrue("Video duration Mismatch", mVideoEditorHelper.checkRange (
- duration, aT.getDuration(), 10));
- assertEquals("Audio Sampling " + aT.getAudioSamplingFrequency(),
- audioSamplingFrequency, aT.getAudioSamplingFrequency());
- // PV SW AAC codec always returns number of channels as Stereo.
- // So we do not assert for number of audio channels for AAC_LC
- if ( audioCodecType != MediaProperties.ACODEC_AAC_LC ) {
- assertEquals("Audio Channels " + aT.getAudioChannels(), audioChannel,
- aT.getAudioChannels());
- }
- }
-
- protected void validateImageProperties(int aspectRatio, int fileType,
- int width, int height, MediaImageItem mii)
- throws Exception {
- assertEquals("Aspect Ratio Mismatch", aspectRatio, mii.getAspectRatio());
- assertEquals("File Type Mismatch", fileType, mii.getFileType());
- assertEquals("Image height " + mii.getHeight(), height, mii.getHeight());
- assertEquals("Image width " + mii.getWidth(), width, mii.getWidth());
- }
-
-
- /**
- *To test Media Properties for file MPEG4 854 x 480
- */
- @LargeTest
- public void testPropertiesMPEG4854_480() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_854x480_15fps_256kbps_AACLC_16khz_48kbps_s_0_26.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_16_9;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_MPEG4;
- final int duration = 26933;
- final int videoBitrate = 319000;
- final int audioBitrate = 48000;
- final int fps = 15;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 16000;
- final int audioChannel = 2;
- final int videoProfile = MediaProperties.MPEG4Profile.MPEG4ProfileSimple;
- final int videoLevel = MediaProperties.MPEG4Level.MPEG4Level1;
- final int width = 854;
- final int height = MediaProperties.HEIGHT_480;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename,
- MediaItem.RENDERING_MODE_BLACK_BORDER);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
-
- /**
- *To test Media Properties for file MPEG4 WVGA
- */
- @LargeTest
- public void testPropertiesMPEGWVGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_800x480_515kbps_15fps_AMR_NB_8KHz_12.2kbps_m_0_26.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_5_3;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_MPEG4;
- final int duration = 26933;
- final int videoBitrate = 384000;
- final int audioBitrate = 12800;
- final int fps = 15;
- final int audioCodecType = MediaProperties.ACODEC_AMRNB;
- final int audioSamplingFrequency = 8000;
- final int audioChannel = 1;
- final int videoProfile = MediaProperties.MPEG4Profile.MPEG4ProfileSimple;
- final int videoLevel = MediaProperties.MPEG4Level.MPEG4Level1;
- final int width = 800;
- final int height = MediaProperties.HEIGHT_480;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test media properties for MPEG4 720x480 (NTSC) + AAC file.
- */
- @LargeTest
- public void testPropertiesMPEGNTSC() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_161kbps_s_0_26.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_3_2;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_MPEG4;
- final int duration = 26866;
- final int videoBitrate = 403000;
- final int audioBitrate = 160000;
- final int fps = 30;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 48000;
- final int audioChannel = 2;
- final int videoProfile = MediaProperties.MPEG4Profile.MPEG4ProfileSimple;
- final int videoLevel = MediaProperties.MPEG4Level.MPEG4Level1;
- final int width = 720;
- final int height = MediaProperties.HEIGHT_480;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test Media Properties for file MPEG4 VGA
- */
- @LargeTest
- public void testPropertiesMPEGVGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_4_3;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_MPEG4;
- final int duration = 26933;
- final int videoBitrate = 533000;
- final int audioBitrate = 128000;
- final int fps = 15;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 48000;
- final int audioChannel = 2;
- final int videoProfile = MediaProperties.MPEG4Profile.MPEG4ProfileSimple;
- final int videoLevel = MediaProperties.MPEG4Level.MPEG4Level1;
- final int width = 640;
- final int height = MediaProperties.HEIGHT_480;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test Media Properties for file MPEG4 QCIF
- */
- @LargeTest
- public void testPropertiesMPEGQCIF() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "MPEG4_SP_176x144_12fps_92kbps_AMRNB_8KHz_12.2kbps_m_0_27.3gp";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_11_9;
- final int fileType = MediaProperties.FILE_3GP;
- final int videoCodecType = MediaProperties.VCODEC_MPEG4;
- final int duration = 27000;
- final int videoBitrate = 384000;
- final int audioBitrate = 12200;
- final int fps = 12;
- final int audioCodecType = MediaProperties.ACODEC_AMRNB;
- final int audioSamplingFrequency = 8000;
- final int audioChannel = 1;
- final int videoProfile = MediaProperties.MPEG4Profile.MPEG4ProfileSimple;
- final int videoLevel = MediaProperties.MPEG4Level.MPEG4Level1;
- final int width = 176;
- final int height = MediaProperties.HEIGHT_144;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To To test media properties for H263 176x144 (QCIF) + AAC (mono) file.
- */
- @LargeTest
- public void testPropertiesH263QCIF() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_16kHz_32kbps_m_0_26.3gp";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_11_9;
- final int fileType = MediaProperties.FILE_3GP;
- final int videoCodecType = MediaProperties.VCODEC_H263;
- final int duration = 26933;
- final int videoBitrate = 384000;
- final int audioBitrate = 64000;
- final int fps = 15;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 16000;
- final int audioChannel = 1;
- final int videoProfile = MediaProperties.H263Profile.H263ProfileBaseline;
- final int videoLevel = MediaProperties.H263Level.H263Level10;
- final int width = 176;
- final int height = MediaProperties.HEIGHT_144;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test Media Properties for file H264 VGA
- */
- @LargeTest
- public void testPropertiesH264VGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H264_BP_640x480_15fps_1200Kbps_AACLC_48KHz_64kps_m_0_27.3gp";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_4_3;
- final int fileType = MediaProperties.FILE_3GP;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int duration = 77600;
- final int videoBitrate = 745000;
- final int audioBitrate = 64000;
- final int fps = 15;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 48000;
- final int audioChannel = 2;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileBaseline;
- final int videoLevel = MediaProperties.H264Level.H264Level13;
- final int width = 640;
- final int height = MediaProperties.HEIGHT_480;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test Media Properties for file H264 NTSC
- */
- @LargeTest
- public void testPropertiesH264NTSC() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H264_BP_720x480_25fps_256kbps_AMRNB_8khz_12.2kbps_m_0_26.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_3_2;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int duration = 26880;
- final int videoBitrate = 244000;
- final int audioBitrate = 12200;
- final int fps = 25;
- final int audioCodecType = MediaProperties.ACODEC_AMRNB;
- final int audioSamplingFrequency = 8000;
- final int audioChannel = 1;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileBaseline;
- final int videoLevel = MediaProperties.H264Level.H264Level13;
- final int width = 720;
- final int height = MediaProperties.HEIGHT_480;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test media properties for H264 800x480 (WVGA) + AAC file.
- */
- @LargeTest
- public void testPropertiesH264WVGA() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_AACLC_24KHz_38Kbps_s_1_17.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_5_3;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int duration = 77466;
- final int videoBitrate = 528000;
- final int audioBitrate = 38000;
- final int fps = 15;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 24000;
- final int audioChannel = 2;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileBaseline;
- final int videoLevel = MediaProperties.H264Level.H264Level13;
- final int width = 800;
- final int height = MediaProperties.HEIGHT_480;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test Media Properties for file H264 HD1280
- */
- @LargeTest
- public void testPropertiesH264HD1280() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H264_BP_1280x720_15fps_512kbps_AACLC_16khz_48kbps_s_1_17.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_16_9;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int duration = 77600;
- final int videoBitrate = 606000;
- final int audioBitrate = 48000;
- final int fps = 15;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 16000;
- final int audioChannel = 2;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileBaseline;
- final int videoLevel = MediaProperties.H264Level.H264Level13;
- final int width = 1280;
- final int height = MediaProperties.HEIGHT_720;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test media properties for H264 1080x720 + AAC file
- */
- @LargeTest
- public void testPropertiesH264HD1080WithAudio() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H264_BP_1080x720_30fps_12Mbps_AACLC_44.1khz_64kbps_s_1_17.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_3_2;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int duration = 77500;
- final int videoBitrate = 1190000;
- final int audioBitrate = 64000;
- final int fps = 10;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 44100;
- final int audioChannel = 2;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileBaseline;
- final int videoLevel = MediaProperties.H264Level.H264Level13;
- final int width = 1080;
- final int height = MediaProperties.HEIGHT_720;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test Media Properties for file WMV - Unsupported type
- */
- @LargeTest
- public void testPropertiesWMVFile() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "WMV_V7_640x480_15fps_512Kbps_wma_V9_44khz_48Kbps_s_1_30.wmv";
- boolean flagForException = false;
- if (MediaProfileReader.getWMVEnable() == false) {
- flagForException = true;
- } else {
- try {
- new MediaVideoItem(mVideoEditor, "m1", videoItemFilename,
- MediaItem.RENDERING_MODE_BLACK_BORDER);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- } catch (IOException e) {
- flagForException = true;
- }
- }
- assertTrue("Media Properties for a WMV File -- Unsupported file type",
- flagForException);
- }
-
- /**
- *To test media properties for H.264 Main/Advanced profile.
- */
- @LargeTest
- public void testPropertiesH264MainLineProfile() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH
- + "H264_MP_960x720_25fps_800kbps_AACLC_48Khz_192Kbps_s_1_17.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_4_3;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int fileType = MediaProperties.FILE_MP4;
- final int duration = 77500;
- final int videoBitrate = 800000;
- final int audioBitrate = 192000;
- final int fps = 25;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 48000;
- final int audioChannel = 2;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileMain;
- final int videoLevel = MediaProperties.H264Level.H264Level31;
- final int width = 960;
- final int height = MediaProperties.HEIGHT_720;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
-
- }
-
- /**
- *To test Media Properties for non existing file.
- */
- @LargeTest
- public void testPropertiesForNonExsitingFile() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH + "abc.3gp";
- boolean flagForException = false;
-
- try {
- new MediaVideoItem(mVideoEditor, "m1", videoItemFilename,
- MediaItem.RENDERING_MODE_BLACK_BORDER);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- } catch (IOException e) {
- flagForException = true;
- }
- assertTrue("Media Properties for non exsisting file", flagForException);
- }
-
- /**
- *To test Media Properties for file H264 HD1080
- */
- @LargeTest
- public void testPropertiesH264HD1080WithoutAudio() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final int aspectRatio = MediaProperties.ASPECT_RATIO_3_2;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int duration = 77366;
- final int videoBitrate = 859000;
- final int audioBitrate = 0;
- final int fps = 30;
- final int audioCodecType = -1;
- final int audioSamplingFrequency = 0;
- final int audioChannel = 0;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileBaseline;
- final int videoLevel = MediaProperties.H264Level.H264Level13;
- final int width = 1080;
- final int height = MediaProperties.HEIGHT_720;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mvi = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", videoItemFilename, renderingMode);
-
- validateVideoProperties(aspectRatio, fileType, videoCodecType, duration,
- videoBitrate, fps, videoProfile, videoLevel, width, height, audioCodecType,
- audioSamplingFrequency, audioChannel, audioBitrate, mvi);
- }
-
- /**
- *To test Media Properties for Image file of JPEG Type
- */
- @LargeTest
- public void testPropertiesVGAImage() throws Exception {
- final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int imageItemDuration = 10000;
- final int aspectRatio = MediaProperties.ASPECT_RATIO_4_3;
- final int fileType = MediaProperties.FILE_JPEG;
- final int width = 640;
- final int height = MediaProperties.HEIGHT_480;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaImageItem mii = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", imageItemFilename, imageItemDuration,
- renderingMode);
- validateImageProperties(aspectRatio, fileType, width, height, mii);
- }
-
- /**
- *To test Media Properties for Image file of PNG Type
- */
- @LargeTest
- public void testPropertiesPNG() throws Exception {
- final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.png";
- final int imageItemDuration = 10000;
- final int aspectRatio = MediaProperties.ASPECT_RATIO_4_3;
- final int fileType = MediaProperties.FILE_PNG;
- final int width = 640;
- final int height = 480;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaImageItem mii = mVideoEditorHelper.createMediaItem
- (mVideoEditor, "m1", imageItemFilename, imageItemDuration,
- renderingMode);
- validateImageProperties(aspectRatio, fileType, width, height, mii);
- }
-
- /**
- *To test Media Properties for file GIF - Unsupported type
- */
- @LargeTest
- public void testPropertiesGIFFile() throws Exception {
-
- final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.gif";
- final int imageItemDuration = 10000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- try {
- new MediaImageItem(mVideoEditor, "m1", imageItemFilename,
- imageItemDuration, renderingMode);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Media Properties for a GIF File -- Unsupported file type",
- flagForException);
- }
-
- /**
- *To test Media Properties for file Text file named as 3GP
- */
- @LargeTest
- public void testPropertiesofDirtyFile() throws Exception {
-
- final String videoItemFilename = INPUT_FILE_PATH +
- "Text_FileRenamedTo3gp.3gp";
- boolean flagForException = false;
-
- try {
- new MediaVideoItem(mVideoEditor, "m1", videoItemFilename,
- MediaItem.RENDERING_MODE_BLACK_BORDER);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Media Properties for a Dirty File ",
- flagForException);
- }
-
- /**
- *To test Media Properties for file name as NULL
- */
- @LargeTest
- public void testPropertieNULLFile() throws Exception {
- final String videoItemFilename = null;
- boolean flagForException = false;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- try {
- new MediaVideoItem(mVideoEditor, "m1", videoItemFilename,
- renderingMode);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Media Properties for NULL File ",
- flagForException);
- }
-
- /**
- *To test Media Properties for file which is of type MPEG2
- */
- @LargeTest
- public void testPropertiesMPEG2File() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "MPEG2_640x480_30fps_192kbps_1_5.mp4";
- boolean flagForException = false;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- try {
- new MediaVideoItem(mVideoEditor, "m1", videoItemFilename,
- renderingMode);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Media Properties for a MPEG2 File --Unsupported file type",
- flagForException);
- }
-
- /**
- *To test Media Properties for file without Video only Audio
- */
- @LargeTest
- public void testProperties3GPWithoutVideoMediaItem() throws Exception {
- final String audioFilename = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- boolean flagForException = false;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- try {
- new MediaVideoItem(mVideoEditor, "m1", audioFilename,
- renderingMode);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Exception in Creaing Media Video item object without video",
- flagForException);
- }
-
- /**
- *To test media properties for Audio Track file. (No Video, AAC Audio)
- */
- @LargeTest
- public void testProperties3GPWithoutVideoAudioTrack() throws Exception {
-
- final String audioFilename = INPUT_FILE_PATH +
- "AACLC_44.1kHz_256kbps_s_1_17.mp4";
- final int duration = 77554;
- final int audioBitrate = 384000;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 44100;
- final int audioChannel = 2;
-
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio
- (mVideoEditor, "a1", audioFilename);
-
- validateAudioProperties(audioCodecType, duration, audioSamplingFrequency,
- audioChannel, audioBitrate, audioTrack);
- }
-
- /**
- *To test media properties for Audio Track file. MP3 file
- */
- @LargeTest
- public void testPropertiesMP3AudioTrack() throws Exception {
-
- final String audioFilename = INPUT_FILE_PATH +
- "MP3_48KHz_128kbps_s_1_17.mp3";
- final int duration = 77640;
- final int audioBitrate = 128000;
- final int audioCodecType = MediaProperties.ACODEC_MP3;
- final int audioSamplingFrequency = 48000;
- final int audioChannel = 2;
-
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio
- (mVideoEditor, "a1", audioFilename);
-
- validateAudioProperties(audioCodecType, duration, audioSamplingFrequency,
- audioChannel, audioBitrate, audioTrack);
- }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorAPITest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorAPITest.java
deleted file mode 100644
index 6e520c3..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorAPITest.java
+++ /dev/null
@@ -1,2751 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.functional.videoeditor;
-
-import java.io.File;
-import java.util.List;
-
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.media.videoeditor.AudioTrack;
-import android.media.videoeditor.EffectColor;
-import android.media.videoeditor.EffectKenBurns;
-import android.media.videoeditor.ExtractAudioWaveformProgressListener;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.videoeditor.MediaProperties;
-import android.media.videoeditor.MediaVideoItem;
-import android.media.videoeditor.OverlayFrame;
-import android.media.videoeditor.Transition;
-import android.media.videoeditor.TransitionAlpha;
-import android.media.videoeditor.TransitionCrossfade;
-import android.media.videoeditor.TransitionFadeBlack;
-import android.media.videoeditor.TransitionSliding;
-import android.media.videoeditor.VideoEditor;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase;
-import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
-
-import android.util.Log;
-import java.lang.annotation.Annotation;
-
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.mediaframeworktest.VideoEditorHelper;
-
-public class VideoEditorAPITest extends
- ActivityInstrumentationTestCase<MediaFrameworkTest> {
- private final String TAG = "VideoEditorTest";
-
- private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
-
- private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
-
- private final String PROJECT_CLASS_NAME =
- "android.media.videoeditor.VideoEditorImpl";
- private VideoEditor mVideoEditor;
- private VideoEditorHelper mVideoEditorHelper;
-
- public VideoEditorAPITest() {
- super("com.android.mediaframeworktest", MediaFrameworkTest.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- // setup for each test case.
- super.setUp();
- mVideoEditorHelper = new VideoEditorHelper();
- // Create a random String which will be used as project path, where all
- // project related files will be stored.
- final String projectPath = mVideoEditorHelper.
- createRandomFile(PROJECT_LOCATION);
- mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
- // Clean the directory created as project path
- mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
- System.gc();
- super.tearDown();
- }
-
- /**
- * To Test Creation of Media Video Item.
- */
- @LargeTest
- public void testMediaVideoItem() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final int videoItemRenderingMode =
- MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
-
- assertTrue("Media Video ID",
- mediaVideoItem1.getId().equals("mediaVideoItem1"));
- assertTrue("Media Video Filename",
- mediaVideoItem1.getFilename().equals(videoItemFileName));
- assertEquals("Media Video Rendering Mode",
- videoItemRenderingMode, mediaVideoItem1.getRenderingMode());
- assertEquals("Media Video Item Duration", mediaVideoItem1.getDuration(),
- mediaVideoItem1.getTimelineDuration());
- assertEquals("Media Video Overlay", 0,
- mediaVideoItem1.getAllOverlays().size());
- assertEquals("Media Video Effect", 0,
- mediaVideoItem1.getAllEffects().size());
- assertNull("Media Video Begin transition",
- mediaVideoItem1.getBeginTransition());
- assertNull("Media Video End transition",
- mediaVideoItem1.getEndTransition());
- mediaVideoItem1.setExtractBoundaries(1000,11000);
- boolean flagForException = false;
- if (mediaVideoItem1.getDuration() !=
- mediaVideoItem1.getTimelineDuration()) {
- flagForException = true;
- }
- assertTrue("Media Video Item Duration & Timeline are same",
- flagForException );
- }
-
- /**
- * To test creation of Media Video Item with Set Extract Boundaries With Get
- * the Begin and End Time.
- */
- @LargeTest
- public void testMediaVideoItemExtractBoundaries() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final int videoItemRenderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- mediaVideoItem1.setExtractBoundaries(1000, 11000);
- assertEquals("Media Item Duration = StoryBoard Duration",
- mediaVideoItem1.getTimelineDuration(), mVideoEditor.getDuration());
- try {
- mediaVideoItem1.setExtractBoundaries(0, 100000000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Set Extract with Invalid Values endTime > FileDuration",
- flagForException);
-
- flagForException = false;
- try {
- mediaVideoItem1.setExtractBoundaries(100000000, 11000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Set Extract with Invalid Values startTime > endTime",
- flagForException);
-
- flagForException = false;
- try {
- mediaVideoItem1.setExtractBoundaries(0, 0);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Set Extract with Invalid Values startTime = endTime",
- flagForException);
-
- mediaVideoItem1.setExtractBoundaries(1000, 10000);
- assertTrue("Media Item Duration is still the same",
- (mediaVideoItem1.getTimelineDuration() ==
- (mediaVideoItem1.getBoundaryEndTime()-
- mediaVideoItem1.getBoundaryBeginTime())) ? true : false);
-
- mediaVideoItem1.setExtractBoundaries(1,mediaVideoItem1.getDuration()-1);
- assertEquals("Media Item Start Time", 1,
- mediaVideoItem1.getBoundaryBeginTime());
- assertEquals("Media Item End Time", (mediaVideoItem1.getDuration() - 1),
- mediaVideoItem1.getBoundaryEndTime());
-
- mediaVideoItem1.setExtractBoundaries(1, mediaVideoItem1.getDuration());
- assertEquals("Media Item Duration = StoryBoard Duration",
- mediaVideoItem1.getTimelineDuration(), mVideoEditor.getDuration());
-
- mediaVideoItem1.setExtractBoundaries(0,mediaVideoItem1.getDuration()/2);
- assertEquals("Media Item Duration = StoryBoard Duration",
- mediaVideoItem1.getTimelineDuration(), mVideoEditor.getDuration());
-
- mediaVideoItem1.setExtractBoundaries(0, -1);
- assertEquals("Media Item Duration = StoryBoard Duration",
- mediaVideoItem1.getTimelineDuration(), mVideoEditor.getDuration());
- }
-
- /**
- * To test creation of Media Video Item with Set and Get rendering Mode
- */
- @LargeTest
- public void testMediaVideoItemRenderingModes() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final int videoItemRenderingMode= MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
- mediaVideoItem1.setRenderingMode(MediaItem.RENDERING_MODE_CROPPING);
- assertEquals("MediaVideo Item rendering Mode",
- MediaItem.RENDERING_MODE_CROPPING,
- mediaVideoItem1.getRenderingMode());
- try {
- mediaVideoItem1.setRenderingMode(
- MediaItem.RENDERING_MODE_CROPPING + 911);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Media Item Invalid rendering Mode", flagForException);
- flagForException = false;
- try {
- mediaVideoItem1.setRenderingMode(
- MediaItem.RENDERING_MODE_BLACK_BORDER - 11);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Media Item Invalid rendering Mode", flagForException);
- assertEquals("MediaVideo Item rendering Mode",
- MediaItem.RENDERING_MODE_CROPPING,
- mediaVideoItem1.getRenderingMode());
- mediaVideoItem1.setRenderingMode(MediaItem.RENDERING_MODE_STRETCH);
- assertEquals("MediaVideo Item rendering Mode",
- MediaItem.RENDERING_MODE_STRETCH,
- mediaVideoItem1.getRenderingMode());
- }
-
-
- /**
- * To Test the Media Video API : Set Audio Volume, Get Audio Volume and Mute
- */
- @LargeTest
- public void testMediaVideoItemAudioFeatures() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final int videoItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
- mediaVideoItem1.setVolume(77);
- assertEquals("Updated Volume is 77", 77, mediaVideoItem1.getVolume());
-
- mediaVideoItem1.setMute(true);
- assertTrue("Audio must be Muted", mediaVideoItem1.isMuted());
-
- mediaVideoItem1.setVolume(78);
- assertEquals("Updated Volume is 78", 78, mediaVideoItem1.getVolume());
- assertTrue("Audio must be Muted", mediaVideoItem1.isMuted());
-
- try {
- mediaVideoItem1.setVolume(1000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Invalid Set Volume", flagForException);
-
- mediaVideoItem1.setMute(false);
- assertFalse("Audio must be Un-Muted", mediaVideoItem1.isMuted());
-
- mediaVideoItem1.setVolume(0);
- assertFalse("Audio must be Un-Muted", mediaVideoItem1.isMuted());
-
- flagForException = false;
- try {
- mediaVideoItem1.setVolume(-1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Invalid Set Volume", flagForException);
-
- mediaVideoItem1.setVolume(100);
- assertEquals("MediaItem Volume", 100, mediaVideoItem1.getVolume());
- try {
- mediaVideoItem1.setVolume(101);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Invalid Set Volume", flagForException);
- assertEquals("MediaItem Volume", 100, mediaVideoItem1.getVolume());
- }
-
- /**
- * To Test the Media Video API : GetWaveFormData and
- * extractAudioWaveFormData
- */
-
- @LargeTest
- public void testMediaVideoItemGetWaveformData() throws Exception {
-
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final int videoItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- assertNull("WaveForm data", mediaVideoItem1.getWaveformData());
- final int[] progressWaveform = new int[105];
-
- mediaVideoItem1.extractAudioWaveform(new
- ExtractAudioWaveformProgressListener() {
- int i = 0;
- public void onProgress(int progress) {
- Log.i("WaveformData","progress=" +progress);
- progressWaveform[i++] = progress;
- }
- });
- assertTrue("Progress of WaveForm data", mVideoEditorHelper
- .checkProgressCBValues(progressWaveform));
- assertNotNull("WaveForm data", mediaVideoItem1.getWaveformData());
- assertTrue("WaveForm Frame Duration",
- (mediaVideoItem1.getWaveformData().getFrameDuration() > 0?
- true : false));
- assertTrue("WaveForm Frame Count",
- (mediaVideoItem1.getWaveformData().getFramesCount() > 0 ?
- true : false));
- assertTrue("WaveForm Gain",
- (mediaVideoItem1.getWaveformData().getFrameGains().length > 0 ?
- true : false));
-
- }
-
- /**
- * To Test the Media Video API : Get Effect, GetAllEffects, remove Effect
- */
-
- @LargeTest
- public void testMediaVideoItemEffect() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final int videoItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem1 = mVideoEditorHelper.
- createMediaItem(mVideoEditor, "mediaVideoItem1", videoItemFileName,
- videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- assertTrue("Effect List Size",
- (mediaVideoItem1.getAllEffects().size() == 0) ? true : false);
- assertNull("Effect Item by ID", mediaVideoItem1.getEffect("xyx"));
-
- final EffectColor effectColor = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "Effecton MVi1", 0, 4000, EffectColor.TYPE_GRADIENT,
- EffectColor.GRAY);
- mediaVideoItem1.addEffect(effectColor);
-
- assertTrue("Effect List Size", (mediaVideoItem1.
- getAllEffects().size() == 1) ? true : false);
- assertEquals("Effect Item by Valid ID", effectColor,
- mediaVideoItem1.getEffect(effectColor.getId()));
- assertNull("Effect Item by Invalid ID",
- mediaVideoItem1.getEffect("xyz"));
- assertNull("Effect Item by Invalid ID",
- mediaVideoItem1.removeEffect("effectId"));
- assertTrue("Effect List Size",
- (mediaVideoItem1.getAllEffects().size() == 1) ? true : false);
- assertEquals("Effect Removed", effectColor,
- mediaVideoItem1.removeEffect(effectColor.getId()));
- assertTrue("Effect List Size",
- (mediaVideoItem1.getAllEffects().size() == 0) ? true : false);
- assertNull("Effect Item by ID", mediaVideoItem1.getEffect("effectId"));
- }
-
- /**
- * To Test the Media Video API : Get Before and after transition
- */
-
- @LargeTest
- public void testMediaVideoItemTransitions() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final int videoItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
- assertNull("Begin Transition", mediaVideoItem1.getBeginTransition());
- assertNull("End Transition", mediaVideoItem1.getEndTransition());
-
- TransitionFadeBlack transition1 =
- mVideoEditorHelper.createTFadeBlack("transition1", mediaVideoItem1,
- null, 0, Transition.BEHAVIOR_SPEED_UP);
- mVideoEditor.addTransition(transition1);
- assertEquals("Begin transition", transition1,
- mediaVideoItem1.getEndTransition());
-
- assertNotNull("End Transition", mediaVideoItem1.getEndTransition());
- assertTrue(mediaVideoItem1.
- getEndTransition().getId().equals(transition1.getId()));
- assertTrue(mediaVideoItem1.getEndTransition().getDuration() ==
- transition1.getDuration() ? true : false);
- assertTrue(mediaVideoItem1.getEndTransition().getBehavior() ==
- transition1.getBehavior() ? true : false);
-
- TransitionFadeBlack transition2 = mVideoEditorHelper.createTFadeBlack(
- "transition2", null,mediaVideoItem1, 0, Transition.BEHAVIOR_LINEAR);
- mVideoEditor.addTransition(transition2);
- assertNotNull("Begin transition", mediaVideoItem1.getBeginTransition());
- assertEquals("End Transition", transition2,
- mediaVideoItem1.getBeginTransition());
- assertTrue(mediaVideoItem1.
- getBeginTransition().getId().equals(transition2.getId()));
- assertTrue(mediaVideoItem1. getBeginTransition().getDuration() ==
- transition2.getDuration() ? true : false);
- assertTrue(mediaVideoItem1.getBeginTransition().getBehavior() ==
- transition2.getBehavior() ? true : false);
- }
-
- /**
- * To Test the Media Video API : Get All Overlay, Get Overlay and remove Overlay
- *
- */
-
- @LargeTest
- public void testMediaVideoItemOverlays() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final String overlayItemFileName = INPUT_FILE_PATH +
- "IMG_176x144_Overlay1.png";
- final int videoItemRenderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- assertTrue("Overlay List Size",
- (mediaVideoItem1.getAllOverlays().size() == 0) ? true : false);
- assertNull("Overlay Item by ID", mediaVideoItem1.getOverlay("xyz"));
-
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayItemFileName,
- 176, 144);
- final OverlayFrame overlayFrame = mVideoEditorHelper.createOverlay(
- mediaVideoItem1, "overlayId", mBitmap, 5000, 5000);
- mediaVideoItem1.addOverlay(overlayFrame);
-
- assertTrue("Overlay List Size",
- (mediaVideoItem1.getAllOverlays().size() == 1) ? true : false);
- assertEquals("Overlay Item by Valid ID", overlayFrame, mediaVideoItem1
- .getOverlay(overlayFrame.getId()));
- assertNull("Overlay Item by Invalid ID",
- mediaVideoItem1.getOverlay("xyz"));
- assertNull("Overlay Item by Invalid ID",
- mediaVideoItem1.removeOverlay("xyz"));
- assertTrue("Overlay List Size",
- (mediaVideoItem1.getAllOverlays().size() == 1) ? true : false);
- assertEquals("Overlay Removed", overlayFrame,
- mediaVideoItem1.removeOverlay(overlayFrame.getId()));
- assertTrue("Overlay List Size",
- (mediaVideoItem1.getAllOverlays().size() == 0) ? true : false);
- assertNull("Overlay Item by ID",mediaVideoItem1.getOverlay("effectId"));
- }
-
- /**
- * To Test Creation of Media Image Item.
- */
- @LargeTest
- public void testMediaImageItem() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, 5000, imageItemRenderingMode);
- assertTrue("Media Image ID",
- mediaImageItem1.getId().equals("mediaImageItem1"));
- assertTrue("Media IMage Filename",
- mediaImageItem1.getFilename().equals(imageItemFileName));
- assertEquals("Media Image Rendering Mode",
- imageItemRenderingMode, mediaImageItem1.getRenderingMode());
- assertEquals("Media Image Item Duration", mediaImageItem1.getDuration(),
- mediaImageItem1.getTimelineDuration());
- assertEquals("Media Image Overlay", 0,
- mediaImageItem1.getAllOverlays().size());
- assertEquals("Media Image Effect", 0,
- mediaImageItem1.getAllEffects().size());
- assertNull("Media Image Begin transition",
- mediaImageItem1.getBeginTransition());
- assertNull("Media Image End transition",
- mediaImageItem1.getEndTransition());
- assertEquals("Media Image Scaled Height", MediaProperties.HEIGHT_720,
- mediaImageItem1.getScaledHeight());
- assertEquals("Media Image Scaled Width", 960,
- mediaImageItem1.getScaledWidth());
- assertEquals("Media Image Aspect Ratio", MediaProperties.ASPECT_RATIO_4_3,
- mediaImageItem1.getAspectRatio());
- assertNotNull("Media Image Thumbnail",
- mediaImageItem1.getThumbnail(960, MediaProperties.HEIGHT_720, 2000));
- }
-
- /**
- * To Test the Media Image API : Get and Set rendering Mode
- */
- @LargeTest
- public void testMediaImageItemRenderingModes() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final int imageItemRenderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, imageItemRenderingMode, 5000);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- mediaImageItem1.setRenderingMode(MediaItem.RENDERING_MODE_CROPPING);
- assertEquals("MediaVideo Item rendering Mode",
- MediaItem.RENDERING_MODE_CROPPING, mediaImageItem1.getRenderingMode());
- try {
- mediaImageItem1.setRenderingMode(
- MediaItem.RENDERING_MODE_CROPPING + 911);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Media Item Invalid rendering Mode", flagForException);
-
- flagForException = false;
- try {
- mediaImageItem1.setRenderingMode(
- MediaItem.RENDERING_MODE_BLACK_BORDER - 11);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Media Item Invalid rendering Mode", flagForException);
-
- assertEquals("MediaVideo Item rendering Mode",
- MediaItem.RENDERING_MODE_CROPPING,
- mediaImageItem1.getRenderingMode());
- mediaImageItem1.setRenderingMode(MediaItem.RENDERING_MODE_STRETCH);
- assertEquals("MediaVideo Item rendering Mode",
- MediaItem.RENDERING_MODE_STRETCH,
- mediaImageItem1.getRenderingMode());
- }
-
- /**
- * To Test the Media Image API : GetHeight and GetWidth
- */
- @LargeTest
- public void testMediaImageItemHeightWidth() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, imageItemRenderingMode, 5000);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- assertEquals("Image Height = Image Scaled Height",
- mediaImageItem1.getScaledHeight(), mediaImageItem1.getHeight());
- assertEquals("Image Width = Image Scaled Width",
- mediaImageItem1.getScaledWidth(), mediaImageItem1.getWidth());
- }
-
-
-
-/** This Test Case can be removed as this is already checked in TC 010 */
- /**
- * To Test the Media Image API : Scaled Height and Scaled GetWidth
- */
- @LargeTest
- public void testMediaImageItemScaledHeightWidth() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, imageItemRenderingMode, 5000);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- assertNotSame("Image Height = Image Scaled Height",
- mediaImageItem1.getScaledHeight(), mediaImageItem1.getHeight());
- assertNotSame("Image Width = Image Scaled Width",
- mediaImageItem1.getScaledWidth(), mediaImageItem1.getWidth());
- }
-
- /**
- * To Test the Media Image API : Get Effect, GetAllEffects, remove Effect
- */
-
- @LargeTest
- public void testMediaImageItemEffect() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, 5000, imageItemRenderingMode);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- assertTrue("Effect List Size",
- (mediaImageItem1.getAllEffects().size() == 0) ? true : false);
- assertNull("Effect Item by ID", mediaImageItem1.getEffect("xyx"));
-
- final EffectColor effectColor =
- mVideoEditorHelper.createEffectItem(mediaImageItem1,
- "Effecton MVi1", 0, 4000, EffectColor.TYPE_GRADIENT, EffectColor.GRAY);
- mediaImageItem1.addEffect(effectColor);
-
- assertTrue("Effect List Size",
- (mediaImageItem1.getAllEffects().size() == 1) ? true : false);
- assertEquals("Effect Item by Valid ID",
- effectColor, mediaImageItem1.getEffect(effectColor.getId()));
- assertNull("Effect Item by Invalid ID",
- mediaImageItem1.getEffect("xyz"));
- assertNull("Effect Item by Invalid ID",
- mediaImageItem1.removeEffect("effectId"));
- assertTrue("Effect List Size",
- (mediaImageItem1.getAllEffects().size() == 1) ? true : false);
- assertEquals("Effect Removed", effectColor,
- mediaImageItem1.removeEffect(effectColor.getId()));
- assertTrue("Effect List Size",
- (mediaImageItem1.getAllEffects().size() == 0) ? true : false);
- assertNull("Effect Item by ID", mediaImageItem1.getEffect("effectId"));
- }
-
- /**
- * To Test the Media Image API : Get Before and after transition
- */
-
- @LargeTest
- public void testMediaImageItemTransitions() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, 5000, imageItemRenderingMode);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- assertNull("Begin Transition", mediaImageItem1.getBeginTransition());
- assertNull("End Transition", mediaImageItem1.getEndTransition());
-
- TransitionFadeBlack transition1 =
- mVideoEditorHelper.createTFadeBlack("transition1", mediaImageItem1,
- null, 0, Transition.BEHAVIOR_SPEED_UP);
- mVideoEditor.addTransition(transition1);
-
- assertEquals("Begin transition", transition1,
- mediaImageItem1.getEndTransition());
- assertNotNull("End Transition", mediaImageItem1.getEndTransition());
- assertTrue(mediaImageItem1.getEndTransition().getId().equals
- (transition1.getId()));
- assertTrue(mediaImageItem1.getEndTransition().getDuration() ==
- transition1.getDuration() ? true : false);
- assertTrue(mediaImageItem1.getEndTransition().getBehavior() ==
- transition1.getBehavior() ? true : false);
-
- TransitionFadeBlack transition2 = mVideoEditorHelper.createTFadeBlack(
- "transition2",null, mediaImageItem1, 0, Transition.BEHAVIOR_SPEED_UP);
- mVideoEditor.addTransition(transition2);
-
- assertNotNull("Begin transition", mediaImageItem1.getBeginTransition());
- assertEquals("End Transition", transition2,
- mediaImageItem1.getBeginTransition());
- assertTrue(mediaImageItem1.getBeginTransition().getId().equals(
- transition2.getId()));
- assertTrue(mediaImageItem1.getBeginTransition().getDuration() ==
- transition2.getDuration() ? true : false);
- assertTrue(mediaImageItem1.getBeginTransition().getBehavior() ==
- transition2.getBehavior() ? true : false);
- }
-
- /**
- * To Test the Media Image API : Get All Overlay, Get Overlay and remove
- * Overlay
- */
-
- @LargeTest
- public void testMediaImageItemOverlays() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String overlayItemFileName = INPUT_FILE_PATH +
- "IMG_640x480_Overlay1.png";
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, 12000, imageItemRenderingMode);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- assertTrue("Overlay List Size",
- (mediaImageItem1.getAllOverlays().size() == 0) ? true : false);
- assertNull("Overlay Item by ID", mediaImageItem1.getOverlay("xyz"));
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayItemFileName,
- 640, 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaImageItem1, "overlayId",
- mBitmap, 5000, 5000);
- mediaImageItem1.addOverlay(overlayFrame);
-
- assertTrue("Overlay List Size",
- (mediaImageItem1.getAllOverlays().size() == 1) ? true : false);
- assertEquals("Overlay Item by Valid ID", overlayFrame, mediaImageItem1
- .getOverlay(overlayFrame.getId()));
- assertNull("Overlay Item by Invalid ID",
- mediaImageItem1.getOverlay("xyz"));
- assertNull("Remove Overlay Item by Invalid ID",
- mediaImageItem1.removeOverlay("xyz"));
- assertTrue("Overlay List Size",
- (mediaImageItem1.getAllOverlays().size() == 1) ? true : false);
- assertEquals("Overlay Removed",
- overlayFrame, mediaImageItem1.removeOverlay(overlayFrame.getId()));
- assertTrue("Overlay List Size",
- (mediaImageItem1.getAllOverlays().size() == 0) ? true : false);
- assertNull("Overlay Item by ID",
- mediaImageItem1.getOverlay("effectId"));
- }
-
- /**
- * To test creation of Audio Track
- */
-
- @LargeTest
- public void testAudioTrack() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- mVideoEditor.addAudioTrack(audioTrack);
-
- assertEquals("Audio Track Item Duration", audioTrack.getDuration(),
- audioTrack.getTimelineDuration());
- assertEquals("Audio Track Start Time", 0, audioTrack.getStartTime());
- assertFalse("Audio Track is Looping", audioTrack.isLooping());
- audioTrack.getVolume();
- assertFalse("Audio Track Ducking is Disabled",
- audioTrack.isDuckingEnabled());
- assertTrue("Audio Track Filename",
- audioTrack.getFilename().equals(audioFileName));
- assertEquals("Audio Ducking Threshold", 0,
- audioTrack.getDuckingThreshhold());
- assertFalse("Audio Track Mute", audioTrack.isMuted());
- audioTrack.getDuckedTrackVolume();
- }
-
- /**
- * To test creation of Audio Track with set extract boundaries
- */
- @LargeTest
- public void testAudioTrackExtractBoundaries() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- boolean flagForException = false;
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- mVideoEditor.addAudioTrack(audioTrack);
-
- audioTrack.setExtractBoundaries(1000, 5000);
- assertEquals("Audio Track Start time", 1000,
- audioTrack.getBoundaryBeginTime());
- assertEquals("Audio Track End time", 5000,
- audioTrack.getBoundaryEndTime());
- try {
- audioTrack.setExtractBoundaries(0, 100000000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Audio Track With endTime > FileDuration", flagForException);
- flagForException = false;
- try {
- audioTrack.setExtractBoundaries(100000000, 5000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Audio Track With startTime > FileDuration",
- flagForException);
- flagForException = false;
- try {
- audioTrack.setExtractBoundaries(0, 0);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- /* This is under discussion. Hence, checked for False */
- assertFalse("Audio Track With startTime = endTime", flagForException);
- assertEquals("Audio Track Start time", 0,
- audioTrack.getBoundaryBeginTime());
- assertEquals("Audio Track End time", 0,
- audioTrack.getBoundaryEndTime());
- assertEquals("Audio Track Start time",0,
- audioTrack.getBoundaryBeginTime());
- assertEquals("Audio Track End time", (audioTrack.getTimelineDuration()),
- audioTrack.getBoundaryEndTime());
- audioTrack.setExtractBoundaries(0, audioTrack.getDuration() / 2);
- assertEquals("Audio Track Start time",0,
- audioTrack.getBoundaryBeginTime());
- assertEquals("Audio Track End time", (audioTrack.getDuration() / 2),
- audioTrack.getBoundaryEndTime());
- audioTrack.setExtractBoundaries(1, audioTrack.getDuration() - 1);
- assertEquals("Audio Track Start time", 1,
- audioTrack.getBoundaryBeginTime());
- assertEquals("Audio Track End time", (audioTrack.getDuration() - 1),
- audioTrack.getBoundaryEndTime());
-
- flagForException = false;
- try {
- audioTrack.setExtractBoundaries(0, -1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue ("Audio Track end time < 0",flagForException);
- }
-
- /**
- * To test creation of Audio Track with set Start Time and Get Time
- */
- @LargeTest
- public void testAudioTrackSetGetTime() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- boolean flagForException = false;
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- mVideoEditor.addAudioTrack(audioTrack);
- /** set StartTime API is removed and start time is always 0 */
- assertEquals("Audio Track Start Time", 0, audioTrack.getStartTime());
- }
-
- /**
- * To Test the Audio Track API: Enable Ducking
- */
- @LargeTest
- public void testAudioTrackEnableDucking() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- boolean flagForException = false;
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- mVideoEditor.addAudioTrack(audioTrack);
-
- assertFalse("Audio Ducking Disabled by default",
- audioTrack.isDuckingEnabled());
- audioTrack.enableDucking(45, 70);
- assertTrue("Audio Ducking Enabled", audioTrack.isDuckingEnabled());
- assertEquals("Audio Ducking Threshold", 45,
- audioTrack.getDuckingThreshhold());
- assertEquals("Audio Ducking Volume", 70,
- audioTrack.getDuckedTrackVolume());
- audioTrack.enableDucking(85, 70);
- assertEquals("Audio Ducking Threshold", 85,
- audioTrack.getDuckingThreshhold());
- assertEquals("Audio Ducking Volume", 70,
- audioTrack.getDuckedTrackVolume());
- try {
- audioTrack.enableDucking(91, 70);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Enable ducking threshold > 90", flagForException);
- flagForException = false;
- try {
- audioTrack.enableDucking(90, 101);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Enable ducking volume > 100", flagForException);
- flagForException = false;
- try {
- audioTrack.enableDucking(91, 101);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Enable ducking volume > 100 and threshold > 91",
- flagForException);
- flagForException = false;
- try {
- audioTrack.enableDucking(-1, 100);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Enable ducking threshold < 0", flagForException);
- flagForException = false;
- try {
- audioTrack.enableDucking(1, -1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Enable ducking lowVolume < 0", flagForException);
- flagForException = false;
- try {
- audioTrack.enableDucking(0, 50);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertFalse("Enable ducking threshold = 0", flagForException);
- }
-
- /**
- * To Test the Audio Track API: Looping
- */
- @LargeTest
- public void testAudioTrackLooping() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- mVideoEditor.addAudioTrack(audioTrack);
- assertFalse("Audio Looping", audioTrack.isLooping());
- audioTrack.enableLoop();
- assertTrue("Audio Looping", audioTrack.isLooping());
- audioTrack.disableLoop();
- assertFalse("Audio Looping", audioTrack.isLooping());
- }
-
- /**
- * To Test the Audio Track API:Extract waveform data
- */
-
- @LargeTest
- public void testAudioTrackWaveFormData() throws Exception {
- /** Image item is added as dummy as Audio track cannot be added without
- * a media item in the story board
- */
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, 5000, imageItemRenderingMode);
- mVideoEditor.addMediaItem(mediaImageItem);
-
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
-
- mVideoEditor.addAudioTrack(audioTrack);
- assertNull("WaveForm data", audioTrack.getWaveformData());
-
- final int[] progressUpdate = new int[105];
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- int i = 0;
- public void onProgress(Object item, int action, int progress) {
- progressUpdate[i++] = progress;
- }
- });
-
- final int[] progressWaveform = new int[105];
-
- audioTrack.extractAudioWaveform(
- new ExtractAudioWaveformProgressListener() {
- int i = 0;
- public void onProgress(int progress) {
- Log.i("AudioWaveformData","progress=" +progress);
- progressWaveform[i++] = progress;
- }
- });
- assertTrue("Progress of WaveForm data", mVideoEditorHelper
- .checkProgressCBValues(progressWaveform));
- assertNotNull("WaveForm data", audioTrack.getWaveformData());
- assertTrue("WaveForm Frame Duration",
- (audioTrack.getWaveformData().getFrameDuration() > 0 ?
- true : false));
- assertTrue("WaveForm Frame Count",
- (audioTrack.getWaveformData().getFramesCount() > 0 ? true : false));
- assertTrue("WaveForm Gain",
- (audioTrack.getWaveformData().getFrameGains().length > 0 ?
- true : false));
- }
-
- /**
- * To Test the Audio Track API: Mute
- */
- @LargeTest
- public void testAudioTrackMute() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- assertFalse("Audio Track UnMute", audioTrack.isMuted());
- audioTrack.setMute(true);
- assertTrue("Audio Track Mute", audioTrack.isMuted());
- audioTrack.setMute(false);
- assertFalse("Audio Track UnMute", audioTrack.isMuted());
- }
-
- /**
- * To Test the Audio Track API: Get Volume and Set Volume
- */
- @LargeTest
- public void testAudioTrackGetSetVolume() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- boolean flagForException = false;
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- audioTrack.setVolume(0);
- assertEquals("Audio Volume", 0, audioTrack.getVolume());
- assertFalse("Audio Track UnMute", audioTrack.isMuted());
- audioTrack.setVolume(45);
- assertEquals("Audio Volume", 45, audioTrack.getVolume());
- assertFalse("Audio Track UnMute", audioTrack.isMuted());
- try {
- audioTrack.setVolume(-1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Volume = -1", flagForException);
- assertEquals("Audio Volume", 45, audioTrack.getVolume());
- flagForException = false;
- try {
- audioTrack.setVolume(101);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Volume = 101", flagForException);
- flagForException = false;
- try {
- audioTrack.setVolume(1000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Volume = 10000", flagForException);
- assertEquals("Audio Volume", 45, audioTrack.getVolume());
- }
-
- /**
- * To test Effect Color.
- */
- @LargeTest
- public void testAllEffects() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_30fps_512Kbps_0_27.mp4";
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final EffectColor effectColor1 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect1", 1000, 1000, EffectColor.TYPE_COLOR,
- EffectColor.PINK);
- mediaVideoItem1.addEffect(effectColor1);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor1.getMediaItem());
- assertTrue("Effect Id", effectColor1.getId().equals("effect1"));
- assertEquals("Effect StartTime", 1000, effectColor1.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor1.getDuration());
- assertEquals("Effect Type", EffectColor.TYPE_COLOR,
- effectColor1.getType());
- assertEquals("Effect Color", EffectColor.PINK, effectColor1.getColor());
-
- final EffectColor effectColor2 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect2", 2000, 1000, EffectColor.TYPE_COLOR,
- EffectColor.GRAY);
- mediaVideoItem1.addEffect(effectColor2);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor2.getMediaItem());
- assertTrue("Effect Id", effectColor2.getId().equals("effect2"));
- assertEquals("Effect StartTime", 2000, effectColor2.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor2.getDuration());
- assertEquals("Effect Type", EffectColor.TYPE_COLOR,
- effectColor2.getType());
- assertEquals("Effect Color", EffectColor.GRAY, effectColor2.getColor());
-
- final EffectColor effectColor3 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect3", 3000, 1000, EffectColor.TYPE_COLOR,
- EffectColor.GREEN);
- mediaVideoItem1.addEffect(effectColor3);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor3.getMediaItem());
- assertTrue("Effect Id", effectColor3.getId().equals("effect3"));
- assertEquals("Effect StartTime", 3000, effectColor3.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor3.getDuration());
- assertEquals("Effect Type", EffectColor.TYPE_COLOR,
- effectColor3.getType());
- assertEquals("Effect Color", EffectColor.GREEN, effectColor3.getColor());
-
- final EffectColor effectColor4 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect4", 4000, 1000, EffectColor.TYPE_GRADIENT,
- EffectColor.PINK);
- mediaVideoItem1.addEffect(effectColor4);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor4.getMediaItem());
- assertTrue("Effect Id", effectColor4.getId().equals("effect4"));
- assertEquals("Effect StartTime", 4000, effectColor4.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor4.getDuration());
- assertEquals("Effect Type", EffectColor.TYPE_GRADIENT,
- effectColor4.getType());
- assertEquals("Effect Color", EffectColor.PINK, effectColor4.getColor());
-
- final EffectColor effectColor5 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect5", 5000, 1000,
- EffectColor.TYPE_GRADIENT, EffectColor.GRAY);
- mediaVideoItem1.addEffect(effectColor5);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor5.getMediaItem());
- assertTrue("Effect Id", effectColor5.getId().equals("effect5"));
- assertEquals("Effect StartTime", 5000, effectColor5.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor5.getDuration());
- assertEquals("Effect Type", EffectColor.TYPE_GRADIENT,
- effectColor5.getType());
- assertEquals("Effect Color", EffectColor.GRAY, effectColor5.getColor());
-
- final EffectColor effectColor6 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect6", 6000, 1000,
- EffectColor.TYPE_GRADIENT, EffectColor.GREEN);
- mediaVideoItem1.addEffect(effectColor6);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor6.getMediaItem());
- assertTrue("Effect Id", effectColor6.getId().equals("effect6"));
- assertEquals("Effect StartTime", 6000, effectColor6.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor6.getDuration());
- assertEquals("Effect Type",
- EffectColor.TYPE_GRADIENT, effectColor6.getType());
- assertEquals("Effect Color",
- EffectColor.GREEN, effectColor6.getColor());
-
- final EffectColor effectColor7 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect7", 7000, 1000,
- EffectColor.TYPE_FIFTIES, 0);
- mediaVideoItem1.addEffect(effectColor7);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor7.getMediaItem());
- assertTrue("Effect Id", effectColor7.getId().equals("effect7"));
- assertEquals("Effect StartTime", 7000, effectColor7.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor7.getDuration());
- assertEquals("Effect Type", EffectColor.TYPE_FIFTIES,
- effectColor7.getType());
- assertEquals("Effect Color", -1, effectColor7.getColor());
-
- final EffectColor effectColor8 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect8", 8000, 1000, EffectColor.TYPE_SEPIA, 0);
- mediaVideoItem1.addEffect(effectColor8);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor8.getMediaItem());
- assertTrue("Effect Id", effectColor8.getId().equals("effect8"));
- assertEquals("Effect StartTime", 8000, effectColor8.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor8.getDuration());
- assertEquals("Effect Type", EffectColor.TYPE_SEPIA,
- effectColor8.getType());
- assertEquals("Effect Color", -1, effectColor8.getColor());
-
- final EffectColor effectColor9 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect9", 9000, 1000,
- EffectColor.TYPE_NEGATIVE, 0);
- mediaVideoItem1.addEffect(effectColor9);
-
- assertEquals("Associated Media Item", mediaVideoItem1,
- effectColor9.getMediaItem());
- assertTrue("Effect Id", effectColor9.getId().equals("effect9"));
- assertEquals("Effect StartTime", 9000, effectColor9.getStartTime());
- assertEquals("Effect EndTime", 1000, effectColor9.getDuration());
- assertEquals("Effect Type", EffectColor.TYPE_NEGATIVE,
- effectColor9.getType());
- assertEquals("Effect Color", -1, effectColor9.getColor());
- try {
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effect9",
- 9000, 1000, EffectColor.TYPE_COLOR - 1, 0);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect type Invalid", flagForException);
- flagForException = false;
- try {
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effect9",
- 9000, 1000, EffectColor.TYPE_FIFTIES + 1, 0);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect type Invalid", flagForException);
- try {
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effect10",
- 10000, 1000, EffectColor.TYPE_FIFTIES +
- EffectColor.TYPE_GRADIENT, 0);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect type Invalid", flagForException);
- }
-
- /**
- * To test Effect Color : Set duration and Get Duration
- */
- @LargeTest
- public void testEffectSetgetDuration() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_30fps_512Kbps_0_27.mp4";
- final int videoItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final EffectColor effectColor1 = mVideoEditorHelper.createEffectItem(
- mediaVideoItem1, "effect1", 1000, 2000,
- EffectColor.TYPE_COLOR, EffectColor.PINK);
- mediaVideoItem1.addEffect(effectColor1);
-
- effectColor1.setDuration(5000);
- assertEquals("Updated Effect Duration", 5000,
- effectColor1.getDuration());
- try {
- effectColor1.setDuration(mediaVideoItem1.getDuration() + 1000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect Color duration > mediaVideoItemDuration",
- flagForException);
- assertEquals("Effect Duration", 5000, effectColor1.getDuration());
- flagForException = false;
- try {
- effectColor1.setDuration(-1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect Color duration = -1", flagForException);
- }
-
- /**
- * To test Effect Color : UNDEFINED color param value
- */
- @LargeTest
- public void testEffectUndefinedColorParam() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_30fps_512Kbps_0_27.mp4";
- final int videoItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
- try{
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effect1", 1000,
- 2000, EffectColor.TYPE_COLOR, 0xabcdabcd);
- }catch (IllegalArgumentException e){
- flagForException = true;
- }
- assertTrue("Invalid Effect added",flagForException);
- }
-
- /**
- * To test Effect Color : with Invalid StartTime and Duration
- */
- @LargeTest
- public void testEffectInvalidStartTimeAndDuration() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_640x480_15fps_1200Kbps_AACLC_48KHz_32kbps_m_1_17.3gp";
- final int videoItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName, videoItemRenderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- try {
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effect1",
- 400000000, 2000, EffectColor.TYPE_COLOR, EffectColor.GREEN);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect with invalid StartTime", flagForException);
-
- flagForException = false;
- try {
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effect1", -1,
- 2000, EffectColor.TYPE_COLOR, EffectColor.GREEN);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect with invalid StartTime", flagForException);
-
- flagForException = false;
- try {
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effect1",
- 2000, -1, EffectColor.TYPE_COLOR, EffectColor.GREEN);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect with invalid Duration", flagForException);
- }
-
-
- /** Test cases 29, 30, 31, 32 and 33 are removed */
-
-
- /**
- * To test Effect : with NULL Media Item
- */
- @LargeTest
- public void testEffectNullMediaItem() throws Exception {
- boolean flagForException = false;
- try {
- mVideoEditorHelper.createEffectItem(null, "effect1", 1000, 4000,
- EffectColor.TYPE_COLOR, EffectColor.GREEN);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Effect with null MediaItem", flagForException);
- }
-
- /**
- * To test Effect : KenBurn Effect
- */
- @LargeTest
- public void testEffectKenBurn() throws Exception {
- // Test ken burn effect using a JPEG file.
- testEffectKenBurn(INPUT_FILE_PATH + "IMG_640x480.jpg",
- "mediaImageItem1");
-
- // Test ken burn effect using a PNG file
- testEffectKenBurn(INPUT_FILE_PATH + "IMG_640x480.png",
- "mediaImageItem2");
- }
-
- private void testEffectKenBurn(final String imageItemFileName,
- final String MediaId) throws Exception {
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, MediaId,
- imageItemFileName, 5000, imageItemRenderingMode);
- mVideoEditor.addMediaItem(mediaImageItem);
-
- final Rect startRect = new Rect((mediaImageItem.getHeight() / 3),
- (mediaImageItem.getWidth() / 3), (mediaImageItem.getHeight() / 2),
- (mediaImageItem.getWidth() / 2));
- final Rect endRect = new Rect(0, 0, mediaImageItem.getWidth(),
- mediaImageItem.getHeight());
-
- final EffectKenBurns kbEffectOnMediaItem = new EffectKenBurns(
- mediaImageItem, "KBOnM2", startRect, endRect, 500, 3000);
-
- assertNotNull("EffectKenBurns: " + imageItemFileName,
- kbEffectOnMediaItem);
-
- mediaImageItem.addEffect(kbEffectOnMediaItem);
- assertEquals("KenBurn Start Rect: " + imageItemFileName, startRect,
- kbEffectOnMediaItem.getStartRect());
-
- assertEquals("KenBurn End Rect: " + imageItemFileName, endRect,
- kbEffectOnMediaItem.getEndRect());
- }
-
- /**
- * To test KenBurnEffect : Set StartRect and EndRect
- */
-
- @LargeTest
- public void testEffectKenBurnSet() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int imageItemRenderingMode =MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, 5000, imageItemRenderingMode);
- mVideoEditor.addMediaItem(mediaImageItem);
-
- final Rect startRect = new Rect((mediaImageItem.getHeight() / 3),
- (mediaImageItem.getWidth() / 3), (mediaImageItem.getHeight() / 2),
- (mediaImageItem.getWidth() / 2));
- final Rect endRect = new Rect(0, 0, mediaImageItem.getWidth(),
- mediaImageItem.getHeight());
-
- EffectKenBurns kbEffectOnMediaItem=null;
- kbEffectOnMediaItem = new EffectKenBurns(mediaImageItem, "KBOnM2",
- startRect, endRect, 500, 3000);
-
- assertNotNull("EffectKenBurns", kbEffectOnMediaItem);
- mediaImageItem.addEffect(kbEffectOnMediaItem);
- assertEquals("KenBurn Start Rect", startRect,
- kbEffectOnMediaItem.getStartRect());
- assertEquals("KenBurn End Rect", endRect,
- kbEffectOnMediaItem.getEndRect());
-
- final Rect startRect1 = new Rect((mediaImageItem.getHeight() / 5),
- (mediaImageItem.getWidth() / 5), (mediaImageItem.getHeight() / 4),
- (mediaImageItem.getWidth() / 4));
- final Rect endRect1 = new Rect(10, 10, mediaImageItem.getWidth() / 4,
- mediaImageItem.getHeight() / 4);
-
- /* Added newly to take care of removal set APIs */
- kbEffectOnMediaItem = new EffectKenBurns(mediaImageItem, "KBOnM2_changed",
- startRect1, endRect1, 500, 3000);
-
- assertEquals("KenBurn Start Rect", startRect1,
- kbEffectOnMediaItem.getStartRect());
- assertEquals("KenBurn End Rect", endRect1,
- kbEffectOnMediaItem.getEndRect());
-
- final Rect zeroRect = new Rect(0, 0, 0, 0);
- try {
- kbEffectOnMediaItem = new EffectKenBurns(mediaImageItem, "KBOnM2_zeroStart",
- zeroRect, endRect, 500, 3000);
-
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Invalid Start Rect", flagForException);
-
- flagForException = false;
- try {
- kbEffectOnMediaItem = new EffectKenBurns(mediaImageItem, "KBOnM2_zeroEnd",
- startRect, zeroRect, 500, 3000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Invalid End Rect", flagForException);
- }
-
- /**
- * To test Transition : Fade To Black with all behavior
- * SPEED_UP/SPEED_DOWN/LINEAR/MIDDLE_SLOW/MIDDLE_FAST
- */
-
- @LargeTest
- public void testTransitionFadeBlack() throws Exception {
-
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String videoItemFilename2 = INPUT_FILE_PATH +
- "H263_profile0_176x144_15fps_128kbps_1_35.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String videoItemFilename3 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final String videoItemFilename4 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_256kbps_0_30.mp4";
- final String videoItemFilename5 = INPUT_FILE_PATH +
- "H263_profile0_176x144_10fps_96kbps_0_25.3gp";
- boolean flagForException = false;
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- videoItemFilename2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem2.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final TransitionFadeBlack transition1And2 = mVideoEditorHelper
- .createTFadeBlack("transition1And2", mediaVideoItem1,
- mediaVideoItem2, 3000, Transition.BEHAVIOR_SPEED_UP);
- mVideoEditor.addTransition(transition1And2);
-
- assertTrue("Transition ID",
- transition1And2.getId().equals("transition1And2"));
- assertEquals("Transtion After Media item",
- mediaVideoItem1, transition1And2.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem2,
- transition1And2.getBeforeMediaItem());
- assertEquals("Transtion Duration", 3000, transition1And2.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_SPEED_UP,
- transition1And2.getBehavior());
-
- final MediaImageItem mediaImageItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- imageItemFilename1, 15000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem3);
-
- final TransitionFadeBlack transition2And3 =
- mVideoEditorHelper.createTFadeBlack("transition2And3", mediaVideoItem2,
- mediaImageItem3, 1000, Transition.BEHAVIOR_SPEED_DOWN);
- mVideoEditor.addTransition(transition2And3);
-
- assertTrue("Transition ID",
- transition2And3.getId().equals("transition2And3"));
- assertEquals("Transtion After Media item", mediaVideoItem2,
- transition2And3.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaImageItem3,
- transition2And3.getBeforeMediaItem());
- assertEquals("Transtion Duration", 1000, transition2And3.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_SPEED_DOWN,
- transition2And3.getBehavior());
-
- final MediaVideoItem mediaVideoItem4 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- videoItemFilename3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem4.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaVideoItem4);
-
- final TransitionFadeBlack transition3And4 =
- mVideoEditorHelper.createTFadeBlack("transition3And4", mediaImageItem3,
- mediaVideoItem4, 5000, Transition.BEHAVIOR_LINEAR);
- mVideoEditor.addTransition(transition3And4);
-
- assertTrue("Transition ID",
- transition3And4.getId().equals("transition3And4"));
- assertEquals("Transtion After Media item", mediaImageItem3,
- transition3And4.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem4,
- transition3And4.getBeforeMediaItem());
- assertEquals("Transtion Duration", 5000, transition3And4.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_LINEAR,
- transition3And4.getBehavior());
-
- final MediaVideoItem mediaVideoItem5 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- videoItemFilename4, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem5);
-
- final TransitionFadeBlack transition4And5 =
- mVideoEditorHelper.createTFadeBlack("transition4And5", mediaVideoItem4,
- mediaVideoItem5, 8000, Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(transition4And5);
-
- assertTrue("Transition ID",
- transition4And5.getId().equals("transition4And5"));
- assertEquals("Transtion After Media item", mediaVideoItem4,
- transition4And5.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem5,
- transition4And5.getBeforeMediaItem());
- assertEquals("Transtion Duration", 8000, transition4And5.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_MIDDLE_FAST,
- transition4And5.getBehavior());
-
- final MediaVideoItem mediaVideoItem6 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m6",
- videoItemFilename5, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem6.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaVideoItem6);
-
- final TransitionFadeBlack transition5And6 =
- mVideoEditorHelper.createTFadeBlack("transition5And6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_SLOW);
- mVideoEditor.addTransition(transition5And6);
-
- assertTrue("Transition ID",
- transition5And6.getId().equals("transition5And6"));
- assertEquals("Transtion After Media item", mediaVideoItem5,
- transition5And6.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem6,
- transition5And6.getBeforeMediaItem());
- assertEquals("Transtion Duration", 2000, transition5And6.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_MIDDLE_SLOW,
- transition5And6.getBehavior());
- flagForException = false;
- try {
- mVideoEditorHelper.createTFadeBlack("transitiond6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_SPEED_UP - 1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition FadeBlack with Invalid behavior", flagForException);
- flagForException = false;
- try {
- mVideoEditorHelper.createTFadeBlack("transitiond6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_FAST + 1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition FadeBlack with Invalid behavior", flagForException);
- }
-
- /**
- * To test Transition : CrossFade with all behavior
- * SPEED_UP/SPEED_DOWN/LINEAR/MIDDLE_SLOW/MIDDLE_FAST
- */
-
- @LargeTest
- public void testTransitionCrossFade() throws Exception {
-
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String videoItemFilename2 = INPUT_FILE_PATH +
- "H263_profile0_176x144_15fps_128kbps_1_35.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String videoItemFilename3 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final String videoItemFilename4 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_256kbps_0_30.mp4";
- final String videoItemFilename5 = INPUT_FILE_PATH +
- "H263_profile0_176x144_10fps_96kbps_0_25.3gp";
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- videoItemFilename2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem2.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final TransitionCrossfade transition1And2 =
- mVideoEditorHelper.createTCrossFade("transition1And2", mediaVideoItem1,
- mediaVideoItem2, 3000, Transition.BEHAVIOR_SPEED_UP);
- mVideoEditor.addTransition(transition1And2);
-
- assertTrue("Transition ID",
- transition1And2.getId().equals("transition1And2"));
- assertEquals("Transtion After Media item", mediaVideoItem1,
- transition1And2.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem2,
- transition1And2.getBeforeMediaItem());
- assertEquals("Transtion Duration", 3000, transition1And2.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_SPEED_UP,
- transition1And2.getBehavior());
-
- final MediaImageItem mediaImageItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- imageItemFilename1, 15000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem3);
-
- final TransitionCrossfade transition2And3 =
- mVideoEditorHelper.createTCrossFade("transition2And3", mediaVideoItem2,
- mediaImageItem3, 1000, Transition.BEHAVIOR_SPEED_DOWN);
- mVideoEditor.addTransition(transition2And3);
-
- assertTrue("Transition ID",
- transition2And3.getId().equals("transition2And3"));
- assertEquals("Transtion After Media item", mediaVideoItem2,
- transition2And3.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaImageItem3,
- transition2And3.getBeforeMediaItem());
- assertEquals("Transtion Duration", 1000, transition2And3.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_SPEED_DOWN,
- transition2And3.getBehavior());
-
- final MediaVideoItem mediaVideoItem4 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- videoItemFilename3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem4.setExtractBoundaries(0, 18000);
- mVideoEditor.addMediaItem(mediaVideoItem4);
-
- final TransitionCrossfade transition3And4 =
- mVideoEditorHelper.createTCrossFade("transition3And4", mediaImageItem3,
- mediaVideoItem4, 5000, Transition.BEHAVIOR_LINEAR);
- mVideoEditor.addTransition(transition3And4);
-
- assertTrue("Transition ID",
- transition3And4.getId().equals("transition3And4"));
- assertEquals("Transtion After Media item", mediaImageItem3,
- transition3And4.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem4,
- transition3And4.getBeforeMediaItem());
- assertEquals("Transtion Duration", 5000, transition3And4.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_LINEAR,
- transition3And4.getBehavior());
-
- final MediaVideoItem mediaVideoItem5 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- videoItemFilename4, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem5);
-
- final TransitionCrossfade transition4And5 =
- mVideoEditorHelper.createTCrossFade("transition4And5", mediaVideoItem4,
- mediaVideoItem5, 8000, Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(transition4And5);
-
- assertTrue("Transition ID",
- transition4And5.getId().equals("transition4And5"));
- assertEquals("Transtion After Media item", mediaVideoItem4,
- transition4And5.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem5,
- transition4And5.getBeforeMediaItem());
- assertEquals("Transtion Duration", 8000, transition4And5.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_MIDDLE_FAST,
- transition4And5.getBehavior());
-
- final MediaVideoItem mediaVideoItem6 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m6",
- videoItemFilename5, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem6.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaVideoItem6);
-
- final TransitionCrossfade transition5And6 =
- mVideoEditorHelper.createTCrossFade("transition5And6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_SLOW);
- mVideoEditor.addTransition(transition5And6);
-
- assertTrue("Transition ID",
- transition5And6.getId().equals("transition5And6"));
- assertEquals("Transtion After Media item", mediaVideoItem5,
- transition5And6.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem6,
- transition5And6.getBeforeMediaItem());
- assertEquals("Transtion Duration", 2000, transition5And6.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_MIDDLE_SLOW,
- transition5And6.getBehavior());
-
- flagForException = false;
- try {
- mVideoEditorHelper.createTCrossFade("transitiond6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_SPEED_UP - 1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition FadeBlack with Invalid behavior", flagForException);
- flagForException = false;
- try {
- mVideoEditorHelper.createTCrossFade("transitiond6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_FAST + 1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition FadeBlack with Invalid behavior", flagForException);
- }
-
- /**
- * To test Transition : Sliding with all behavior
- * SPEED_UP/SPEED_DOWN/LINEAR/MIDDLE_SLOW/MIDDLE_FAST and Direction =
- * DIRECTION_RIGHT_OUT_LEFT_IN
- * ,DIRECTION_LEFT_OUT_RIGHT_IN,DIRECTION_TOP_OUT_BOTTOM_IN
- * ,DIRECTION_BOTTOM_OUT_TOP_IN
- */
-
- @LargeTest
- public void testTransitionSliding() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String videoItemFilename2 = INPUT_FILE_PATH +
- "H263_profile0_176x144_15fps_128kbps_1_35.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH +
- "IMG_1600x1200.jpg";
- final String videoItemFilename3 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final String videoItemFilename4 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_256kbps_0_30.mp4";
- final String videoItemFilename5 = INPUT_FILE_PATH +
- "H263_profile0_176x144_10fps_96kbps_0_25.3gp";
- boolean flagForException = false;
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- videoItemFilename2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem2.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final TransitionSliding transition1And2 =
- mVideoEditorHelper.createTSliding("transition1And2", mediaVideoItem1,
- mediaVideoItem2, 3000, Transition.BEHAVIOR_SPEED_UP,
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN);
- mVideoEditor.addTransition(transition1And2);
-
- assertTrue("Transition ID",
- transition1And2.getId().equals("transition1And2"));
- assertEquals("Transtion After Media item", mediaVideoItem1,
- transition1And2.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem2,
- transition1And2.getBeforeMediaItem());
- assertEquals("Transtion Duration", 3000, transition1And2.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_SPEED_UP,
- transition1And2.getBehavior());
- assertEquals("Transition Sliding",
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN,
- transition1And2.getDirection());
-
- final MediaImageItem mediaImageItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- imageItemFilename1, 15000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem3);
-
- final TransitionSliding transition2And3 =
- mVideoEditorHelper.createTSliding("transition2And3",
- mediaVideoItem2, mediaImageItem3, 1000,
- Transition.BEHAVIOR_SPEED_DOWN,
- TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN);
- mVideoEditor.addTransition(transition2And3);
-
- assertTrue("Transition ID",
- transition2And3.getId().equals("transition2And3"));
- assertEquals("Transtion After Media item", mediaVideoItem2,
- transition2And3.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaImageItem3,
- transition2And3.getBeforeMediaItem());
- assertEquals("Transtion Duration", 1000, transition2And3.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_SPEED_DOWN,
- transition2And3.getBehavior());
- assertEquals("Transition Sliding",
- TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN,
- transition2And3.getDirection());
-
- final MediaVideoItem mediaVideoItem4 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- videoItemFilename3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem4.setExtractBoundaries(0, 18000);
- mVideoEditor.addMediaItem(mediaVideoItem4);
-
- final TransitionSliding transition3And4 =
- mVideoEditorHelper.createTSliding("transition3And4", mediaImageItem3,
- mediaVideoItem4, 5000, Transition.BEHAVIOR_LINEAR,
- TransitionSliding.DIRECTION_TOP_OUT_BOTTOM_IN);
- mVideoEditor.addTransition(transition3And4);
-
- assertTrue("Transition ID",
- transition3And4.getId().equals("transition3And4"));
- assertEquals("Transtion After Media item", mediaImageItem3,
- transition3And4.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem4,
- transition3And4.getBeforeMediaItem());
- assertEquals("Transtion Duration", 5000, transition3And4.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_LINEAR,
- transition3And4.getBehavior());
- assertEquals("Transition Sliding",
- TransitionSliding.DIRECTION_TOP_OUT_BOTTOM_IN,
- transition3And4.getDirection());
-
- final MediaVideoItem mediaVideoItem5 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- videoItemFilename4, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem5);
-
- final TransitionSliding transition4And5 =
- mVideoEditorHelper.createTSliding("transition4And5", mediaVideoItem4,
- mediaVideoItem5, 8000, Transition.BEHAVIOR_MIDDLE_FAST,
- TransitionSliding.DIRECTION_BOTTOM_OUT_TOP_IN);
- mVideoEditor.addTransition(transition4And5);
-
- assertTrue("Transition ID",
- transition4And5.getId().equals("transition4And5"));
- assertEquals("Transtion After Media item", mediaVideoItem4,
- transition4And5.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem5,
- transition4And5.getBeforeMediaItem());
- assertEquals("Transtion Duration", 8000, transition4And5.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_MIDDLE_FAST,
- transition4And5.getBehavior());
- assertEquals("Transition Sliding",
- TransitionSliding.DIRECTION_BOTTOM_OUT_TOP_IN,
- transition4And5.getDirection());
-
- final MediaVideoItem mediaVideoItem6 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m6",
- videoItemFilename5, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem6.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaVideoItem6);
-
- final TransitionSliding transition5And6 =
- mVideoEditorHelper.createTSliding("transition5And6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_SLOW,
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN);
- mVideoEditor.addTransition(transition5And6);
-
- assertTrue("Transition ID",
- transition5And6.getId().equals("transition5And6"));
- assertEquals("Transtion After Media item", mediaVideoItem5,
- transition5And6.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem6,
- transition5And6.getBeforeMediaItem());
- assertEquals("Transtion Duration", 2000, transition5And6.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_MIDDLE_SLOW,
- transition5And6.getBehavior());
- assertEquals("Transition Sliding",
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN,
- transition5And6.getDirection());
-
- flagForException = false;
- try {
- mVideoEditorHelper.createTSliding("transitiond6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_SLOW,
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN - 1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition Sliding with Invalid Direction", flagForException);
- flagForException = false;
- try {
- mVideoEditorHelper.createTSliding("transitiond6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_FAST + 1,
- TransitionSliding.DIRECTION_BOTTOM_OUT_TOP_IN + 1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition Sliding with Invalid behavior", flagForException);
- flagForException = false;
- try {
- mVideoEditorHelper.createTSliding("transitiond6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_SPEED_UP - 1,
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition Sliding with Invalid behavior", flagForException);
- flagForException = false;
- try {
- mVideoEditorHelper.createTSliding("transitiond6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_FAST + 1,
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition Sliding with Invalid behavior", flagForException);
- }
-
- /**
- * To test Transition : Alpha with all behavior
- * SPEED_UP/SPEED_DOWN/LINEAR/MIDDLE_SLOW/MIDDLE_FAST
- */
-
- @LargeTest
- public void testTransitionAlpha() throws Exception {
-
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String videoItemFilename2 = INPUT_FILE_PATH +
- "H263_profile0_176x144_15fps_128kbps_1_35.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH +
- "IMG_640x480.jpg";
- final String videoItemFilename3 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final String videoItemFilename4 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_256kbps_0_30.mp4";
- final String videoItemFilename5 = INPUT_FILE_PATH +
- "H263_profile0_176x144_10fps_96kbps_0_25.3gp";
- final String maskFilename = INPUT_FILE_PATH +
- "TransitionSpiral_QVGA.jpg";
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- videoItemFilename2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem2.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final TransitionAlpha transition1And2 =
- mVideoEditorHelper.createTAlpha("transition1And2", mediaVideoItem1,
- mediaVideoItem2, 3000, Transition.BEHAVIOR_SPEED_UP, maskFilename,
- 10, false);
- mVideoEditor.addTransition(transition1And2);
-
- assertTrue("Transition ID",
- transition1And2.getId().equals("transition1And2"));
- assertEquals("Transtion After Media item", mediaVideoItem1,
- transition1And2.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem2,
- transition1And2.getBeforeMediaItem());
- assertEquals("Transtion Duration", 3000, transition1And2.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_SPEED_UP,
- transition1And2.getBehavior());
- assertTrue("Transition maskFile",
- transition1And2.getMaskFilename().equals(maskFilename));
- assertEquals("Transition BlendingPercent", 10,
- transition1And2.getBlendingPercent());
- assertFalse("Transition Invert", transition1And2.isInvert());
-
- final MediaImageItem mediaImageItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- imageItemFilename1, 15000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem3);
-
- final TransitionAlpha transition2And3 =
- mVideoEditorHelper.createTAlpha("transition2And3", mediaVideoItem2,
- mediaImageItem3, 1000, Transition.BEHAVIOR_SPEED_DOWN,
- maskFilename, 30, false);
- mVideoEditor.addTransition(transition2And3);
-
- assertTrue("Transition ID",
- transition2And3.getId().equals("transition2And3"));
- assertEquals("Transtion After Media item", mediaVideoItem2,
- transition2And3.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaImageItem3,
- transition2And3.getBeforeMediaItem());
- assertEquals("Transtion Duration", 1000, transition2And3.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_SPEED_DOWN,
- transition2And3.getBehavior());
- assertTrue("Transition maskFile",
- transition2And3.getMaskFilename().equals(maskFilename));
- assertEquals("Transition BlendingPercent", 30,
- transition2And3.getBlendingPercent());
- assertFalse("Transition Invert", transition2And3.isInvert());
-
- final MediaVideoItem mediaVideoItem4 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- videoItemFilename3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem4.setExtractBoundaries(0, 18000);
- mVideoEditor.addMediaItem(mediaVideoItem4);
-
- final TransitionAlpha transition3And4 =
- mVideoEditorHelper.createTAlpha("transition3And4", mediaImageItem3,
- mediaVideoItem4, 5000, Transition.BEHAVIOR_LINEAR, maskFilename,
- 50, false);
- mVideoEditor.addTransition(transition3And4);
-
- assertTrue("Transition ID",
- transition3And4.getId().equals("transition3And4"));
- assertEquals("Transtion After Media item", mediaImageItem3,
- transition3And4.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem4,
- transition3And4.getBeforeMediaItem());
- assertEquals("Transtion Duration", 5000, transition3And4.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_LINEAR,
- transition3And4.getBehavior());
- assertTrue("Transition maskFile",
- transition3And4.getMaskFilename().equals(maskFilename));
- assertEquals("Transition BlendingPercent", 50,
- transition3And4.getBlendingPercent());
- assertFalse("Transition Invert", transition3And4.isInvert());
-
- final MediaVideoItem mediaVideoItem5 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- videoItemFilename4, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem5);
-
- final TransitionAlpha transition4And5 =
- mVideoEditorHelper.createTAlpha("transition4And5", mediaVideoItem4,
- mediaVideoItem5, 8000, Transition.BEHAVIOR_MIDDLE_FAST,
- maskFilename, 70, true);
- mVideoEditor.addTransition(transition4And5);
-
- assertTrue("Transition ID",
- transition4And5.getId().equals("transition4And5"));
- assertEquals("Transtion After Media item", mediaVideoItem4,
- transition4And5.getAfterMediaItem());
- assertEquals("Transtion Before Media item", mediaVideoItem5,
- transition4And5.getBeforeMediaItem());
- assertEquals("Transtion Duration", 8000, transition4And5.getDuration());
- assertEquals("Transtion Behavior", Transition.BEHAVIOR_MIDDLE_FAST,
- transition4And5.getBehavior());
- assertTrue("Transition maskFile",
- transition4And5.getMaskFilename().equals(maskFilename));
- assertEquals("Transition BlendingPercent", 70,
- transition4And5.getBlendingPercent());
- assertTrue("Transition Invert", transition4And5.isInvert());
-
- final MediaVideoItem mediaVideoItem6 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m6",
- videoItemFilename5, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem6.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaVideoItem6);
-
- try {
- mVideoEditorHelper.createTAlpha("transition5And6", mediaVideoItem5,
- mediaVideoItem6, 2000, Transition.BEHAVIOR_MIDDLE_SLOW,
- INPUT_FILE_PATH + "imDummyFile.jpg", 70,
- true);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("MaskFile is not exsisting", flagForException);
- flagForException = false;
- try {
- mVideoEditorHelper.createTAlpha("transition5And6", null, null, 2000,
- Transition.BEHAVIOR_MIDDLE_SLOW, maskFilename, 101, true);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Invalid Blending Percent", flagForException);
-
- flagForException = false;
- try {
- mVideoEditorHelper.createTAlpha("transitiond6", mediaVideoItem4,
- mediaVideoItem5, 2000, Transition.BEHAVIOR_SPEED_UP - 1,
- maskFilename, 30, false);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition FadeBlack with Invalid behavior", flagForException);
- flagForException = false;
- try {
- mVideoEditorHelper.createTAlpha("transitiond6", mediaVideoItem4,
- mediaVideoItem5, 2000, Transition.BEHAVIOR_MIDDLE_FAST + 1,
- maskFilename, 30, false);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition FadeBlack with Invalid behavior", flagForException);
- }
-
- /**
- * To test Frame Overlay for Media Video Item
- */
-
- @LargeTest
- public void testFrameOverlayVideoItem() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H263_profile0_176x144_10fps_256kbps_0_25.3gp";
- final String overlayFile1 = INPUT_FILE_PATH + "IMG_176x144_Overlay1.png";
- final String overlayFile2 = INPUT_FILE_PATH + "IMG_176x144_Overlay2.png";
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final Bitmap mBitmap1 = mVideoEditorHelper.getBitmap(overlayFile1,
- 176, 144);
- final OverlayFrame overlayFrame1 = mVideoEditorHelper.createOverlay(
- mediaVideoItem1, "overlayId1", mBitmap1, 5000, 5000);
- mediaVideoItem1.addOverlay(overlayFrame1);
-
- assertEquals("Overlay : Media Item", mediaVideoItem1,
- overlayFrame1.getMediaItem());
- assertTrue("Overlay Id", overlayFrame1.getId().equals("overlayId1"));
- assertEquals("Overlay Bitmap", mBitmap1, overlayFrame1.getBitmap());
- assertEquals("Overlay Start Time", 5000, overlayFrame1.getStartTime());
- assertEquals("Overlay Duration", 5000, overlayFrame1.getDuration());
-
- Bitmap upddateBmp = mVideoEditorHelper.getBitmap(overlayFile2, 176, 144);
- overlayFrame1.setBitmap(upddateBmp);
- assertEquals("Overlay Update Bitmap", upddateBmp, overlayFrame1.getBitmap());
- upddateBmp.recycle();
- }
-
- /**
- * To test Frame Overlay for Media Video Item : Set duration and Get
- * Duration
- */
-
- @LargeTest
- public void testFrameOverlaySetAndGet() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_30fps_512Kbps_0_27.mp4";
- final String overlayFile1 = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
- boolean flagForException = false;
-
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1,
- 640, 480);
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final OverlayFrame overlayFrame1 = mVideoEditorHelper.createOverlay(
- mediaVideoItem1, "overlayId1", mBitmap, 5000, 5000);
- mediaVideoItem1.addOverlay(overlayFrame1);
- overlayFrame1.setDuration(5000);
-
- assertEquals("Overlay Duration", 5000, overlayFrame1.getDuration());
- try {
- overlayFrame1.setDuration(mediaVideoItem1.getDuration() + 10000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay Duration > MediaVideo Item Duration",
- flagForException);
-
- assertEquals("Overlay Duration", 5000, overlayFrame1.getDuration());
- flagForException = false;
-
- try {
- overlayFrame1.setDuration(-1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay Duration = -1", flagForException);
- }
-
- /**
- * To test Frame Overlay for Media Video Item : Set duration and Get
- * Duration
- */
-
- @LargeTest
- public void testFrameOverlayInvalidTime() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
- final String overlayFile1 = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
- boolean flagForException = false;
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- try {
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1,
- 640, 480);
- mVideoEditorHelper.createOverlay(mediaVideoItem1, "overlayId1",
- mBitmap, 400000000, 2000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay With Invalid Start Time", flagForException);
-
- flagForException = false;
- try {
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1,
- 640, 480);
- mVideoEditorHelper.createOverlay(mediaVideoItem1, "overlayId2",
- mBitmap, -1, 2000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay With Invalid Start Time", flagForException);
-
- flagForException = false;
- try {
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1,
- 640, 480);
- mVideoEditorHelper.createOverlay(mediaVideoItem1, "overlayId3",
- mBitmap, 2000, -1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay With Invalid Start Time", flagForException);
- }
-
- /**
- * To test Frame Overlay for Media Image Item
- */
- @LargeTest
- public void testFrameOverlayImageItem() throws Exception {
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String overlayFile1 = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
- final String overlayFile2 = INPUT_FILE_PATH + "IMG_640x480_Overlay2.png";
-
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- imageItemFilename1, 10000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1, 640,
- 480);
- final OverlayFrame overlayFrame1 = mVideoEditorHelper.createOverlay(
- mediaImageItem1, "overlayId1", mBitmap, 5000, 5000);
- mediaImageItem1.addOverlay(overlayFrame1);
-
- assertEquals("Overlay : Media Item", mediaImageItem1,
- overlayFrame1.getMediaItem());
- assertTrue("Overlay Id", overlayFrame1.getId().equals("overlayId1"));
- assertEquals("Overlay Bitmap",mBitmap ,overlayFrame1.getBitmap());
- assertEquals("Overlay Start Time", 5000, overlayFrame1.getStartTime());
- assertEquals("Overlay Duration", 5000, overlayFrame1.getDuration());
- Bitmap upddateBmp = mVideoEditorHelper.getBitmap(overlayFile2, 640, 480);
-
- overlayFrame1.setBitmap(upddateBmp);
- assertEquals("Overlay Update Bitmap", upddateBmp, overlayFrame1.getBitmap());
- upddateBmp.recycle();
- }
-
- /**
- * To test Frame Overlay for Media Image Item : Set duration and Get
- * Duration
- */
-
- @LargeTest
- public void testFrameOverlaySetAndGetImage() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String overlayFile1 = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
- boolean flagForException = false;
-
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, 10000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1,
- 640, 480);
- final OverlayFrame overlayFrame1 = mVideoEditorHelper.createOverlay(
- mediaImageItem1, "overlayId1", mBitmap, 5000, 5000);
- mediaImageItem1.addOverlay(overlayFrame1);
-
- overlayFrame1.setDuration(5000);
- assertEquals("Overlay Duration", 5000, overlayFrame1.getDuration());
-
- try {
- overlayFrame1.setDuration(mediaImageItem1.getDuration() + 10000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay Duration > Media Item Duration", flagForException);
- assertEquals("Overlay Duration", 5000, overlayFrame1.getDuration());
-
- flagForException = false;
- try {
- overlayFrame1.setDuration(-1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay Duration = -1", flagForException);
- }
-
- /**
- * To test Frame Overlay for Media Image Item :Invalid StartTime and
- * Duration
- */
-
- @LargeTest
- public void testFrameOverlayInvalidTimeImage() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String overlayFile1 = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
- boolean flagForException = false;
-
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, 10000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- try {
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1,
- 640, 480);
- mVideoEditorHelper.createOverlay(mediaImageItem1, "overlayId1",
- mBitmap, 400000000, 2000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay With Invalid Start Time", flagForException);
-
- flagForException = false;
- try {
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1,
- 640, 480);
- mVideoEditorHelper.createOverlay(mediaImageItem1, "overlayId2",
- mBitmap, -1, 2000);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay With Invalid Start Time", flagForException);
-
- flagForException = false;
- try {
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1,
- 640, 480);
- mVideoEditorHelper.createOverlay(mediaImageItem1, "overlayId3",
- mBitmap, 2000, -1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Overlay With Invalid Start Time", flagForException);
- }
-
- /**
- * To Test Frame Overlay Media Image Item :JPG File
- */
-
- @LargeTest
- public void testFrameOverlayJPGImage() throws Exception {
-
- final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String overlayFile1 = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
- boolean flagForException = false;
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- imageItemFilename, 10000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem1);
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile1, 640,
- 480);
- mVideoEditorHelper.createOverlay(mediaImageItem1, "overlayId1",
- mBitmap, 5000, 5000);
- }
-
- /**
- * To test Video Editor API
- *
- * @throws Exception
- */
- @LargeTest
- public void testVideoEditorAPI() throws Exception {
-
- final String videoItemFileName1 = INPUT_FILE_PATH
- + "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
- final String videoItemFileName2 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
- final String videoItemFileName3 = INPUT_FILE_PATH
- + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final String imageItemFileName1 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String imageItemFileName2 = INPUT_FILE_PATH + "IMG_176x144.jpg";
- final String audioFilename1 = INPUT_FILE_PATH +
- "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
- final String audioFilename2 = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- TransitionCrossfade transition2And4;
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName1, renderingMode);
- mediaVideoItem1.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- videoItemFileName2, renderingMode);
- mediaVideoItem2.setExtractBoundaries(mediaVideoItem2.getDuration() / 4,
- mediaVideoItem2.getDuration() / 2);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final MediaVideoItem mediaVideoItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- videoItemFileName3, renderingMode);
- mediaVideoItem3.setExtractBoundaries(mediaVideoItem3.getDuration() / 2,
- mediaVideoItem3.getDuration());
- mVideoEditor.addMediaItem(mediaVideoItem3);
-
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- imageItemFileName1, 5000, renderingMode);
-
- final MediaImageItem mediaImageItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- imageItemFileName2, 5000, renderingMode);
-
- List<MediaItem> mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item List Size", 3, mediaList.size());
-
- mVideoEditor.insertMediaItem(mediaImageItem1, mediaVideoItem2.getId());
- mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item List Size", 4, mediaList.size());
- assertEquals("Media item 1", mediaVideoItem1, mediaList.get(0));
- assertEquals("Media item 2", mediaVideoItem2, mediaList.get(1));
- assertEquals("Media item 4", mediaImageItem1, mediaList.get(2));
- assertEquals("Media item 3", mediaVideoItem3, mediaList.get(3));
-
- mVideoEditor.insertMediaItem(mediaImageItem2, mediaImageItem1.getId());
- mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item List Size", 5, mediaList.size());
- assertEquals("Media item 1", mediaVideoItem1, mediaList.get(0));
- assertEquals("Media item 2", mediaVideoItem2, mediaList.get(1));
- assertEquals("Media item 4", mediaImageItem1, mediaList.get(2));
- assertEquals("Media item 5", mediaImageItem2, mediaList.get(3));
- assertEquals("Media item 3", mediaVideoItem3, mediaList.get(4));
-
- mVideoEditor.moveMediaItem(mediaVideoItem1.getId(), mediaImageItem2.getId());
- mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item List Size", 5, mediaList.size());
- assertEquals("Media item 2", mediaVideoItem2, mediaList.get(0));
- assertEquals("Media item 4", mediaImageItem1, mediaList.get(1));
- assertEquals("Media item 5", mediaImageItem2, mediaList.get(2));
- assertEquals("Media item 1", mediaVideoItem1, mediaList.get(3));
- assertEquals("Media item 3", mediaVideoItem3, mediaList.get(4));
-
- assertEquals("Media Item 1", mediaVideoItem1,
- mVideoEditor.getMediaItem(mediaVideoItem1.getId()));
-
- flagForException = false;
- transition2And4 = null;
- try{
- transition2And4 = mVideoEditorHelper.createTCrossFade(
- "transition2And4", mediaVideoItem2, mediaImageItem1, 2000,
- Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(transition2And4);
- }
- catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertFalse("Transition2and4 cannot be created", flagForException);
-
-
- TransitionCrossfade transition1And3 = null;
- flagForException = false;
- try{
- transition1And3 = mVideoEditorHelper.createTCrossFade(
- "transition1And3", mediaVideoItem1, mediaVideoItem2, 5000,
- Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(transition1And3);
- }catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Transition1and3 cannot be created", flagForException);
-
- List<Transition> transitionList = mVideoEditor.getAllTransitions();
- assertEquals("Transition List", 1, transitionList.size());
-
- assertEquals("Transition 2", transition2And4,
- mVideoEditor.getTransition(transition2And4.getId()));
-
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFilename1);
- mVideoEditor.addAudioTrack(audioTrack);
-
- List<AudioTrack> audioList = mVideoEditor.getAllAudioTracks();
- assertEquals("Audio List", 1, audioList.size());
-
- final AudioTrack audioTrack1 = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack1", audioFilename2);
- flagForException = false;
- try {
- mVideoEditor.addAudioTrack(audioTrack1);
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Audio Track support is 1 ", flagForException);
-
- flagForException = false;
- try {
- mVideoEditor.insertAudioTrack(audioTrack1,"audioTrack");
- } catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Audio Track supports is 1 ", flagForException);
-
- assertEquals("Removing AudioTrack", audioTrack,
- mVideoEditor.removeAudioTrack(audioTrack.getId()));
-
- assertEquals("Removing transition", transition2And4,
- mVideoEditor.removeTransition(transition2And4.getId()));
-
- assertEquals("Removing Media Item", mediaVideoItem2,
- mVideoEditor.removeMediaItem(mediaVideoItem2.getId()));
-
- mVideoEditor.setAspectRatio(MediaProperties.ASPECT_RATIO_16_9);
- assertEquals("Check Aspect Ratio", MediaProperties.ASPECT_RATIO_16_9,
- mVideoEditor.getAspectRatio());
-
- long storyBoardDuration = mediaVideoItem1.getTimelineDuration()
- + mediaVideoItem3.getTimelineDuration()
- + mediaImageItem1.getDuration()
- + mediaImageItem2.getDuration();
- assertEquals("Story Board Duration", storyBoardDuration,
- mVideoEditor.getDuration());
- }
-
- /**
- * To add Audio Track Greater than MediaItem Duration
- *
- * @throws Exception
- */
- @LargeTest
- public void testVideoLessThanAudio() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH
- + "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
- final String audioTrackFilename = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrackId", audioTrackFilename);
- mVideoEditor.addAudioTrack(audioTrack);
- assertEquals("Storyboard = mediaItem Duration",
- mediaVideoItem1.getDuration(), mVideoEditor.getDuration());
- assertTrue("Audio Duration > mediaItem Duration",
- (audioTrack.getDuration() > mediaVideoItem1.getDuration() ?
- true : false));
- }
-
- /**
- * To test Video Editor API with 1080 P
- *
- * @throws Exception
- */
- @LargeTest
- public void testVideoContentHD() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH
- + "H264_BP_1920x1080_30fps_1200Kbps_1_10.mp4";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final MediaVideoItem mediaVideoItem1;
- // 1080p resolution is supported on some devices
- // but not on other devices.
- // So this test case is not generic and
- // hence we always assert true
- boolean flagForException = true;
- try {
- mediaVideoItem1 = mVideoEditorHelper.createMediaItem(mVideoEditor,
- "m1", videoItemFileName1, renderingMode);
- } catch (IllegalArgumentException e) {
- }
- assertTrue("VideoContent 1920x1080", flagForException);
- }
-
-
- /**
- * To test: Remove audio track
- *
- * @throws Exception
- */
- @LargeTest
- public void testRemoveAudioTrack() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- boolean flagForException = false;
-
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack1", audioFileName);
- mVideoEditor.addAudioTrack(audioTrack);
-
- assertEquals("Audio Track Item Duration", audioTrack.getDuration(),
- audioTrack.getTimelineDuration());
- assertTrue("Audio Track ID", audioTrack.getId().equals("audioTrack1"));
- assertNotNull("Remove Audio Track",
- mVideoEditor.removeAudioTrack("audioTrack1"));
- try{
- mVideoEditor.removeAudioTrack("audioTrack1");
- }catch (IllegalArgumentException e){
- flagForException = true;
- }
- assertTrue("Remove Audio Track not possible", flagForException);
- }
-
- /**
- * To test: Disable ducking
- *
- * @throws Exception
- */
- @LargeTest
- public void testAudioDuckingDisable() throws Exception {
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- mVideoEditor.addAudioTrack(audioTrack);
-
- audioTrack.disableDucking();
- assertFalse("Audio Track Ducking is Disabled",
- audioTrack.isDuckingEnabled());
- }
-
-
-
- /**
- * To test: Need a basic test case for the get value for TransitionAlpha
- * ( ie. getBlendingPercent, getMaskFilename, isInvert)
- *
- * @throws Exception
- */
- @LargeTest
- public void testTransitionAlphaBasic() throws Exception {
-
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String maskFilename = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
- boolean flagForException = false;
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 15000);
-
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2", maskFilename,
- 10000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaImageItem.setDuration(15000);
-
- mVideoEditor.addMediaItem(mediaVideoItem1);
- mVideoEditor.addMediaItem(mediaImageItem);
- final TransitionAlpha transition1And2 =
- mVideoEditorHelper.createTAlpha("transition1And2", mediaVideoItem1,
- mediaImageItem, 3000, Transition.BEHAVIOR_SPEED_UP,
- maskFilename, 10, false);
- mVideoEditor.addTransition(transition1And2);
- assertTrue("Transition maskFile",
- transition1And2.getMaskFilename().equals(maskFilename));
- assertEquals("Transition BlendingPercent", 10,
- transition1And2.getBlendingPercent());
- assertFalse("Transition Invert", transition1And2.isInvert());
- }
-
- /**
- * To test: NULL arguments to the Video Editor APIs
- *
- * @throws Exception
- */
- @LargeTest
- public void testNullAPIs() throws Exception {
-
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String maskFilename = INPUT_FILE_PATH +
- "IMG_640x480_Overlay1.png";
- final String audioFileName = INPUT_FILE_PATH +
- "AACLC_48KHz_256Kbps_s_1_17.3gp";
- boolean flagForException = false;
-
- try {
- mVideoEditor.addAudioTrack(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Video Editor with null Audio Track", flagForException);
- flagForException = false;
- try {
- mVideoEditor.addMediaItem(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Video Editor with NULL Image Item ", flagForException);
- flagForException = false;
- try {
- mVideoEditor.addMediaItem(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Video Editor with NULL Video Item ", flagForException);
-
- MediaVideoItem mediaVideoItem1 = null;
- try {
- mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- } catch (IllegalArgumentException e) {
- assertTrue("Cannot Create Video Item", false);
- }
- mediaVideoItem1.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
- flagForException = false;
- try {
- mediaVideoItem1.addEffect(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Video with null effect ", flagForException);
- flagForException = false;
- try {
- mediaVideoItem1.addOverlay(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Video with null overlay ", flagForException);
-
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2", maskFilename,
- 10000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaImageItem.setDuration(15000);
- mVideoEditor.addMediaItem(mediaImageItem);
- flagForException = false;
- try {
- mediaImageItem.addEffect(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Image with null effect ", flagForException);
- flagForException = false;
- try {
- mediaImageItem.addOverlay(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Image with null overlay ", flagForException);
-
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioFileName);
- mVideoEditor.addAudioTrack(audioTrack);
-
- flagForException = false;
- try {
- mVideoEditor.addTransition(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Added null transition ", flagForException);
-
- flagForException = false;
- try {
- mVideoEditor.addTransition(null);
- } catch(IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Added null transition ", flagForException);
-
- }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorExportTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorExportTest.java
deleted file mode 100644
index 69ecf0d..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorExportTest.java
+++ /dev/null
@@ -1,812 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.functional.videoeditor;
-
-import java.io.File;
-
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.media.videoeditor.AudioTrack;
-import android.media.videoeditor.EffectColor;
-import android.media.videoeditor.EffectKenBurns;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.videoeditor.MediaProperties;
-import android.media.videoeditor.MediaVideoItem;
-import android.media.videoeditor.OverlayFrame;
-import android.media.videoeditor.Transition;
-import android.media.videoeditor.TransitionAlpha;
-import android.media.videoeditor.TransitionCrossfade;
-import android.media.videoeditor.TransitionFadeBlack;
-import android.media.videoeditor.TransitionSliding;
-import android.media.videoeditor.VideoEditor;
-import android.media.videoeditor.VideoEditor.ExportProgressListener;
-import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase;
-
-
-import android.util.Log;
-
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
-import com.android.mediaframeworktest.VideoEditorHelper;
-
-public class VideoEditorExportTest extends
- ActivityInstrumentationTestCase<MediaFrameworkTest> {
- private final String TAG = "TransitionTest";
-
- private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
-
- private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
-
- private VideoEditor mVideoEditor;
-
- private VideoEditorHelper mVideoEditorHelper;
-
- // Declares the annotation for Preview Test Cases
- public @interface TransitionTests {
- }
-
- public VideoEditorExportTest() {
- super("com.android.mediaframeworktest", MediaFrameworkTest.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- // setup for each test case.
- super.setUp();
- mVideoEditorHelper = new VideoEditorHelper();
- // Create a random String which will be used as project path, where all
- // project related files will be stored.
- final String projectPath =
- mVideoEditorHelper.createRandomFile(PROJECT_LOCATION);
- mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
- // Clean the directory created as project path
- mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
- System.gc();
- super.tearDown();
- }
-
- /**
- * To Test export : Merge and Trim different types of Video and Image files
- */
- @LargeTest
- public void testExportMergeTrim() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String videoItemFilename2 = INPUT_FILE_PATH
- + "H264_BP_640x480_12.5fps_256kbps_AACLC_16khz_24kbps_s_0_26.mp4";
- final String videoItemFilename3 = INPUT_FILE_PATH
- + "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
- final String imageItemFilename2 = INPUT_FILE_PATH + "IMG_176x144.jpg";
- final String imageItemFilename3 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/")
- + ".3gp";
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(2000, 7000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaImageItem mediaImageItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFilename1, 3000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem2);
-
- final MediaVideoItem mediaVideoItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- videoItemFilename2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem3.setExtractBoundaries(0, 2000);
- mVideoEditor.addMediaItem(mediaVideoItem3);
-
- final MediaVideoItem mediaVideoItem4 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- videoItemFilename3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem4.setExtractBoundaries(mediaVideoItem4.getDuration()-5000,
- mediaVideoItem4.getDuration());
- mVideoEditor.addMediaItem(mediaVideoItem4);
-
- final MediaImageItem mediaImageItem5 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- imageItemFilename2, 4000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem5);
-
- final MediaImageItem mediaImageItem6 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m6",
- imageItemFilename3, 2000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem6);
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_720,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- final long storyBoardDuration = mediaVideoItem1.getTimelineDuration()
- + mediaImageItem2.getDuration() + mediaVideoItem3.getTimelineDuration()
- + mediaVideoItem4.getTimelineDuration() + mediaImageItem5.getDuration()
- + mediaImageItem6.getDuration();
- mVideoEditorHelper.validateExport(mVideoEditor, outFilename,
- MediaProperties.HEIGHT_720, 0, storyBoardDuration,
- MediaProperties.VCODEC_H264, MediaProperties.ACODEC_AAC_LC);
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
- }
-
- /**
- *To Test export : With Effect and Overlays on Different Media Items
- */
- @LargeTest
- public void testExportEffectOverlay() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String videoItemFilename2 = INPUT_FILE_PATH
- + "H264_BP_640x480_15fps_1200Kbps_AACLC_48KHz_64kps_m_0_27.3gp";
- final String videoItemFilename3 = INPUT_FILE_PATH
- + "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
- final String imageItemFilename2 = INPUT_FILE_PATH + "IMG_176x144.jpg";
- final String imageItemFilename3 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
-
- final String overlayFile = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(2000, 7000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final EffectColor effectPink =
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effectPink",
- 0, 2000, EffectColor.TYPE_COLOR, EffectColor.PINK);
- mediaVideoItem1.addEffect(effectPink);
-
- final EffectColor effectNegative =
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effectNegative",
- 3000, 4000, EffectColor.TYPE_NEGATIVE, 0);
- mediaVideoItem1.addEffect(effectNegative);
-
- final MediaImageItem mediaImageItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFilename1, 3000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem2);
-
- final EffectColor effectFifties =
- mVideoEditorHelper.createEffectItem(mediaImageItem2, "effectFifties",
- 0, 3000, EffectColor.TYPE_FIFTIES, 0);
- mediaImageItem2.addEffect(effectFifties);
-
- final MediaVideoItem mediaVideoItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- videoItemFilename2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem3);
- mediaVideoItem3.setExtractBoundaries(0, 8000);
-
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile,
- 640, 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaVideoItem3, "overlay",
- mBitmap, 2000, 5000);
- mediaVideoItem3.addOverlay(overlayFrame);
-
- final EffectColor effectGreen =
- mVideoEditorHelper.createEffectItem(mediaVideoItem3, "effectGreen",
- 0, 2000, EffectColor.TYPE_COLOR, EffectColor.GREEN);
- mediaVideoItem3.addEffect(effectGreen);
-
- final MediaVideoItem mediaVideoItem4 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- videoItemFilename3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem4.setExtractBoundaries(mediaVideoItem4.getDuration()-5000,
- mediaVideoItem4.getDuration());
- mVideoEditor.addMediaItem(mediaVideoItem4);
-
- final EffectColor effectSepia =
- mVideoEditorHelper.createEffectItem(mediaVideoItem4, "effectSepia",
- 0, 2000, EffectColor.TYPE_SEPIA, 0);
- mediaVideoItem4.addEffect(effectSepia);
-
- final MediaImageItem mediaImageItem5 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- imageItemFilename2, 4000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem5);
-
- final EffectColor effectGray =
- mVideoEditorHelper.createEffectItem(mediaImageItem5, "effectGray",
- 0, 2000, EffectColor.TYPE_COLOR, EffectColor.GRAY);
- mediaImageItem5.addEffect(effectGray);
-
- final MediaImageItem mediaImageItem6 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m6",
- imageItemFilename3, 2000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem6);
-
- final EffectColor effectGradient =
- mVideoEditorHelper.createEffectItem(mediaImageItem6,
- "effectGradient", 0, 2000, EffectColor.TYPE_GRADIENT,
- EffectColor.PINK);
- mediaImageItem6.addEffect(effectGradient);
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_720,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- final long storyBoardDuration = mediaVideoItem1.getTimelineDuration()
- + mediaImageItem2.getDuration()
- + mediaVideoItem3.getTimelineDuration()
- + mediaVideoItem4.getTimelineDuration()
- + mediaImageItem5.getDuration()
- + mediaImageItem6.getDuration();
- mVideoEditorHelper.validateExport(mVideoEditor, outFilename,
- MediaProperties.HEIGHT_720, 0, storyBoardDuration,
- MediaProperties.VCODEC_H264, MediaProperties.ACODEC_AAC_LC);
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
- }
-
- /**
- * To test export : with Image with KenBurnEffect
- */
- @LargeTest
- public void testExportEffectKenBurn() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int imageItemRenderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
-
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaImageItem1",
- imageItemFileName, 5000, imageItemRenderingMode);
- mVideoEditor.addMediaItem(mediaImageItem);
-
- final Rect startRect = new Rect((mediaImageItem.getHeight() / 3),
- (mediaImageItem.getWidth() / 3), (mediaImageItem.getHeight() / 2),
- (mediaImageItem.getWidth() / 2));
-
- final Rect endRect = new Rect(0, 0, mediaImageItem.getWidth(),
- mediaImageItem.getHeight());
-
- final EffectKenBurns kbEffectOnMediaItem = new EffectKenBurns(
- mediaImageItem, "KBOnM2", startRect, endRect, 500, 3000);
- assertNotNull("EffectKenBurns", kbEffectOnMediaItem);
- mediaImageItem.addEffect(kbEffectOnMediaItem);
-
- assertEquals("KenBurn Start Rect", startRect,
- kbEffectOnMediaItem.getStartRect());
- assertEquals("KenBurn End Rect", endRect,
- kbEffectOnMediaItem.getEndRect());
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_720,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- mVideoEditorHelper.validateExport(mVideoEditor, outFilename,
- MediaProperties.HEIGHT_720, 0, mediaImageItem.getDuration(),
- MediaProperties.VCODEC_H264, MediaProperties.ACODEC_AAC_LC);
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
- }
-
- /**
- * To Test Export : With Video and Image and An Audio BackGround Track
- */
- @LargeTest
- public void testExportAudio() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
- final String audioTrackFilename = INPUT_FILE_PATH +
- "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFileName, 5000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem);
-
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "a1", audioTrackFilename);
- audioTrack.setExtractBoundaries(2000, 5000);
- mVideoEditor.addAudioTrack(audioTrack);
-
- audioTrack.disableDucking();
- audioTrack.enableLoop();
- audioTrack.setVolume(75);
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_720,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- mVideoEditorHelper.validateExport(mVideoEditor, outFilename,
- MediaProperties.HEIGHT_720, 0, (mediaVideoItem.getTimelineDuration() +
- mediaImageItem.getDuration()),
- MediaProperties.VCODEC_H264, MediaProperties.ACODEC_AAC_LC);
-
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
- }
-
- /**
- *To Test export : With Transition on Different Media Items
- */
- @LargeTest
- public void testExportTransition() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String videoItemFilename2 = INPUT_FILE_PATH
- + "H264_BP_640x480_12.5fps_256kbps_AACLC_16khz_24kbps_s_0_26.mp4";
- final String videoItemFilename3 = INPUT_FILE_PATH +
- "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
-
- final String imageItemFilename2 = INPUT_FILE_PATH + "IMG_176x144.jpg";
- final String imageItemFilename3 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
- final String maskFilename = INPUT_FILE_PATH +
- "TransitionSpiral_QVGA.jpg";
-
- final MediaVideoItem mediaItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaItem1.setExtractBoundaries(2000, 7000);
- mVideoEditor.addMediaItem(mediaItem1);
-
- final TransitionAlpha transition1 =
- mVideoEditorHelper.createTAlpha("transition1", null, mediaItem1,
- 2000, Transition.BEHAVIOR_LINEAR, maskFilename, 50, true);
- mVideoEditor.addTransition(transition1);
-
- final MediaImageItem mediaItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFilename1, 8000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaItem2);
-
- final MediaVideoItem mediaItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- videoItemFilename2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaItem3.setExtractBoundaries(0, 8000);
- mVideoEditor.addMediaItem(mediaItem3);
-
- final TransitionSliding transition2And3 =
- mVideoEditorHelper.createTSliding("transition2", mediaItem2,
- mediaItem3, 4000, Transition.BEHAVIOR_MIDDLE_FAST,
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN);
- mVideoEditor.addTransition(transition2And3);
-
- final MediaVideoItem mediaItem4 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- videoItemFilename3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaItem4);
- mediaItem4.setExtractBoundaries(0, 8000);
-
- final TransitionCrossfade transition3And4 =
- mVideoEditorHelper.createTCrossFade("transition3", mediaItem3,
- mediaItem4, 3500, Transition.BEHAVIOR_MIDDLE_SLOW);
- mVideoEditor.addTransition(transition3And4);
-
- final MediaImageItem mediaItem5 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- imageItemFilename2, 7000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaItem5);
-
- final TransitionFadeBlack transition4And5 =
- mVideoEditorHelper.createTFadeBlack("transition4", mediaItem4,
- mediaItem5, 3500, Transition.BEHAVIOR_SPEED_DOWN);
- mVideoEditor.addTransition(transition4And5);
-
- final MediaImageItem mediaItem6 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m6",
- imageItemFilename3, 3000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaItem6);
-
- final TransitionSliding transition5And6 =
- mVideoEditorHelper.createTSliding("transition5", mediaItem5,
- mediaItem6, 1000/*4000*/, Transition.BEHAVIOR_SPEED_UP,
- TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN);
- mVideoEditor.addTransition(transition5And6);
-
- final TransitionSliding transition6 =
- mVideoEditorHelper.createTSliding("transition6", mediaItem6, null,
- 1000 /*4000*/, Transition.BEHAVIOR_SPEED_UP,
- TransitionSliding.DIRECTION_TOP_OUT_BOTTOM_IN);
- mVideoEditor.addTransition(transition6);
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_720,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- final long storyBoardDuration = mediaItem1.getTimelineDuration()
- + mediaItem2.getTimelineDuration()
- + mediaItem3.getTimelineDuration() - transition2And3.getDuration()
- + mediaItem4.getTimelineDuration() - transition3And4.getDuration()
- + mediaItem5.getTimelineDuration() - transition4And5.getDuration()
- + mediaItem6.getTimelineDuration() - transition5And6.getDuration();
- mVideoEditorHelper.validateExport(mVideoEditor, outFilename,
- MediaProperties.HEIGHT_720, 0, storyBoardDuration,
- MediaProperties.VCODEC_H264, MediaProperties.ACODEC_AAC_LC);
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
- }
-
- /**
- * To Test Export : Without any Media Items in the story Board
- *
- * @throws Exception
- */
- @LargeTest
- public void testExportWithoutMediaItems() throws Exception {
- boolean flagForException = false;
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export("/sdcard/Test.3gp", MediaProperties.HEIGHT_720,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (IllegalStateException e) {
- flagForException = true;
- }
- assertTrue("Export without any MediaItems", flagForException);
- }
-
- /**
- * To Test Export : With Media Items add and removed in the story Board
- *
- * @throws Exception
- */
- @LargeTest
- public void testExportWithoutMediaItemsAddRemove() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_1_17.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String maskFilename = INPUT_FILE_PATH + "TransitionSpiral_QVGA.jpg";
- boolean flagForException = false;
-
- final MediaVideoItem mediaItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaItem1.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaItem1);
-
- final MediaImageItem mediaItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFilename1, 15000,
- MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaItem2);
-
- final TransitionAlpha transition1 =
- mVideoEditorHelper.createTAlpha("transition1", mediaItem1, mediaItem2,
- 3000, Transition.BEHAVIOR_LINEAR, maskFilename, 50, false);
- mVideoEditor.addTransition(transition1);
-
- final EffectColor effectColor =
- mVideoEditorHelper.createEffectItem(mediaItem2, "effect", 12000,
- 3000, EffectColor.TYPE_COLOR, EffectColor.PINK);
- mediaItem2.addEffect(effectColor);
-
- mVideoEditor.removeMediaItem(mediaItem1.getId());
- mVideoEditor.removeMediaItem(mediaItem2.getId());
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export("/sdcard/Test.3gp", MediaProperties.HEIGHT_720,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (IllegalStateException e) {
- flagForException = true;
- }
- assertTrue("Export with MediaItem added and removed", flagForException);
- }
-
- /**
- * To Test Export : With Video and Image : MMS use case
- *
- * @throws Exception
- */
- @LargeTest
- public void testExportMMS() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_1_17.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String videoItemFilename2 = INPUT_FILE_PATH
- + "H264_BP_640x480_12.5fps_256kbps_AACLC_16khz_24kbps_s_0_26.mp4";
- final String maskFilename = INPUT_FILE_PATH + "TransitionSpiral_QVGA.jpg";
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
-
- final MediaVideoItem mediaItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaItem1.setExtractBoundaries(2000, 7000);
- mVideoEditor.addMediaItem(mediaItem1);
-
- final TransitionAlpha transition1 =
- mVideoEditorHelper.createTAlpha("transition1", null, mediaItem1,
- 2000, Transition.BEHAVIOR_LINEAR, maskFilename, 50, true);
- mVideoEditor.addTransition(transition1);
-
- final MediaImageItem mediaItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFilename1, 8000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaItem2);
-
- final MediaVideoItem mediaItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- videoItemFilename2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaItem3.setExtractBoundaries(0, 8000);
- mVideoEditor.addMediaItem(mediaItem3);
-
- final TransitionSliding transition2And3 =
- mVideoEditorHelper.createTSliding("transition2", mediaItem2,
- mediaItem3, 4000, Transition.BEHAVIOR_MIDDLE_FAST,
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN);
- mVideoEditor.addTransition(transition2And3);
-
- final TransitionCrossfade transition3 =
- mVideoEditorHelper.createTCrossFade("transition3", mediaItem3, null,
- 3500, Transition.BEHAVIOR_MIDDLE_SLOW);
- mVideoEditor.addTransition(transition3);
-
- final EffectColor effectColor =
- mVideoEditorHelper.createEffectItem(mediaItem2, "effect", 0,
- 3000, EffectColor.TYPE_COLOR, EffectColor.PINK);
- mediaItem2.addEffect(effectColor);
-
- mVideoEditor.setAspectRatio(MediaProperties.ASPECT_RATIO_11_9);
-
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_144,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- final long storyBoardDuration = mediaItem1.getTimelineDuration()
- + mediaItem2.getTimelineDuration() + mediaItem3.getTimelineDuration()
- - transition2And3.getDuration();
-
- mVideoEditorHelper.validateExport(mVideoEditor, outFilename,
- MediaProperties.HEIGHT_144, 0, storyBoardDuration,
- MediaProperties.VCODEC_H264, MediaProperties.ACODEC_AAC_LC);
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
- }
-
- /**
- * To Test Export :Media Item having duration of 1 Hour
- *
- * @throws Exception
- */
- @Suppress
- @LargeTest
- public void testExportDuration1Hour() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH +
- "H264_BP_640x480_15fps_384kbps_60_0.mp4";
- final String outFilename = mVideoEditorHelper.createRandomFile(
- mVideoEditor.getPath() + "/") + ".3gp";
-
- final MediaVideoItem mediaItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaItem1);
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_144,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- }catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- mVideoEditorHelper.validateExport(mVideoEditor, outFilename,
- MediaProperties.HEIGHT_720, 0, mediaItem1.getDuration(),
- MediaProperties.VCODEC_H264, MediaProperties.ACODEC_AAC_LC);
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
- }
-
- /**
- * To Test Export : Storage location having very less space (Less than 100
- * KB)
- *
- * @throws Exception
- */
- @LargeTest
- public void testExportWithStorageFull() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH
- + "H264_BP_640x480_12.5fps_256kbps_AACLC_16khz_24kbps_s_0_26.mp4";
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
- boolean flagForException = false;
-
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1", videoItemFilename1,
- MediaItem.RENDERING_MODE_BLACK_BORDER);
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_144,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (Exception e) {
- flagForException = true;
- }
- assertTrue("Error in exporting file due to lack of storage space",
- flagForException);
- }
-
- /**
- * To Test Export :Two Media Items added
- *
- * @throws Exception
- */
- @LargeTest
- public void testExportTwoVideos() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_1_17.3gp";
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_640x480_12.5fps_256kbps_AACLC_16khz_24kbps_s_0_26.mp4";
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- videoItemFileName1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- try {
- final int[] progressUpdate = new int[100];
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_720,
- MediaProperties.BITRATE_800K, new ExportProgressListener() {
- int i = 0;
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- } catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- mVideoEditorHelper.validateExport(mVideoEditor, outFilename,
- MediaProperties.HEIGHT_720, 0,
- (mediaVideoItem.getDuration()+ mediaVideoItem1.getDuration()),
- MediaProperties.VCODEC_H264, MediaProperties.ACODEC_AAC_LC);
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
- }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java
deleted file mode 100644
index 7965b0a..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java
+++ /dev/null
@@ -1,1156 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.functional.videoeditor;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.Semaphore;
-
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.media.videoeditor.AudioTrack;
-import android.media.videoeditor.Effect;
-import android.media.videoeditor.EffectColor;
-import android.media.videoeditor.EffectKenBurns;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.videoeditor.MediaProperties;
-import android.media.videoeditor.MediaVideoItem;
-import android.media.videoeditor.Overlay;
-import android.media.videoeditor.OverlayFrame;
-import android.media.videoeditor.Transition;
-import android.media.videoeditor.TransitionAlpha;
-import android.media.videoeditor.TransitionCrossfade;
-import android.media.videoeditor.TransitionFadeBlack;
-import android.media.videoeditor.TransitionSliding;
-import android.media.videoeditor.VideoEditor;
-import android.media.videoeditor.VideoEditor.ExportProgressListener;
-import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
-import android.media.videoeditor.VideoEditor.PreviewProgressListener;
-import android.media.videoeditor.VideoEditor.OverlayData;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase;
-import android.view.SurfaceHolder;
-
-
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.mediaframeworktest.VideoEditorHelper;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
-import java.util.concurrent.TimeUnit;
-
-import android.util.Log;
-
-public class VideoEditorPreviewTest extends
- ActivityInstrumentationTestCase<MediaFrameworkTest> {
- private final String TAG = "VideoEditorTest";
-
- private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
-
- private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
-
- private final String PROJECT_CLASS_NAME =
- "android.media.videoeditor.VideoEditorImpl";
-
- private VideoEditor mVideoEditor;
-
- private VideoEditorHelper mVideoEditorHelper;
-
- private class EventHandler extends Handler {
- public EventHandler( Looper lp)
- {
- super(lp);
- }
- public void handleMessage(Message msg)
- {
- switch (msg.what)
- {
- default:
- MediaFrameworkTest.testInvalidateOverlay();
- }
- }
- }
- private EventHandler mEventHandler;
-
- private boolean previewStart;
- private boolean previewStop;
- private boolean previewError;
-
- /* Minimum waiting time for Semaphore to wait for release */
- private final long minWaitingTime = 3000;
-
- // Declares the annotation for Preview Test Cases
- public @interface Preview {
- }
-
- public VideoEditorPreviewTest() {
- super("com.android.mediaframeworktest", MediaFrameworkTest.class);
-
- Looper looper;
- if ((looper = Looper.myLooper()) != null) {
- mEventHandler = new EventHandler(looper);
-
- } else {
- //Handle error when looper can not be created.
- ;
- }
- }
-
- @Override
- protected void setUp() throws Exception {
- // setup for each test case.
- super.setUp();
- mVideoEditorHelper = new VideoEditorHelper();
- // Create a random String which will be used as project path, where all
- // project related files will be stored.
- final String projectPath =
- mVideoEditorHelper.createRandomFile(PROJECT_LOCATION);
- mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
- // Clean the directory created as project path
- mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
- System.gc();
- super.tearDown();
- }
-
- protected void setPreviewStart() {
- previewStart = true;
- }
- protected void setPreviewStop() {
- previewStop = true;
- }
- protected void setPreviewError() {
- previewError = true;
- }
- protected void validatePreviewProgress(int startMs, int endMs,
- boolean loop, long duration) throws Exception {
-
- final int[] progressUpdate = new int[100];
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
- previewStart = false;
- previewStop = false;
- previewError = false;
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- int i = 0;
- public void onProgress(Object item, int action, int progress) {
- progressUpdate[i++] = progress;
- }
- });
- mVideoEditorHelper.checkProgressCBValues(progressUpdate);
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
-
- long waitingTime = minWaitingTime;
- if (endMs == -1) {
- waitingTime += duration;
- }
- else {
- waitingTime += (endMs - startMs);
- }
- blockTillPreviewCompletes.acquire();
- try {
- mVideoEditor.startPreview(surfaceHolder, startMs, endMs, loop, 1,
- new PreviewProgressListener() {
- public void onProgress(VideoEditor videoEditor, long timeMs,
- OverlayData overlayData) {
-
- if ( overlayData != null) {
- if(overlayData.needsRendering()) {
- overlayData.renderOverlay(MediaFrameworkTest.mDestBitmap);
- mEventHandler.sendMessage(mEventHandler.obtainMessage(1, 2, 3));
- }
- }
- }
- public void onStart(VideoEditor videoEditor) {
- setPreviewStart();
- }
- public void onStop(VideoEditor videoEditor) {
- setPreviewStop();
- blockTillPreviewCompletes.release();
- }
- public void onError(VideoEditor videoEditor, int error) {
- setPreviewError();
- blockTillPreviewCompletes.release();
- }
- });
- } catch (Exception e) {
- blockTillPreviewCompletes.release();
- }
- blockTillPreviewCompletes.tryAcquire(waitingTime, TimeUnit.MILLISECONDS);
-
- mVideoEditor.stopPreview();
- assertTrue("Preview Failed to start", previewStart);
- assertTrue("Preview Failed to stop", previewStop);
- assertFalse("Preview Error occurred", previewError);
-
- blockTillPreviewCompletes.release();
- }
-
- // -----------------------------------------------------------------
- // Preview
- // -----------------------------------------------------------------
-
- /**
- *To test Preview : FULL Preview of current work (beginning till end)
- */
- @LargeTest
- public void testPreviewTheStoryBoard() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH
- + "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
- final String videoItemFileName2 = INPUT_FILE_PATH
- + "MPEG4_SP_640x480_15fps_256kbps_0_30.mp4";
- final String videoItemFileName3 = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_1_17.3gp";
- previewStart = false;
- previewStop = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem2",
- videoItemFileName2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem2);
- mediaVideoItem2.setExtractBoundaries(0, 10000);
-
- final MediaVideoItem mediaVideoItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem3",
- videoItemFileName3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem3.setExtractBoundaries(0, 10000);
-
- mVideoEditor.insertMediaItem(mediaVideoItem3, mediaVideoItem1.getId());
- List<MediaItem> mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item 1", mediaVideoItem1, mediaList.get(0));
- assertEquals("Media Item 3", mediaVideoItem3, mediaList.get(1));
- assertEquals("Media Item 2", mediaVideoItem2, mediaList.get(2));
-
- mediaVideoItem1.setRenderingMode(MediaItem.RENDERING_MODE_BLACK_BORDER);
- assertEquals("Media Item 1 Rendering Mode",
- MediaItem.RENDERING_MODE_BLACK_BORDER,
- mediaVideoItem1.getRenderingMode());
-
- mediaVideoItem2.setRenderingMode(MediaItem.RENDERING_MODE_BLACK_BORDER);
- assertEquals("Media Item 2 Rendering Mode",
- MediaItem.RENDERING_MODE_BLACK_BORDER,
- mediaVideoItem2.getRenderingMode());
-
- mediaVideoItem3.setRenderingMode(MediaItem.RENDERING_MODE_STRETCH);
- assertEquals("Media Item 3 Rendering Mode",
- MediaItem.RENDERING_MODE_STRETCH,
- mediaVideoItem3.getRenderingMode());
-
- mVideoEditor.setAspectRatio(MediaProperties.ASPECT_RATIO_5_3);
- assertEquals("Aspect Ratio", MediaProperties.ASPECT_RATIO_5_3,
- mVideoEditor.getAspectRatio());
-
- validatePreviewProgress(0, -1, false, mVideoEditor.getDuration());
- }
-
- /**
- * To test Preview : Preview of start + 10 sec till end of story board
- */
- @LargeTest
- public void testPreviewTheStoryBoardFromDuration() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH
- + "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
- final String videoItemFileName2 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_256kbps_0_30.mp4";
- final String videoItemFileName3 = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_1_17.3gp";
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
- previewStart = false;
- previewStop = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem2",
- videoItemFileName2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem2.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final MediaVideoItem mediaVideoItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem3",
- videoItemFileName3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem3.setExtractBoundaries(0, 10000);
-
- mVideoEditor.insertMediaItem(mediaVideoItem3, mediaVideoItem1.getId());
-
- List<MediaItem> mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item 1", mediaVideoItem1, mediaList.get(0));
- assertEquals("Media Item 3", mediaVideoItem3, mediaList.get(1));
- assertEquals("Media Item 2", mediaVideoItem2, mediaList.get(2));
- mediaVideoItem1.setRenderingMode(MediaItem.RENDERING_MODE_BLACK_BORDER);
-
- assertEquals("Media Item 1 Rendering Mode",
- MediaItem.RENDERING_MODE_BLACK_BORDER,
- mediaVideoItem1.getRenderingMode());
- mediaVideoItem2.setRenderingMode(MediaItem.RENDERING_MODE_BLACK_BORDER);
-
- assertEquals("Media Item 2 Rendering Mode",
- MediaItem.RENDERING_MODE_BLACK_BORDER,
- mediaVideoItem2.getRenderingMode());
- mediaVideoItem3.setRenderingMode(MediaItem.RENDERING_MODE_STRETCH);
-
- assertEquals("Media Item 3 Rendering Mode",
- MediaItem.RENDERING_MODE_STRETCH,
- mediaVideoItem3.getRenderingMode());
-
- mVideoEditor.setAspectRatio(MediaProperties.ASPECT_RATIO_5_3);
- assertEquals("Aspect Ratio", MediaProperties.ASPECT_RATIO_5_3,
- mVideoEditor.getAspectRatio());
-
- validatePreviewProgress(10000, -1, false, mVideoEditor.getDuration());
- }
-
- /**
- * To test Preview : Preview of current Effects applied
- */
- @LargeTest
- public void testPreviewOfEffects() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
-
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
- previewStart = false;
- previewStop = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "mediaVideoItem1",
- videoItemFileName1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final EffectColor effectNegative =
- mVideoEditorHelper.createEffectItem(mediaVideoItem1,
- "effectNegative", 0, 2000, EffectColor.TYPE_NEGATIVE, 0);
- mediaVideoItem1.addEffect(effectNegative);
-
- final EffectColor effectGreen =
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "effectGreen",
- 2000, 3000, EffectColor.TYPE_COLOR, EffectColor.GREEN);
- mediaVideoItem1.addEffect(effectGreen);
-
- final EffectColor effectFifties =
- mVideoEditorHelper.createEffectItem(mediaVideoItem1,
- "effectFifties", 5000, 4000, EffectColor.TYPE_FIFTIES, 0);
- mediaVideoItem1.addEffect(effectFifties);
-
- List<Effect> effectList = mediaVideoItem1.getAllEffects();
- assertEquals("Effect List Size", 3, effectList.size());
- assertEquals("Effect negative", effectNegative, effectList.get(0));
- assertEquals("Effect Green", effectGreen, effectList.get(1));
- assertEquals("Effect Fifties", effectFifties, effectList.get(2));
-
- mVideoEditor.setAspectRatio(MediaProperties.ASPECT_RATIO_4_3);
- assertEquals("Aspect Ratio", MediaProperties.ASPECT_RATIO_4_3,
- mVideoEditor.getAspectRatio());
-
- final long storyboardDuration = mVideoEditor.getDuration() ;
- validatePreviewProgress(0, (int)(storyboardDuration/2), false, (storyboardDuration/2));
-
- assertEquals("Removing Effect : Negative", effectNegative,
- mediaVideoItem1.removeEffect(effectNegative.getId()));
-
- effectList = mediaVideoItem1.getAllEffects();
-
- assertEquals("Effect List Size", 2, effectList.size());
- assertEquals("Effect Green", effectGreen, effectList.get(0));
- assertEquals("Effect Fifties", effectFifties, effectList.get(1));
-
- validatePreviewProgress(0, -1, false, mVideoEditor.getDuration());
- }
-
- /**
- *To test Preview : Preview of current Transitions applied (with multiple
- * generatePreview)
- */
- @LargeTest
- public void testPreviewWithTransition() throws Exception {
-
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H263_profile0_176x144_10fps_96kbps_0_25.3gp";
- final String imageItemFileName1 = INPUT_FILE_PATH +
- "IMG_1600x1200.jpg";
- final String videoItemFileName2 = INPUT_FILE_PATH +
- "MPEG4_SP_800x480_515kbps_15fps_AMR_NB_8KHz_12.2kbps_m_0_26.mp4";
- final String maskFilename = INPUT_FILE_PATH +
- "TransitionSpiral_QVGA.jpg";
- previewStart = false;
- previewStop = false;
- previewError = false;
-
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFileName1, 10000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- videoItemFileName2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem2.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final TransitionCrossfade transition1And2CrossFade =
- mVideoEditorHelper.createTCrossFade("transition_1_2_CF",
- mediaVideoItem1, mediaImageItem1, 2000,
- Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(transition1And2CrossFade);
-
- final TransitionAlpha transition2And3Alpha =
- mVideoEditorHelper.createTAlpha("transition_2_3", mediaImageItem1,
- mediaVideoItem2, 4000, Transition.BEHAVIOR_SPEED_UP,
- maskFilename, 50, true);
- mVideoEditor.addTransition(transition2And3Alpha);
-
- final TransitionFadeBlack transition1FadeBlack =
- mVideoEditorHelper.createTFadeBlack("transition_1FB", null,
- mediaVideoItem1, 2000, Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(transition1FadeBlack);
-
- List<Transition> transitionList = mVideoEditor.getAllTransitions();
- assertEquals("Transition List Size", 3, transitionList.size());
- assertEquals("Transition 1", transition1And2CrossFade,
- transitionList.get(0));
- assertEquals("Transition 2", transition2And3Alpha, transitionList.get(1));
- assertEquals("Transition 3", transition1FadeBlack, transitionList.get(2));
-
- mVideoEditor.setAspectRatio(MediaProperties.ASPECT_RATIO_3_2);
-
- final int[] progressValues = new int[300];
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- int i = 0;
-
- public void onProgress(Object item, int action, int progress) {
- if (item instanceof TransitionCrossfade) {
- progressValues[i] = progress;
- assertEquals("Object", item, transition1And2CrossFade);
- assertEquals("Action", action,
- MediaProcessingProgressListener.ACTION_ENCODE);
- } else if (item instanceof TransitionAlpha) {
- progressValues[i] = progress;
- assertEquals("Object", item, transition2And3Alpha);
- assertEquals("Action", action,
- MediaProcessingProgressListener.ACTION_ENCODE);
- } else if (item instanceof TransitionFadeBlack) {
- progressValues[i] = progress;
- assertEquals("Object", item, transition1FadeBlack);
- assertEquals("Action", action,
- MediaProcessingProgressListener.ACTION_ENCODE);
- }
- i++;
- }
- });
-
- mVideoEditorHelper.checkProgressCBValues(progressValues);
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
- /* As transition takes more time buffer of 10 sec is added */
- long waitingTime = minWaitingTime + 10000 + 10000;
-
- blockTillPreviewCompletes.acquire();
- try {
- mVideoEditor.startPreview(surfaceHolder, 0, 10000, false, 1,
- new PreviewProgressListener() {
- public void onProgress(VideoEditor videoEditor, long timeMs,
- OverlayData overlayData) {
- }
- public void onStart(VideoEditor videoEditor) {
- setPreviewStart();
- }
- public void onStop(VideoEditor videoEditor) {
- setPreviewStop();
- blockTillPreviewCompletes.release();
- }
- public void onError(VideoEditor videoEditor, int error) {
- setPreviewError();
- blockTillPreviewCompletes.release();
- }
- });
- } catch (Exception e) {
- blockTillPreviewCompletes.release();
- }
- blockTillPreviewCompletes.tryAcquire(waitingTime, TimeUnit.MILLISECONDS);
- mVideoEditor.stopPreview();
- blockTillPreviewCompletes.release();
- assertTrue("Preview Failed to start", previewStart);
- assertTrue("Preview Failed to stop", previewStop);
- assertFalse("Preview Error occurred", previewError);
-
- assertEquals("Removing Transition " + transition1And2CrossFade.getId(),
- transition1And2CrossFade,
- mVideoEditor.removeTransition(transition1And2CrossFade.getId()));
- transitionList = mVideoEditor.getAllTransitions();
- assertEquals("Transition List Size", 2, transitionList.size());
- assertEquals("Transition 1", transition2And3Alpha, transitionList.get(0));
- assertEquals("Transition 2", transition1FadeBlack, transitionList.get(1));
-
- validatePreviewProgress(0, -1, false, mVideoEditor.getDuration());
-
-
- final TransitionSliding transition1And2Sliding =
- mVideoEditorHelper.createTSliding("transition_1_2Sliding",
- mediaVideoItem1, mediaImageItem1, 4000,
- Transition.BEHAVIOR_MIDDLE_FAST,
- TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN);
- mVideoEditor.addTransition(transition1And2Sliding);
-
- transitionList = mVideoEditor.getAllTransitions();
- assertEquals("Transition List Size", 3, transitionList.size());
- assertEquals("Transition 1", transition2And3Alpha, transitionList.get(0));
- assertEquals("Transition 2", transition1FadeBlack, transitionList.get(1));
- assertEquals("Transition 3", transition1And2Sliding,
- transitionList.get(2));
-
- validatePreviewProgress(5000, -1, false, (mVideoEditor.getDuration()));
-
- }
-
- /**
- * To test Preview : Preview of current Overlay applied
- */
- @LargeTest
- public void testPreviewWithOverlay() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
- final String overlayFilename1 = INPUT_FILE_PATH +
- "IMG_640x480_Overlay1.png";
- final String overlayFilename2 = INPUT_FILE_PATH +
- "IMG_640x480_Overlay2.png";
- final int previewFrom = 5000;
- final int previewTo = 10000;
- final boolean previewLoop = false;
- final int previewCallbackFrameCount = 1;
- final int setAspectRatio = MediaProperties.ASPECT_RATIO_4_3;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
- previewStart = false;
- previewStop = false;
- boolean flagForException = false;
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName, renderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem);
- mediaVideoItem.setExtractBoundaries(0, 10000);
-
- final Bitmap mBitmap1 = mVideoEditorHelper.getBitmap(overlayFilename1,
- 640, 480);
- final OverlayFrame overlayOnMvi1 =
- mVideoEditorHelper.createOverlay(mediaVideoItem, "OverlayOnMvi1",
- mBitmap1, 0, 5000);
- mediaVideoItem.addOverlay(overlayOnMvi1);
-
- final Bitmap mBitmap2 = mVideoEditorHelper.getBitmap(overlayFilename2,
- 640, 480);
- final OverlayFrame overlayOnMvi2 =
- mVideoEditorHelper.createOverlay(mediaVideoItem, "OverlayOnMvi2",
- mBitmap2, 5000, 9000);
- mediaVideoItem.addOverlay(overlayOnMvi2);
-
- List<Overlay> overlayList = mediaVideoItem.getAllOverlays();
- assertEquals("Overlay Size", 2, overlayList.size());
- assertEquals("Overlay 1", overlayOnMvi1, overlayList.get(0));
- assertEquals("Overlay 2", overlayOnMvi2, overlayList.get(1));
-
- mVideoEditor.setAspectRatio(setAspectRatio);
-
- validatePreviewProgress(0 /* previewFrom */, -1, previewLoop,
- mVideoEditor.getDuration());
- }
-
- /**
- * To test Preview : Preview of current Trim applied (with default aspect
- * ratio)
- */
- @LargeTest
- public void testPreviewWithTrim() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName, MediaItem.RENDERING_MODE_CROPPING);
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
- boolean flagForException = false;
- previewStart = false;
- previewStop = false;
- mediaVideoItem.setExtractBoundaries(mediaVideoItem.getDuration() / 2,
- mediaVideoItem.getDuration());
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- validatePreviewProgress(1000, -1, false, mVideoEditor.getDuration());
- }
-
- /**
- * To test Preview : Preview of current work having Overlay and Effect
- * applied
- */
-
- @LargeTest
- public void testPreviewWithOverlayEffectKenBurn() throws Exception {
-
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final String overlayFilename = INPUT_FILE_PATH +
- "IMG_640x480_Overlay1.png";
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
- previewStart = false;
- previewStop = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaImageItem mediaImageItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFileName, 10000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem2);
-
- final MediaVideoItem mediaVideoItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- videoItemFileName1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem3);
-
- final EffectColor effectColor =
- mVideoEditorHelper.createEffectItem(mediaVideoItem1, "Effect1",
- 1000, 3000, EffectColor.TYPE_COLOR, EffectColor.GREEN);
- mediaVideoItem1.addEffect(effectColor);
-
- final Rect startRect = new Rect((mediaImageItem2.getHeight() / 3),
- (mediaImageItem2.getWidth() / 3), (mediaImageItem2.getHeight() / 2),
- (mediaImageItem2.getWidth() / 2));
- final Rect endRect = new Rect(0, 0, mediaImageItem2.getWidth(),
- mediaImageItem2.getHeight());
-
- final EffectKenBurns kbeffectOnMI2 = new EffectKenBurns(mediaImageItem2,
- "KBOnM2", startRect, endRect, 0, 10000);
- assertNotNull("EffectKenBurns", kbeffectOnMI2);
- mediaImageItem2.addEffect(kbeffectOnMI2);
-
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFilename,
- 640, 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaVideoItem3, "OverlayID",
- mBitmap, (mediaImageItem2.getDuration() / 4),
- (mediaVideoItem3.getDuration() / 3));
- mediaVideoItem3.addOverlay(overlayFrame);
-
- validatePreviewProgress(5000, -1, false, mVideoEditor.getDuration());
- }
-
- /**
- *To test Preview : Export during preview
- */
- @LargeTest
- public void testPreviewDuringExport() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
- previewStart = false;
- previewStop = false;
- previewError = false;
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- long waitingTime = minWaitingTime + mVideoEditor.getDuration();
-
-
- blockTillPreviewCompletes.acquire();
- final String fileName = mVideoEditor.getPath() + "/test.3gp";
- final int height = MediaProperties.HEIGHT_480;
- final int bitrate = MediaProperties.BITRATE_512K;
-
- try {
- mVideoEditor.export(fileName, height, bitrate,
- new ExportProgressListener() {
- public void onProgress(VideoEditor ve,
- String outFileName,int progress) {
-
- }
- });
- } catch (IOException e) {
- assertTrue("UnExpected Error in Export" +
- e.toString(), false);
- }
-
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
- try {
-
- mVideoEditor.startPreview(surfaceHolder, 5000, -1, false, 1,
- new PreviewProgressListener() {
-
- public void onProgress(VideoEditor videoEditor, long timeMs,
- OverlayData overlayData) {
- }
- public void onStart(VideoEditor videoEditor) {
- setPreviewStart();
- }
- public void onStop(VideoEditor videoEditor) {
- setPreviewStop();
- blockTillPreviewCompletes.release();
- }
- public void onError(VideoEditor videoEditor, int error) {
- setPreviewError();
- blockTillPreviewCompletes.release();
- }
- });
-
- } catch (Exception e) {
- blockTillPreviewCompletes.release();
- }
- blockTillPreviewCompletes.tryAcquire(waitingTime, TimeUnit.MILLISECONDS);
- mVideoEditor.stopPreview();
- assertTrue("Preview Failed to start", previewStart);
- assertTrue("Preview Failed to stop", previewStop);
- assertFalse("Preview Error occurred", previewError);
-
- blockTillPreviewCompletes.release();
- }
-
- /**
- * To test Preview : Preview of current Effects applied (with from time >
- * total duration)
- */
- @LargeTest
- public void testPreviewWithDurationGreaterThanMediaDuration()
- throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_192kbps_1_5.mp4";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- boolean flagForException = false;
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
-
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName, renderingMode);
- try {
- mediaVideoItem1.setExtractBoundaries(0, 20000);
- } catch (Exception e) {
- assertTrue("Exception during setExtract Boundaries", false);
- }
- mVideoEditor.addMediaItem(mediaVideoItem1);
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
- long waitingTime = minWaitingTime + (mVideoEditor.getDuration() - 30000);
- if(waitingTime < 0)
- {
- waitingTime = minWaitingTime;
- }
-
- blockTillPreviewCompletes.acquire();
- try {
- mVideoEditor.startPreview(surfaceHolder, 30000, -1, true, 1,
- new PreviewProgressListener() {
- public void onProgress(VideoEditor videoEditor, long timeMs,
- OverlayData overlayData) {
- }
- public void onStart(VideoEditor videoEditor) {
- setPreviewStart();
- }
- public void onStop(VideoEditor videoEditor) {
- setPreviewStop();
- blockTillPreviewCompletes.release();
- }
- public void onError(VideoEditor videoEditor, int error) {
- setPreviewError();
- blockTillPreviewCompletes.release();
- }
- });
-
- } catch (IllegalArgumentException e) {
- blockTillPreviewCompletes.release();
- flagForException = true;
- }
- blockTillPreviewCompletes.tryAcquire(waitingTime, TimeUnit.MILLISECONDS);
- assertTrue("Expected Error in Preview", flagForException);
- mVideoEditor.stopPreview();
- blockTillPreviewCompletes.release();
- }
-
- /**
- * To test Preview : Preview of current Effects applied (with Render Preview
- * Frame)
- */
- @LargeTest
- public void testPreviewWithRenderPreviewFrame() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final Semaphore blockTillPreviewCompletes = new Semaphore(1);
- boolean flagForException = false;
- OverlayData overlayData1 = new OverlayData();
- previewStart = false;
- previewStop = false;
-
- final String overlayFilename1 = INPUT_FILE_PATH +
- "IMG_640x480_Overlay1.png";
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor,
- "m1", videoItemFileName, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final EffectColor effectPink =
- mVideoEditorHelper.createEffectItem(mediaVideoItem,
- "effectNegativeOnMvi", 1000, 3000, EffectColor.TYPE_COLOR,
- EffectColor.PINK);
- mediaVideoItem.addEffect(effectPink);
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
-
- assertEquals("Render preview Frame at 5 Sec", 5000,
- mVideoEditor.renderPreviewFrame(surfaceHolder, 5000,
- overlayData1));
-
- assertEquals("Render preview Frame at 7 Sec", 7000,
- mVideoEditor.renderPreviewFrame(surfaceHolder, 7000,
- overlayData1));
-
- validatePreviewProgress(5000, -1, false, mVideoEditor.getDuration());
- }
-
- /**
- * To test Preview : Preview of current work from selected jump location
- * till end with Audio Track
- */
- @LargeTest
- public void testPreviewWithEndAudioTrack() throws Exception {
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String imageItemFilename2 = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final String audioFilename = INPUT_FILE_PATH +
- "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
-
- boolean flagForException = false;
- previewStart = false;
- previewStop = false;
- final MediaImageItem mediaImageItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- imageItemFilename1, 7000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem1);
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- videoItemFileName, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem.setExtractBoundaries(1000, 8000);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final MediaImageItem mediaImageItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- imageItemFilename2, 7000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem2);
-
- final AudioTrack audioTrack =
- mVideoEditorHelper.createAudio(mVideoEditor, "a1", audioFilename);
- mVideoEditor.addAudioTrack(audioTrack);
-
- List<AudioTrack> audioList = mVideoEditor.getAllAudioTracks();
- assertEquals("Audio Track List size", 1, audioList.size());
- assertEquals("Audio Track", audioTrack, audioList.get(0));
- mVideoEditor.setAspectRatio(MediaProperties.ASPECT_RATIO_4_3);
-
- validatePreviewProgress(10000, -1, false, mVideoEditor.getDuration());
- }
-
- /**
- * To test render Preview Frame
- */
- @LargeTest
- public void testRenderPreviewFrame() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH
- + "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String videoItemFileName2 = INPUT_FILE_PATH
- + "MPEG4_SP_800x480_515kbps_15fps_AMR_NB_8KHz_12.2kbps_m_0_26.mp4";
- final String videoItemFileName3 = INPUT_FILE_PATH
- + "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String imageItemFilename1 = INPUT_FILE_PATH
- + "IMG_1600x1200.jpg";
- final String imageItemFilename2 = INPUT_FILE_PATH
- + "IMG_176x144.jpg";
- final String audioFilename = INPUT_FILE_PATH
- + "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
- OverlayData overlayData1 = new OverlayData();
- previewStart = false;
- previewStop = false;
- final MediaVideoItem mediaVideoItem1 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFileName1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- videoItemFileName2, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(mediaVideoItem2.getDuration() / 4,
- mediaVideoItem2.getDuration() / 2);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final MediaVideoItem mediaVideoItem3 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m3",
- videoItemFileName3, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem1.setExtractBoundaries(mediaVideoItem2.getDuration() / 2,
- mediaVideoItem2.getDuration());
- mVideoEditor.addMediaItem(mediaVideoItem3);
-
- final MediaImageItem mediaImageItem4 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m4",
- imageItemFilename1, 5000, MediaItem.RENDERING_MODE_BLACK_BORDER);
-
- final MediaImageItem mediaImageItem5 =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m5",
- imageItemFilename2, 5000, MediaItem.RENDERING_MODE_BLACK_BORDER);
-
- List<MediaItem> mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item List Size", 3, mediaList.size());
-
- mVideoEditor.insertMediaItem(mediaImageItem4, mediaVideoItem2.getId());
- mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item List Size", 4, mediaList.size());
- assertEquals("Media item 1", mediaVideoItem1, mediaList.get(0));
- assertEquals("Media item 2", mediaVideoItem2, mediaList.get(1));
- assertEquals("Media item 4", mediaImageItem4, mediaList.get(2));
- assertEquals("Media item 3", mediaVideoItem3, mediaList.get(3));
-
- mVideoEditor.insertMediaItem(mediaImageItem5, mediaImageItem4.getId());
- mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item List Size", 5, mediaList.size());
- assertEquals("Media item 1", mediaVideoItem1, mediaList.get(0));
- assertEquals("Media item 2", mediaVideoItem2, mediaList.get(1));
- assertEquals("Media item 4", mediaImageItem4, mediaList.get(2));
- assertEquals("Media item 5", mediaImageItem5, mediaList.get(3));
- assertEquals("Media item 3", mediaVideoItem3, mediaList.get(4));
-
- mVideoEditor.moveMediaItem(mediaVideoItem1.getId(),
- mediaImageItem5.getId());
- mediaList = mVideoEditor.getAllMediaItems();
- assertEquals("Media Item List Size", 5, mediaList.size());
- assertEquals("Media item 2", mediaVideoItem2, mediaList.get(0));
- assertEquals("Media item 4", mediaImageItem4, mediaList.get(1));
- assertEquals("Media item 5", mediaImageItem5, mediaList.get(2));
- assertEquals("Media item 1", mediaVideoItem1, mediaList.get(3));
- assertEquals("Media item 3", mediaVideoItem3, mediaList.get(4));
-
- final TransitionCrossfade transition2And4CrossFade =
- mVideoEditorHelper.createTCrossFade("transition2And4CrossFade",
- mediaVideoItem2, mediaImageItem4, 2000,
- Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(transition2And4CrossFade);
-
- final TransitionCrossfade transition1And3CrossFade =
- mVideoEditorHelper.createTCrossFade("transition1And3CrossFade",
- mediaVideoItem1, mediaVideoItem3, 5000,
- Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(transition1And3CrossFade);
-
- final AudioTrack audioTrack =
- mVideoEditorHelper.createAudio(mVideoEditor, "a1", audioFilename);
- audioTrack.setExtractBoundaries(0, 2000);
- mVideoEditor.addAudioTrack(audioTrack);
-
- audioTrack.enableLoop();
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
-
- mVideoEditor.renderPreviewFrame(surfaceHolder, mVideoEditor.getDuration()/4, overlayData1);
- Thread.sleep(1000);
- mVideoEditor.renderPreviewFrame(surfaceHolder, mVideoEditor.getDuration()/2, overlayData1);
- Thread.sleep(1000);
- mVideoEditor.renderPreviewFrame(surfaceHolder, mVideoEditor.getDuration(), overlayData1);
-
- }
-
- /**
- * To Test Preview : Without any Media Items in the story Board
- */
- @LargeTest
- public void testStartPreviewWithoutMediaItems() throws Exception {
- boolean flagForException = false;
-
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
- try{
- mVideoEditor.startPreview(surfaceHolder, 0, -1, false, 1,
- new PreviewProgressListener() {
- public void onProgress(VideoEditor videoEditor, long timeMs,
- OverlayData overlayData) {
- }
- public void onStart(VideoEditor videoEditor) {
- setPreviewStart();
- }
- public void onStop(VideoEditor videoEditor) {
- setPreviewStop();
- }
- public void onError(VideoEditor videoEditor, int error) {
- setPreviewError();
- }
- });
- }catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Preview without Media Items", flagForException);
- }
-
- /**
- * To Test Preview : Add Media and Remove Media Item (Without any Media
- * Items in the story Board)
- */
- @LargeTest
- public void testStartPreviewAddRemoveMediaItems() throws Exception {
- final String videoItemFilename1 = INPUT_FILE_PATH
- + "H263_profile0_176x144_15fps_256kbps_AACLC_32kHz_128kbps_s_0_26.3gp";
- final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String alphaFilename = INPUT_FILE_PATH +
- "TransitionSpiral_QVGA.jpg";
- boolean flagForException = false;
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m1",
- videoItemFilename1, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mediaVideoItem.setExtractBoundaries(0, 15000);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final MediaImageItem mediaImageItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor, "m2",
- imageItemFilename1, 15000, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaImageItem);
-
- final TransitionAlpha transition1And2 =
- mVideoEditorHelper.createTAlpha("transition", mediaVideoItem,
- mediaImageItem, 3000, Transition.BEHAVIOR_SPEED_UP,
- alphaFilename, 10, false);
- mVideoEditor.addTransition(transition1And2);
-
- final EffectColor effectColor =
- mVideoEditorHelper.createEffectItem(mediaImageItem, "effect", 5000,
- 3000, EffectColor.TYPE_COLOR, EffectColor.PINK);
- mediaImageItem.addEffect(effectColor);
-
- assertEquals("removing Media item 1", mediaVideoItem,
- mVideoEditor.removeMediaItem(mediaVideoItem.getId()));
- assertEquals("removing Media item 2", mediaImageItem,
- mVideoEditor.removeMediaItem(mediaImageItem.getId()));
-
- try{
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
- mVideoEditor.startPreview(surfaceHolder, 0, -1, false, 1,
- new PreviewProgressListener() {
- public void onProgress(VideoEditor videoEditor, long timeMs,
- OverlayData overlayData) {
- }
- public void onStart(VideoEditor videoEditor) {
- setPreviewStart();
- }
- public void onStop(VideoEditor videoEditor) {
- setPreviewStop();
- }
- public void onError(VideoEditor videoEditor, int error) {
- setPreviewError();
- }
- });
- }catch (IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue("Preview with removed Media Items", flagForException);
-
- }
-
- /**
- * To test Preview : Preview of current Effects applied (with Render Preview
- * Frame)
- */
- @LargeTest
- public void testPreviewWithRenderPreviewFrameWithoutGenerate() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- boolean flagForException = false;
- long duration = 0;
- OverlayData overlayData1 = new OverlayData();
-
- final MediaVideoItem mediaVideoItem =
- mVideoEditorHelper.createMediaItem(mVideoEditor,
- "m1", videoItemFileName, MediaItem.RENDERING_MODE_BLACK_BORDER);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final SurfaceHolder surfaceHolder =
- MediaFrameworkTest.mSurfaceView.getHolder();
- duration = mVideoEditor.getDuration();
- /* RenderPreviewFrame returns -1 to indicate last frame */
- try {
- mVideoEditor.renderPreviewFrame(surfaceHolder, duration,
- overlayData1);
- } catch ( IllegalStateException e) {
- flagForException = true;
- }
- assertTrue (" Render Preview Frame without generate", flagForException);
- duration = mVideoEditor.getDuration() + 1000;
- try {
- mVideoEditor.renderPreviewFrame(surfaceHolder, duration,
- overlayData1);
- } catch ( IllegalArgumentException e) {
- flagForException = true;
- }
- assertTrue (" Preview time greater than duration", flagForException);
- }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java
deleted file mode 100644
index d15a535..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java
+++ /dev/null
@@ -1,1073 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.mediaframeworktest.performance;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.Writer;
-
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.media.videoeditor.AudioTrack;
-import android.media.videoeditor.EffectColor;
-import android.media.videoeditor.EffectKenBurns;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.videoeditor.MediaProperties;
-import android.media.videoeditor.MediaVideoItem;
-import android.media.videoeditor.OverlayFrame;
-import android.media.videoeditor.Transition;
-import android.media.videoeditor.TransitionCrossfade;
-import android.media.videoeditor.TransitionAlpha;
-import android.media.videoeditor.TransitionFadeBlack;
-import android.media.videoeditor.TransitionSliding;
-import android.media.videoeditor.VideoEditor;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase;
-import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
-import android.os.Environment;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase;
-import android.media.videoeditor.VideoEditor.ExportProgressListener;
-
-import android.util.Log;
-
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.mediaframeworktest.VideoEditorHelper;
-
-/**
- * Junit / Instrumentation - performance measurement for media player and
- * recorder
- */
-public class VideoEditorPerformance extends
- ActivityInstrumentationTestCase<MediaFrameworkTest> {
-
- private final String TAG = "VideoEditorPerformance";
-
- private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
-
- private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
-
- private final String VIDEOEDITOR_OUTPUT = PROJECT_LOCATION +
- "VideoEditorPerformance.txt";
-
- public VideoEditorPerformance() {
- super("com.android.mediaframeworktest", MediaFrameworkTest.class);
- }
-
- private final String PROJECT_CLASS_NAME =
- "android.media.videoeditor.VideoEditorImpl";
- private VideoEditor mVideoEditor;
- private VideoEditorHelper mVideoEditorHelper;
-
- @Override
- protected void setUp() throws Exception {
- // setup for each test case.
- super.setUp();
- mVideoEditorHelper = new VideoEditorHelper();
- // Create a random String which will be used as project path, where all
- // project related files will be stored.
- final String projectPath =
- mVideoEditorHelper.createRandomFile(PROJECT_LOCATION);
- mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
- // Clean the directory created as project path
- mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
- System.gc();
- super.tearDown();
- }
-
- private void writeTimingInfo(String testCaseName, String[] information)
- throws Exception {
- File outFile = new File(VIDEOEDITOR_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(outFile, true));
- output.write(testCaseName + "\n\t");
- for (int i = 0; i < information.length; i++) {
- output.write(information[i]);
- }
- output.write("\n\n");
- output.close();
- }
-
- private final int NUM_OF_ITERATIONS=20;
-
- private int calculateTimeTaken(long beginTime, int numIterations)
- throws Exception {
- final long duration2 = SystemClock.uptimeMillis();
- final long durationToCreateMediaItem = (duration2 - beginTime);
- final int timeTaken1 = (int)(durationToCreateMediaItem / numIterations);
- return (timeTaken1);
- }
-
- private void createVideoItems(MediaVideoItem[] mediaVideoItem,
- String videoItemFileName, int renderingMode, int startTime, int endTime) throws Exception {
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- try {
- mediaVideoItem[i] = new MediaVideoItem(mVideoEditor, "m" + i,
- videoItemFileName, renderingMode);
- mediaVideoItem[i].setExtractBoundaries(startTime, endTime);
- } catch (Exception e1) {
- assertTrue(
- "Can not create an object of Video Item with file name = "
- + videoItemFileName + "------ID:m" + i + " Issue = "
- + e1.toString(), false);
- }
- }
- }
-
- private void addVideoItems(MediaVideoItem[] mediaVideoItem) throws Exception {
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- try {
- mVideoEditor.addMediaItem(mediaVideoItem[i]);
- } catch (Exception e1) {
- assertTrue(
- "Can not add an object of Video Item with ID:m" + i +
- " Issue = " + e1.toString(), false);
- }
- }
- }
-
- private void removeVideoItems(MediaVideoItem[] mediaVideoItem) throws Exception {
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- try {
- mVideoEditor.removeMediaItem(mediaVideoItem[i].getId());
- } catch (Exception e1) {
- assertTrue(
- "Can not Remove an object of Video Item with ID:m" + i +
- " Issue = " + e1.toString(), false);
- }
- }
- }
-
- private void createImageItems(MediaImageItem[] mIi,
- String imageItemFileName, int renderingMode, int duration) throws Exception {
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- try {
- mIi[i] = new MediaImageItem(mVideoEditor, "m" + i,
- imageItemFileName, duration, renderingMode);
- } catch (Exception e1) {
- assertTrue( " Cannot create Image Item", false);
- }
- }
- }
-
- private void addImageItems(MediaImageItem[] mIi) throws Exception {
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- try {
- mVideoEditor.addMediaItem(mIi[i]);
- } catch (Exception e1) {
- assertTrue("Cannot add Image item", false);
- }
- }
- }
-
- private void removeImageItems(MediaImageItem[] mIi) throws Exception {
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- try {
- mVideoEditor.removeMediaItem(mIi[i].getId());
- } catch (Exception e1) {
- assertTrue("Cannot remove image item", false);
- }
- }
- }
- /**
- * To test the performance of adding and removing the video media item
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceAddRemoveVideoItem() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final int videoItemStartTime = 0;
- final int videoItemEndTime = 5000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String[] loggingInfo = new String[3];
- final MediaVideoItem[] mediaVideoItem =
- new MediaVideoItem[NUM_OF_ITERATIONS];
- int timeTaken = 0;
- long startTime = 0;
-
- /** Time Take for creation of Media Video Item */
- startTime = SystemClock.uptimeMillis();
- createVideoItems(mediaVideoItem, videoItemFileName, renderingMode,
- videoItemStartTime, videoItemEndTime);
-
- timeTaken = calculateTimeTaken (startTime, NUM_OF_ITERATIONS);
- loggingInfo[0] = "Time taken to Create Media Video Item :" +
- timeTaken;
-
- /** Time Take for Addition of Media Video Item */
- startTime = SystemClock.uptimeMillis();
- addVideoItems(mediaVideoItem);
- timeTaken = calculateTimeTaken (startTime, NUM_OF_ITERATIONS);
- loggingInfo[1] = "\n\tTime taken to Add Media Video Item :"
- + timeTaken;
-
- /** Time Take for Removal of Media Video Item */
- startTime = SystemClock.uptimeMillis();
- removeVideoItems(mediaVideoItem);
- timeTaken = calculateTimeTaken (startTime, NUM_OF_ITERATIONS);
- loggingInfo[2] = "\n\tTime taken to remove Media Video Item :"
- + timeTaken;
-
- writeTimingInfo("testPerformanceAddRemoveVideoItem (in mSec)", loggingInfo);
- }
-
- /**
- * To test the performance of adding and removing the image media item
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceAddRemoveImageItem() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final int imageItemDuration = 0;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String[] loggingInfo = new String[3];
- final MediaImageItem[] mediaImageItem =
- new MediaImageItem[NUM_OF_ITERATIONS];
- int timeTaken = 0;
-
- long beginTime = SystemClock.uptimeMillis();
- createImageItems(mediaImageItem, imageItemFileName, renderingMode,
- imageItemDuration);
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[0] = "Time taken to Create Media Image Item :" +
- timeTaken;
-
- beginTime = SystemClock.uptimeMillis();
- addImageItems(mediaImageItem);
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[1] = "\n\tTime taken to add Media Image Item :" +
- timeTaken;
-
- beginTime = SystemClock.uptimeMillis();
- removeImageItems(mediaImageItem);
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[2] = "\n\tTime taken to remove Media Image Item :"
- + timeTaken;
-
- writeTimingInfo("testPerformanceAddRemoveImageItem (in mSec)",
- loggingInfo);
- }
-
- /**
- * To test the performance of adding and removing the transition
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceAddRemoveTransition() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final int videoItemStartTime1 = 0;
- final int videoItemEndTime1 = 20000;
- final String videoItemFileName2 = INPUT_FILE_PATH
- + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final int videoItemStartTime2 = 0;
- final int videoItemEndTime2 = 20000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int transitionDuration = 5000;
- final int transitionBehavior = Transition.BEHAVIOR_MIDDLE_FAST;
- final String[] loggingInfo = new String[3];
- int timeTaken = 0;
-
- final MediaVideoItem[] mediaVideoItem =
- new MediaVideoItem[(NUM_OF_ITERATIONS *10) + 1];
-
- for (int i = 0; i < (NUM_OF_ITERATIONS *10); i+=2) {
- try {
- mediaVideoItem[i] = new MediaVideoItem(mVideoEditor, "m" + i,
- videoItemFileName1, renderingMode);
- mediaVideoItem[i+1] = new MediaVideoItem(mVideoEditor,
- "m" + (i+1), videoItemFileName2, renderingMode);
- mediaVideoItem[i].setExtractBoundaries(videoItemStartTime1,
- videoItemEndTime1);
- mediaVideoItem[i+1].setExtractBoundaries(videoItemStartTime2,
- videoItemEndTime2);
- } catch (Exception e1) {
- assertTrue("Can not create Video Object Item with file name = "
- + e1.toString(), false);
- }
- mVideoEditor.addMediaItem(mediaVideoItem[i]);
- mVideoEditor.addMediaItem(mediaVideoItem[i+1]);
- }
- mediaVideoItem[(NUM_OF_ITERATIONS *10)] = new MediaVideoItem(mVideoEditor,
- "m" + (NUM_OF_ITERATIONS *10), videoItemFileName1, renderingMode);
- mediaVideoItem[(NUM_OF_ITERATIONS *10)].setExtractBoundaries(
- videoItemStartTime1, videoItemEndTime1);
- mVideoEditor.addMediaItem(mediaVideoItem[(NUM_OF_ITERATIONS *10)]);
- final TransitionCrossfade tranCrossfade[] =
- new TransitionCrossfade[(NUM_OF_ITERATIONS *10)];
-
- long beginTime = SystemClock.uptimeMillis();
- for (int i = 0; i < (NUM_OF_ITERATIONS *10); i++) {
- tranCrossfade[i] = new TransitionCrossfade("transition" + i,
- mediaVideoItem[i], mediaVideoItem[i+1], transitionDuration,
- transitionBehavior);
- }
- timeTaken = calculateTimeTaken(beginTime, (NUM_OF_ITERATIONS * 10));
- loggingInfo[0] = "Time taken to Create CrossFade Transition :" +
- timeTaken;
-
- beginTime = SystemClock.uptimeMillis();
- for (int i = 0; i < (NUM_OF_ITERATIONS *10); i++) {
- mVideoEditor.addTransition(tranCrossfade[i]);
- }
- timeTaken = calculateTimeTaken(beginTime, (NUM_OF_ITERATIONS * 10));
- loggingInfo[1] = "\n\tTime taken to add CrossFade Transition :" +
- timeTaken;
-
- beginTime = SystemClock.uptimeMillis();
- for (int i = 0; i < (NUM_OF_ITERATIONS *10); i++) {
- assertEquals("Removing Transitions", tranCrossfade[i], mVideoEditor
- .removeTransition(tranCrossfade[i].getId()));
- }
- timeTaken = calculateTimeTaken(beginTime, (NUM_OF_ITERATIONS * 10));
- loggingInfo[2] = "\n\tTime taken to remove CrossFade Transition :" +
- timeTaken;
-
- writeTimingInfo("testPerformanceAddRemoveTransition (in mSec)", loggingInfo);
- }
-
- /**
- * To test performance of Export
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceExport() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int outHeight = MediaProperties.HEIGHT_480;
- final int outBitrate = MediaProperties.BITRATE_256K;
- final int outVcodec = MediaProperties.VCODEC_H264;
- final String[] loggingInfo = new String[1];
- final String outFilename = mVideoEditorHelper
- .createRandomFile(mVideoEditor.getPath() + "/") + ".3gp";
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_12Mbps_AACLC_44.1khz_64kbps_s_1_17.mp4";
- final String imageItemFileName1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg";
- final String videoItemFileName2 = INPUT_FILE_PATH +
- "H264_BP_640x480_15fps_1200Kbps_AACLC_48KHz_32kbps_m_1_17.3gp";
- final String imageItemFileName2 = INPUT_FILE_PATH + "IMG_176x144.jpg";
- final String videoItemFileName3 = INPUT_FILE_PATH +
- "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_161kbps_s_0_26.mp4";
- final String overlayFile = INPUT_FILE_PATH + "IMG_640x480_Overlay1.png";
- final String audioTrackFilename = INPUT_FILE_PATH +
- "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
- final String maskFilename = INPUT_FILE_PATH +
- "TransitionSpiral_QVGA.jpg";
-
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1", videoItemFileName1, renderingMode);
- mediaItem1.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaItem1);
-
- final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
- "m2", imageItemFileName1, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
-
- final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
- "m3", videoItemFileName2, renderingMode);
- mediaItem3.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaItem3);
-
- final MediaImageItem mediaItem4 = new MediaImageItem(mVideoEditor,
- "m4", imageItemFileName2, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem4);
-
- final MediaVideoItem mediaItem5 = new MediaVideoItem(mVideoEditor,
- "m5", videoItemFileName3, renderingMode);
- mediaItem5.setExtractBoundaries(0, 20000);
- mVideoEditor.addMediaItem(mediaItem5);
- /**
- * 7.Add TransitionAlpha, Apply this Transition as Begin for Media Item 1
- * with duration = 2 sec behavior = BEHAVIOR_LINEAR, mask file name =
- * TransitionSpiral_QVGA.jpg , blending percent = 50%, invert = true;
- * */
- final TransitionAlpha transition1 =
- mVideoEditorHelper.createTAlpha("transition1", null, mediaItem1,
- 2000, Transition.BEHAVIOR_LINEAR, maskFilename, 50, true);
- mVideoEditor.addTransition(transition1);
-
- /**
- * 8.Add Transition Sliding between MediaItem 2 and 3 ,
- * Sliding Direction = DIRECTION_RIGHT_OUT_LEFT_IN,
- * behavior = BEHAVIOR_MIDDLE_FAST and duration = 4sec
- * */
- final TransitionSliding transition2And3 =
- mVideoEditorHelper.createTSliding("transition2", mediaItem2,
- mediaItem3, 4000, Transition.BEHAVIOR_MIDDLE_FAST,
- TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN);
- mVideoEditor.addTransition(transition2And3);
-
- /**
- * 9.Add Transition Crossfade between Media Item 3 and 4,
- * behavior = BEHAVIOR_MIDDLE_SLOW, duration = 3.5 sec
- * */
- final TransitionCrossfade transition3And4 =
- mVideoEditorHelper.createTCrossFade("transition3", mediaItem3,
- mediaItem4, 3500, Transition.BEHAVIOR_MIDDLE_SLOW);
- mVideoEditor.addTransition(transition3And4);
-
- /**
- * 10.Add Transition Fadeblack between Media Item 4 and 5,
- * behavior = BEHAVIOR_SPEED_DOWN, duration = 3.5 sec
- * */
- final TransitionFadeBlack transition4And5 =
- mVideoEditorHelper.createTFadeBlack("transition4", mediaItem4,
- mediaItem5, 3500, Transition.BEHAVIOR_SPEED_DOWN);
- mVideoEditor.addTransition(transition4And5);
-
- /**
- * 11.Add Effect 1 type="TYPE_SEPIA" to the MediaItem 1,
- * start time=1sec and duration =4secs
- * */
- final EffectColor effectColor1 = mVideoEditorHelper.createEffectItem(
- mediaItem1, "effect1", 1000, 4000, EffectColor.TYPE_SEPIA, 0);
- mediaItem1.addEffect(effectColor1);
-
- /**
- * 12.Add Overlay 1 to the MediaItem 3: Frame Overlay with start time = 1 sec
- * duration = 4 sec with item = IMG_640x480_Overlay1.png
- * */
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFile, 640,
- 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaItem3, "overlay",
- mBitmap, 1000, 4000);
- mediaItem3.addOverlay(overlayFrame);
- /**
- * 13.Add Effect 2 type="TYPE_NEGATIVE" to the MediaItem 2,
- * start time=8sec and duration =2secs
- * */
- final EffectColor effectColor2 = mVideoEditorHelper.createEffectItem(
- mediaItem2, "effect2", 8000, 2000, EffectColor.TYPE_NEGATIVE, 0);
- mediaItem2.addEffect(effectColor2);
- /**
- * 14.Add Effect 3 type="TYPE_COLOR" to the MediaItem 3, color param = "PINK",
- * start time=5 sec and duration =3secs
- * */
- final EffectColor effectColor3 = mVideoEditorHelper.createEffectItem(
- mediaItem3, "effect3", 5000, 3000, EffectColor.TYPE_COLOR,
- EffectColor.PINK);
- mediaItem3.addEffect(effectColor3);
- /**
- * 15.Add Effect 4 type="TYPE_FIFTIES" to the MediaItem 4,
- * start time=2 sec and duration =1secs
- * */
- final EffectColor effectColor4 = mVideoEditorHelper.createEffectItem(
- mediaItem4, "effect4", 2000, 1000, EffectColor.TYPE_FIFTIES, 0);
- mediaItem4.addEffect(effectColor4);
- /**
- * 16.Add KenBurnsEffect for MediaItem 4 with
- * duration = 3 sec and startTime = 4 sec
- * StartRect
- * left = org_height/3 ; top = org_width/3
- * bottom = org_width/2 ; right = org_height/2
- * EndRect
- * left = 0 ; top = 0
- * bottom = org_height; right = org_width
- * */
-
- final Rect startRect = new Rect((mediaItem4.getHeight() / 3),
- (mediaItem4.getWidth() / 3), (mediaItem4.getHeight() / 2),
- (mediaItem4.getWidth() / 2));
- final Rect endRect = new Rect(0, 0, mediaItem4.getWidth(),
- mediaItem4.getHeight());
- final EffectKenBurns kbEffectOnMediaItem = new EffectKenBurns(
- mediaItem4, "KBOnM2", startRect, endRect,4000 , 3000);
- mediaItem4.addEffect(kbEffectOnMediaItem);
-
- /** 17.Add Audio Track,Set extract boundaries o to 10 sec.
- * */
- final AudioTrack audioTrack = mVideoEditorHelper.createAudio(
- mVideoEditor, "audioTrack", audioTrackFilename);
- mVideoEditor.addAudioTrack(audioTrack);
- /** 18.Enable Looping for Audio Track.
- * */
- audioTrack.enableLoop();
- int timeTaken = 0;
- final long beginTime = SystemClock.uptimeMillis();
- try {
- mVideoEditor.export(outFilename, outHeight, outBitrate,
- new ExportProgressListener() {
- public void onProgress(VideoEditor ve,
- String outFileName, int progress) {
- }
- });
- } catch (Exception e) {
- assertTrue("Error in Export" + e.toString(), false);
- }
- mVideoEditorHelper.checkDeleteExistingFile(outFilename);
-
- timeTaken = calculateTimeTaken(beginTime, 1);
- loggingInfo[0] = "Time taken to do ONE export of storyboard duration "
- + mVideoEditor.getDuration() + " is :" + timeTaken;
-
- writeTimingInfo("testPerformanceExport (in mSec)", loggingInfo);
- mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
- }
-
-
- /**
- * To test the performance of thumbnail extraction
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceThumbnailVideoItem() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final int videoItemStartTime = 0;
- final int videoItemEndTime = 20000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String[] loggingInfo = new String[1];
-
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "m1", videoItemFileName, renderingMode);
- mediaVideoItem.setExtractBoundaries(videoItemStartTime,
- videoItemEndTime);
-
- int timeTaken = 0;
- long beginTime = SystemClock.uptimeMillis();
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- mediaVideoItem.getThumbnail(mediaVideoItem.getWidth() / 2,
- mediaVideoItem.getHeight() / 2, i);
- }
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[0] = "Duration taken to get Video Thumbnails :" +
- timeTaken;
-
- writeTimingInfo("testPerformanceThumbnailVideoItem (in mSec)", loggingInfo);
- }
-
- /**
- * To test the performance of adding and removing the overlay to media item
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceOverlayVideoItem() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final int videoItemStartTime1 = 0;
- final int videoItemEndTime1 = 10000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String overlayFilename = INPUT_FILE_PATH
- + "IMG_640x480_Overlay1.png";
- final int overlayStartTime = 1000;
- final int overlayDuration = 5000;
-
- final String[] loggingInfo = new String[2];
- MediaVideoItem mediaVideoItem = null;
-
- try {
- mediaVideoItem = new MediaVideoItem(mVideoEditor, "m0",
- videoItemFileName1, renderingMode);
- mediaVideoItem.setExtractBoundaries(videoItemStartTime1,
- videoItemEndTime1);
- } catch (Exception e1) {
- assertTrue("Can not create Video Item with file name = "
- + e1.toString(), false);
- }
- final OverlayFrame overlayFrame[] = new OverlayFrame[NUM_OF_ITERATIONS];
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(overlayFilename,
- 640, 480);
- int timeTaken = 0;
- long beginTime = SystemClock.uptimeMillis();
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- overlayFrame[i] = new OverlayFrame(mediaVideoItem, "overlay" + i,
- mBitmap, overlayStartTime, overlayDuration);
- mediaVideoItem.addOverlay(overlayFrame[i]);
- }
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[0] = "Time taken to add & create Overlay :" + timeTaken;
-
- beginTime = SystemClock.uptimeMillis();
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- assertEquals("Removing Overlays", overlayFrame[i],
- mediaVideoItem.removeOverlay((overlayFrame[i].getId())));
- }
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[1] = "\n\tTime taken to remove Overlay :" +
- timeTaken;
-
- writeTimingInfo("testPerformanceOverlayVideoItem (in mSec)", loggingInfo);
- }
-
- /**
- * To test the performance of get properties of a Video media item
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceVideoItemProperties() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final int videoItemStartTime1 = 0;
- final int videoItemEndTime1 = 10100;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int aspectRatio = MediaProperties.ASPECT_RATIO_3_2;
- final int fileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int duration = 77366;
- final int videoBitrate = 3169971;
- final int fps = 30;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileBaseline;
- final int videoLevel = MediaProperties.H264Level.H264Level13;
- final int width = 1080;
- final int height = MediaProperties.HEIGHT_720;
- int timeTaken = 0;
- final String[] loggingInfo = new String[1];
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "m0", videoItemFileName1, renderingMode);
- mediaVideoItem.setExtractBoundaries(videoItemStartTime1,
- videoItemEndTime1);
- long beginTime = SystemClock.uptimeMillis();
- for (int i = 0; i < (NUM_OF_ITERATIONS*10); i++) {
- try {
- assertEquals("Aspect Ratio Mismatch",
- aspectRatio, mediaVideoItem.getAspectRatio());
- assertEquals("File Type Mismatch",
- fileType, mediaVideoItem.getFileType());
- assertEquals("VideoCodec Mismatch",
- videoCodecType, mediaVideoItem.getVideoType());
- assertEquals("duration Mismatch",
- duration, mediaVideoItem.getDuration());
- assertEquals("Video Profile ",
- videoProfile, mediaVideoItem.getVideoProfile());
- assertEquals("Video Level ",
- videoLevel, mediaVideoItem.getVideoLevel());
- assertEquals("Video height ",
- height, mediaVideoItem.getHeight());
- assertEquals("Video width ",
- width, mediaVideoItem.getWidth());
- } catch (Exception e1) {
- assertTrue("Can not create Video Item with file name = "
- + e1.toString(), false);
- }
- }
- timeTaken = calculateTimeTaken(beginTime, (NUM_OF_ITERATIONS*10));
- loggingInfo[0] = "Time taken to get Media Properties :"
- + timeTaken;
- writeTimingInfo("testPerformanceVideoItemProperties:", loggingInfo);
- }
-
- /**
- * To test the performance of generatePreview : with Transitions
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceGeneratePreviewWithTransitions()
- throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String imageItemFileName = INPUT_FILE_PATH +
- "IMG_1600x1200.jpg";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int transitionBehavior = Transition.BEHAVIOR_MIDDLE_FAST;
- long averageTime = 0;
- final String[] loggingInfo = new String[1];
-
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "mediaItem1", videoItemFileName, renderingMode);
- mediaVideoItem.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final MediaImageItem mediaImageItem = new MediaImageItem(mVideoEditor,
- "mediaItem2", imageItemFileName, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaImageItem);
-
- final TransitionCrossfade transitionCrossFade = new TransitionCrossfade(
- "transitionCrossFade", mediaVideoItem, mediaImageItem,
- 5000, transitionBehavior);
- mVideoEditor.addTransition(transitionCrossFade);
-
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- final long duration1 = SystemClock.uptimeMillis();
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- final long duration2 = SystemClock.uptimeMillis();
- mVideoEditor.removeTransition(transitionCrossFade.getId());
- mVideoEditor.addTransition(transitionCrossFade);
- averageTime += (duration2 - duration1);
- }
- final long durationToAddObjects = averageTime;
- final float timeTaken = (float)durationToAddObjects *
- 1.0f/(float)NUM_OF_ITERATIONS;
- loggingInfo[0] = "Time taken to Generate Preview with transition :"
- + timeTaken;
- writeTimingInfo("testPerformanceGeneratePreviewWithTransitions:",
- loggingInfo);
- }
-
- /**
- * To test the performance of generatePreview : with KenBurn
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceWithKenBurn() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String imageItemFileName = INPUT_FILE_PATH +
- "IMG_1600x1200.jpg";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- long averageTime = 0;
- final String[] loggingInfo = new String[1];
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "mediaItem1", videoItemFileName, renderingMode);
- mediaVideoItem.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final MediaImageItem mediaImageItem = new MediaImageItem(mVideoEditor,
- "mediaItem2", imageItemFileName, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaImageItem);
-
- final Rect startRect = new Rect((mediaImageItem.getHeight() / 3),
- (mediaImageItem.getWidth() / 3), (mediaImageItem.getHeight() / 2),
- (mediaImageItem.getWidth() / 2));
- final Rect endRect = new Rect(0, 0, mediaImageItem.getWidth(),
- mediaImageItem.getHeight());
- final EffectKenBurns kbEffectOnMediaItem =
- new EffectKenBurns(mediaImageItem, "KBOnM2", startRect, endRect,
- 500, 3000);
- mediaImageItem.addEffect(kbEffectOnMediaItem);
-
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- final long duration1 = SystemClock.uptimeMillis();
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- final long duration2 = SystemClock.uptimeMillis();
- mediaImageItem.removeEffect(kbEffectOnMediaItem.getId());
- mediaImageItem.addEffect(kbEffectOnMediaItem);
- averageTime += duration2 - duration1;
- }
-
- final long durationToAddObjects = (averageTime);
- final float timeTaken = (float)durationToAddObjects *
- 1.0f/(float)NUM_OF_ITERATIONS;
- loggingInfo[0] = "Time taken to Generate KenBurn Effect :"
- + timeTaken;
- writeTimingInfo("testPerformanceWithKenBurn", loggingInfo);
- }
-
- /**
- * To test the performance of generatePreview : with Transitions and
- * Effect,Overlapping scenario
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceEffectOverlappingTransition() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String videoItemFileName2 = INPUT_FILE_PATH
- + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final int videoStartTime1 = 0;
- final int videoEndTime1 = 10000;
- final int videoStartTime2 = 0;
- final int videoEndTime2 = 10000;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int transitionDuration = 5000;
- final int transitionBehavior = Transition.BEHAVIOR_MIDDLE_FAST;
- final int effectItemStartTime = 5000;
- final int effectItemDurationTime = 5000;
- final int effectType = EffectColor.TYPE_COLOR;
- final int effectColorType = EffectColor.GREEN;
- long averageDuration = 0;
-
- final String[] loggingInfo = new String[1];
- final MediaVideoItem mediaVideoItem1 = new MediaVideoItem(mVideoEditor,
- "mediaItem1", videoItemFileName1, renderingMode);
- mediaVideoItem1.setExtractBoundaries(videoStartTime1, videoEndTime1);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 = new MediaVideoItem(mVideoEditor,
- "mediaItem2", videoItemFileName2, renderingMode);
- mediaVideoItem2.setExtractBoundaries(videoStartTime2, videoEndTime2);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final TransitionCrossfade transitionCrossFade = new TransitionCrossfade(
- "transitionCrossFade", mediaVideoItem1, mediaVideoItem2,
- transitionDuration, transitionBehavior);
- mVideoEditor.addTransition(transitionCrossFade);
-
- final EffectColor effectColor = new EffectColor(mediaVideoItem1,
- "effect", effectItemStartTime, effectItemDurationTime, effectType,
- effectColorType);
- mediaVideoItem1.addEffect(effectColor);
-
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- final long duration1 = SystemClock.uptimeMillis();
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- final long duration2 = SystemClock.uptimeMillis();
- mVideoEditor.removeTransition(transitionCrossFade.getId());
- mVideoEditor.addTransition(transitionCrossFade);
- averageDuration += (duration2 - duration1);
- }
- SystemClock.uptimeMillis();
- final long durationToAddObjects = (averageDuration);
- final float timeTaken = (float)durationToAddObjects *
- 1.0f/(float)NUM_OF_ITERATIONS;
- loggingInfo[0] =
- "Time taken to testPerformanceEffectOverlappingTransition :"
- + timeTaken;
- writeTimingInfo("testPerformanceEffectOverlappingTransition:",
- loggingInfo);
- }
-
- /**
- * To test creation of story board with Transition and Two Effects, Effect
- * overlapping transitions
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceTransitionWithEffectOverlapping() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String videoItemFileName2 = INPUT_FILE_PATH
- + "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int transitionDuration = 5000;
- final int transitionBehavior = Transition.BEHAVIOR_MIDDLE_FAST;
- final int effectItemStartTime1 = 5000;
- final int effectItemDurationTime1 = 5000;
- final int effectType1 = EffectColor.TYPE_COLOR;
- final int effectColorType1 = EffectColor.GREEN;
- final int effectItemStartTime2 = 5000;
- final int effectItemDurationTime2 = 5000;
- final int effectType2 = EffectColor.TYPE_COLOR;
- final int effectColorType2 = EffectColor.GREEN;
- int averageTime = 0;
- final String[] loggingInfo = new String[1];
-
- final MediaVideoItem mediaVideoItem1 = new MediaVideoItem(mVideoEditor,
- "mediaItem1", videoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem1);
-
- final MediaVideoItem mediaVideoItem2 = new MediaVideoItem(mVideoEditor,
- "mediaItem2", videoItemFileName2, renderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem2);
-
- final TransitionCrossfade transitionCrossFade = new TransitionCrossfade(
- "transitionCrossFade", mediaVideoItem1, mediaVideoItem2,
- transitionDuration, transitionBehavior);
- mVideoEditor.addTransition(transitionCrossFade);
-
- final EffectColor effectColor1 = new EffectColor(mediaVideoItem1,
- "effect1", effectItemStartTime1, effectItemDurationTime1,
- effectType1, effectColorType1);
- mediaVideoItem1.addEffect(effectColor1);
-
- final EffectColor effectColor2 = new EffectColor(mediaVideoItem2,
- "effect2", effectItemStartTime2, effectItemDurationTime2,
- effectType2, effectColorType2);
- mediaVideoItem2.addEffect(effectColor2);
-
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- final long duration1 = SystemClock.uptimeMillis();
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- final long duration2 = SystemClock.uptimeMillis();
- mVideoEditor.removeTransition(transitionCrossFade.getId());
- mVideoEditor.addTransition(transitionCrossFade);
- averageTime += duration2 - duration1;
- }
- final long durationToAddObjects = (averageTime);
- final float timeTaken = (float)durationToAddObjects *
- 1.0f/(float)NUM_OF_ITERATIONS;
- loggingInfo[0] = "Time taken to TransitionWithEffectOverlapping :"
- + timeTaken;
- writeTimingInfo("testPerformanceTransitionWithEffectOverlapping",
- loggingInfo);
- }
-
- /**
- *To test ThumbnailList for H264
- */
- @LargeTest
- public void testThumbnailH264NonIFrame() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final int outWidth = 1080;
- final int outHeight = 720;
- final int atTime = 2400;
- long durationToAddObjects = 0;
- int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String[] loggingInfo = new String[1];
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "m1", videoItemFilename, renderingMode);
- assertNotNull("MediaVideoItem", mediaVideoItem);
-
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- final long duration1 = SystemClock.uptimeMillis();
- mediaVideoItem.getThumbnail(outWidth, outHeight, atTime + i);
- final long duration2 = SystemClock.uptimeMillis();
- durationToAddObjects += (duration2 - duration1);
- }
- final float timeTaken = (float)durationToAddObjects *
- 1.0f/(float)NUM_OF_ITERATIONS;
- loggingInfo[0] = "Time taken for Thumbnail generation :"
- + timeTaken;
- writeTimingInfo("testThumbnailH264NonIFrame", loggingInfo);
- }
-
- /**
- *To test ThumbnailList for H264
- */
- @LargeTest
- public void testThumbnailH264AnIFrame() throws Exception {
- final String videoItemFilename = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final int outWidth = 1080;
- final int outHeight = 720;
- final int atTime = 3000;
- int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String[] loggingInfo = new String[1];
- long durationToAddObjects = 0;
-
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "m1", videoItemFilename, renderingMode);
- assertNotNull("MediaVideoItem", mediaVideoItem);
-
- for (int i = 0; i < NUM_OF_ITERATIONS; i++) {
- final long duration1 = SystemClock.uptimeMillis();
- mediaVideoItem.getThumbnail(outWidth, outHeight, atTime + i);
- final long duration2 = SystemClock.uptimeMillis();
- durationToAddObjects += (duration2 - duration1);
- }
- final float timeTaken = (float)durationToAddObjects *
- 1.0f/(float)NUM_OF_ITERATIONS;
- loggingInfo[0] = "Time taken Thumbnail generation :"
- + timeTaken;
- writeTimingInfo("testThumbnailH264AnIFrame", loggingInfo);
- }
-
- /**
- * To test the performance : With an audio track
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceWithAudioTrack() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String audioFilename1 = INPUT_FILE_PATH +
- "AACLC_44.1kHz_256kbps_s_1_17.mp4";
- final String audioFilename2 = INPUT_FILE_PATH +
- "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int audioVolume = 50;
- final String[] loggingInfo = new String[2];
- int timeTaken = 0;
-
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "mediaItem1", videoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final AudioTrack audioTrack1 = new AudioTrack(mVideoEditor,
- "Audio Track1", audioFilename1);
- audioTrack1.disableDucking();
- audioTrack1.setVolume(audioVolume);
- mVideoEditor.addAudioTrack(audioTrack1);
-
- long beginTime = SystemClock.uptimeMillis();
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- timeTaken = calculateTimeTaken(beginTime, 1);
- loggingInfo[0] = "Time taken for 1st Audio Track (AACLC) :"
- + timeTaken;
-
- final AudioTrack audioTrack2 = new AudioTrack(mVideoEditor,
- "Audio Track2", audioFilename2);
- audioTrack2.enableLoop();
-
- beginTime = SystemClock.uptimeMillis();
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- timeTaken = calculateTimeTaken(beginTime, 1);
- loggingInfo[1] = "\n\tTime taken for 2nd Audio Track(AMRNB) :"
- + timeTaken;
-
- writeTimingInfo("testPerformanceWithAudioTrack", loggingInfo);
- }
-
- /**
- * To test the performance of adding and removing the
- * image media item with 640 x 480
- *
- * @throws Exception
- */
- @LargeTest
- public void testPerformanceAddRemoveImageItem640x480() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int imageItemDuration = 0;
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String[] loggingInfo = new String[3];
-
- int timeTaken = 0;
-
- final MediaImageItem[] mediaImageItem =
- new MediaImageItem[NUM_OF_ITERATIONS];
- long beginTime = SystemClock.uptimeMillis();
- createImageItems(mediaImageItem, imageItemFileName, renderingMode,
- imageItemDuration);
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[0] = "Time taken to Create Media Image Item (640x480) :"
- + timeTaken;
-
- beginTime = SystemClock.uptimeMillis();
- addImageItems(mediaImageItem);
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[1] = "\n\tTime taken to add Media Image Item (640x480) :"
- + timeTaken;
-
- beginTime = SystemClock.uptimeMillis();
- removeImageItems(mediaImageItem);
- timeTaken = calculateTimeTaken(beginTime, NUM_OF_ITERATIONS);
- loggingInfo[2] = "\n\tTime taken to remove Media Image Item (640x480) :"
- + timeTaken;
- writeTimingInfo("testPerformanceAddRemoveImageItem640x480 (in mSec)", loggingInfo);
- }
-
-
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
deleted file mode 100644
index 7784c7b..0000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/VideoEditorStressTest.java
+++ /dev/null
@@ -1,1309 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.stress;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.Writer;
-import java.util.List;
-
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.media.videoeditor.AudioTrack;
-import android.media.videoeditor.EffectColor;
-import android.media.videoeditor.EffectKenBurns;
-import android.media.videoeditor.MediaImageItem;
-import android.media.videoeditor.MediaItem;
-import android.media.videoeditor.MediaProperties;
-import android.media.videoeditor.MediaVideoItem;
-import android.media.videoeditor.OverlayFrame;
-import android.media.videoeditor.Transition;
-import android.media.videoeditor.TransitionCrossfade;
-import android.media.videoeditor.TransitionAlpha;
-import android.media.videoeditor.TransitionFadeBlack;
-import android.media.videoeditor.TransitionSliding;
-import android.media.videoeditor.VideoEditor;
-import android.os.Environment;
-import android.test.ActivityInstrumentationTestCase;
-import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
-import android.os.Environment;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase;
-import android.media.videoeditor.VideoEditor.ExportProgressListener;
-import android.media.videoeditor.VideoEditorFactory;
-import android.media.videoeditor.ExtractAudioWaveformProgressListener;
-
-import android.os.Debug;
-import android.util.Log;
-import com.android.mediaframeworktest.MediaFrameworkPerfTestRunner;
-import com.android.mediaframeworktest.MediaFrameworkTest;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.mediaframeworktest.VideoEditorHelper;
-import com.android.mediaframeworktest.MediaTestUtil;
-
-/**
- * Junit / Instrumentation - performance measurement for media player and
- * recorder
- */
-public class VideoEditorStressTest
- extends ActivityInstrumentationTestCase<MediaFrameworkTest> {
-
- private final String TAG = "VideoEditorStressTest";
-
- private final String PROJECT_LOCATION = VideoEditorHelper.PROJECT_LOCATION_COMMON;
-
- private final String INPUT_FILE_PATH = VideoEditorHelper.INPUT_FILE_PATH_COMMON;
-
- private final String VIDEOEDITOR_OUTPUT = PROJECT_LOCATION +
- "VideoEditorStressMemOutput.txt";
-
- private long BeginJavaMemory;
- private long AfterJavaMemory;
-
- private long BeginNativeMemory;
- private long AfterNativeMemory;
-
- public VideoEditorStressTest() {
- super("com.android.mediaframeworktest", MediaFrameworkTest.class);
- new File(VIDEOEDITOR_OUTPUT).delete();
- }
-
- private final String PROJECT_CLASS_NAME =
- "android.media.videoeditor.VideoEditorImpl";
- private VideoEditor mVideoEditor;
- private MediaTestUtil mMediaTestUtil;
- private VideoEditorHelper mVideoEditorHelper;
-
- @Override
- protected void setUp() throws Exception {
- // setup for each test case.
- super.setUp();
- getActivity();
- mMediaTestUtil = new MediaTestUtil(
- "/sdcard/VideoEditorMediaServerMemoryLog.txt",
- this.getName(), "mediaserver");
- mVideoEditorHelper = new VideoEditorHelper();
- // Create a random String which will be used as project path, where all
- // project related files will be stored.
- final String projectPath =
- mVideoEditorHelper.createRandomFile(PROJECT_LOCATION);
- mVideoEditor = mVideoEditorHelper.createVideoEditor(projectPath);
- }
-
- @Override
- protected void tearDown() throws Exception {
- final String[] loggingInfo = new String[1];
- mMediaTestUtil.getMemorySummary();
- loggingInfo[0] = "\n" +this.getName();
- writeTimingInfo(loggingInfo);
- loggingInfo[0] = " diff : " + (AfterNativeMemory - BeginNativeMemory);
- writeTimingInfo(loggingInfo);
- mVideoEditorHelper.destroyVideoEditor(mVideoEditor);
- // Clean the directory created as project path
- mVideoEditorHelper.deleteProject(new File(mVideoEditor.getPath()));
- System.gc();
- super.tearDown();
- }
-
- private void writeTimingInfo(String[] information)
- throws Exception {
- File outFile = new File(VIDEOEDITOR_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(outFile, true));
- for (int i = 0; i < information.length; i++) {
- output.write(information[i]);
- }
- output.close();
- }
-
- private void writeTestCaseHeader(String testCaseName)
- throws Exception {
- File outFile = new File(VIDEOEDITOR_OUTPUT);
- Writer output = new BufferedWriter(new FileWriter(outFile, true));
- output.write("\n\n" + testCaseName + "\n");
- output.close();
- }
-
- private void getBeginMemory() throws Exception {
- System.gc();
- Thread.sleep(2500);
- BeginNativeMemory = Debug.getNativeHeapAllocatedSize();
- mMediaTestUtil.getStartMemoryLog();
- }
- private void getAfterMemory_updateLog(String[] loggingInfo, boolean when,
- int iteration)
- throws Exception {
- System.gc();
- Thread.sleep(2500);
- AfterNativeMemory = Debug.getNativeHeapAllocatedSize();
- if(when == false){
- loggingInfo[0] = "\n Before Remove: iteration No.= " + iteration +
- "\t " + (AfterNativeMemory - BeginNativeMemory);
- } else {
- loggingInfo[0] = "\n After Remove: iteration No.= " + iteration +
- "\t " + (AfterNativeMemory - BeginNativeMemory);
- }
- writeTimingInfo(loggingInfo);
- mMediaTestUtil.getMemoryLog();
- }
-
- /**
- * To stress test MediaItem(Video Item) adding functionality
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressAddRemoveVideoItem() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
-
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_176x144_15fps_144kbps_AMRNB_8kHz_12.2kbps_m_1_17.3gp";
- final String videoItemFileName2 = INPUT_FILE_PATH +
- "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_96kbps_s_0_21.mp4";
- final String videoItemFileName3 = INPUT_FILE_PATH +
- "H263_profile0_176x144_15fps_128kbps_1_35.3gp";
- final String videoItemFileName4 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
- final String[] loggingInfo = new String[1];
- writeTestCaseHeader("testStressAddRemoveVideoItem");
- int i = 0;
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- if (i % 4 == 0) {
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1" + i, videoItemFileName1, renderingMode);
- mediaItem1.setExtractBoundaries(0, 5000);
- mVideoEditor.addMediaItem(mediaItem1);
- }
- if (i % 4 == 1) {
- final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor,
- "m2" + i, videoItemFileName2, renderingMode);
- mediaItem2.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaItem2);
- }
- if (i % 4 == 2) {
- final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
- "m3" + i, videoItemFileName3, renderingMode);
- mediaItem3.setExtractBoundaries(30000, 45000);
- mVideoEditor.addMediaItem(mediaItem3);
- }
- if (i % 4 == 3) {
- final MediaVideoItem mediaItem4 = new MediaVideoItem(mVideoEditor,
- "m4" + i, videoItemFileName4, renderingMode);
- mediaItem4.setExtractBoundaries(10000, 30000);
- mVideoEditor.addMediaItem(mediaItem4);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- for ( i = 0; i < 50; i++) {
- if (i % 4 == 0) {
- mVideoEditor.removeMediaItem("m1" + i);
- }
- if (i % 4 == 1) {
- mVideoEditor.removeMediaItem("m2" + i);
- }
- if (i % 4 == 2) {
- mVideoEditor.removeMediaItem("m3" + i);
- }
- if (i % 4 == 3) {
- mVideoEditor.removeMediaItem("m4" + i);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To stress test MediaItem(Image Item) adding functionality
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressAddRemoveImageItem() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String ImageItemFileName1 = INPUT_FILE_PATH +
- "IMG_1600x1200.jpg";
- final String ImageItemFileName2 = INPUT_FILE_PATH +
- "IMG_640x480.jpg";
- final String ImageItemFileName3 = INPUT_FILE_PATH +
- "IMG_320x240.jpg";
- final String ImageItemFileName4 = INPUT_FILE_PATH +
- "IMG_176x144.jpg";
- final String[] loggingInfo = new String[1];
- int i = 0;
- writeTestCaseHeader("testStressAddRemoveImageItem");
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- if (i % 4 == 0) {
- final MediaImageItem mediaItem1 = new MediaImageItem(mVideoEditor,
- "m1"+ i, ImageItemFileName1, 5000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
- }
- if (i % 4 == 1) {
- final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
- "m2"+ i, ImageItemFileName2, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
- }
- if (i % 4 == 2) {
- final MediaImageItem mediaItem3 = new MediaImageItem(mVideoEditor,
- "m3"+ i, ImageItemFileName3, 15000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem3);
- }
- if (i % 4 == 3) {
- final MediaImageItem mediaItem4 = new MediaImageItem(mVideoEditor,
- "m4"+ i, ImageItemFileName4, 20000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem4);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- for ( i = 0; i < 50; i++) {
- if (i % 4 == 0) {
- mVideoEditor.removeMediaItem("m1"+i);
- }
- if (i % 4 == 1) {
- mVideoEditor.removeMediaItem("m2"+i);
- }
- if (i % 4 == 2) {
- mVideoEditor.removeMediaItem("m3"+i);
- }
- if (i % 4 == 3) {
- mVideoEditor.removeMediaItem("m4"+i);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To stress test transition
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressAddRemoveTransition() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String VideoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_1_17.mp4";
- final String ImageItemFileName2 = INPUT_FILE_PATH +
- "IMG_1600x1200.jpg";
- final String VideoItemFileName3 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final String maskFilename = INPUT_FILE_PATH +
- "TransitionSpiral_QVGA.jpg";
- final String[] loggingInfo = new String[1];
- int i = 0;
- writeTestCaseHeader("testStressAddRemoveTransition");
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- if (i % 4 == 0) {
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1"+i, VideoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
- mediaItem1.setExtractBoundaries(0, 10000);
- final TransitionCrossfade tranCrossfade =
- new TransitionCrossfade("transCF" + i, null,
- mediaItem1, 5000, Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(tranCrossfade);
- }
- if (i % 4 == 1) {
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1"+i, VideoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
- mediaItem1.setExtractBoundaries(0, 10000);
-
- final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
- "m2" +i, ImageItemFileName2, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
-
- final TransitionAlpha transitionAlpha =
- mVideoEditorHelper.createTAlpha("transAlpha" + i, mediaItem1,
- mediaItem2, 5000, Transition.BEHAVIOR_SPEED_UP,
- maskFilename, 10, false);
- transitionAlpha.setDuration(4000);
- mVideoEditor.addTransition(transitionAlpha);
- }
- if (i % 4 == 2) {
- final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
- "m2" + i, ImageItemFileName2, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
-
- final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
- "m3" + i, VideoItemFileName3, renderingMode);
- mVideoEditor.addMediaItem(mediaItem3);
-
- mediaItem3.setExtractBoundaries(0, 10000);
- final TransitionAlpha transitionAlpha =
- mVideoEditorHelper.createTAlpha("transAlpha" + i, mediaItem2,
- mediaItem3, 5000, Transition.BEHAVIOR_SPEED_UP,
- maskFilename, 10, false);
- transitionAlpha.setDuration(4000);
- mVideoEditor.addTransition(transitionAlpha);
-
- mediaItem3.setExtractBoundaries(0, 6000);
-
- final TransitionSliding transition2And3 =
- mVideoEditorHelper.createTSliding("transSlide" +i, mediaItem2,
- mediaItem3, 3000, Transition.BEHAVIOR_MIDDLE_FAST,
- TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN);
- mVideoEditor.addTransition(transition2And3);
- }
- if (i % 4 == 3) {
- final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
- "m3" + i, VideoItemFileName3, renderingMode);
- mVideoEditor.addMediaItem(mediaItem3);
- mediaItem3.setExtractBoundaries(0, 5000);
-
- final TransitionFadeBlack transition3 =
- mVideoEditorHelper.createTFadeBlack("transFB" +i, mediaItem3,
- null, 2500, Transition.BEHAVIOR_SPEED_UP);
- transition3.setDuration(500);
- mVideoEditor.addTransition(transition3);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- for ( i = 0; i < 50; i++) {
- if (i % 4 == 0) {
- mVideoEditor.removeTransition("transCF" + i);
- mVideoEditor.removeMediaItem("m1" + i);
- }
- if (i % 4 == 1) {
- mVideoEditor.removeTransition("transAlpha" + i);
- mVideoEditor.removeMediaItem("m1" + i);
- mVideoEditor.removeMediaItem("m2" + i);
- }
- if (i % 4 == 2) {
- mVideoEditor.removeTransition("transSlide" +i);
- mVideoEditor.removeMediaItem("m2" + i);
- mVideoEditor.removeMediaItem("m3" + i);
- }
- if (i % 4 == 3) {
- mVideoEditor.removeMediaItem("m3" + i);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To stress test overlay
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressAddRemoveOverlay() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String VideoItemFileName1 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final String ImageItemFileName2 = INPUT_FILE_PATH +
- "IMG_640x480.jpg";
- final String OverlayFile3 = INPUT_FILE_PATH +
- "IMG_640x480_Overlay1.png";
- final String OverlayFile4 = INPUT_FILE_PATH +
- "IMG_640x480_Overlay2.png";
- final String[] loggingInfo = new String[1];
- int i = 0;
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1", VideoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
-
- final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
- "m2", ImageItemFileName2, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
- writeTestCaseHeader("testStressAddRemoveOverlay");
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- if (i % 3 == 0) {
- mediaItem1.setExtractBoundaries(0, 10000);
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(
- OverlayFile3, 640, 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaItem1, "overlay" + i,
- mBitmap, 1000, 5000);
- mediaItem1.addOverlay(overlayFrame);
- mediaItem1.removeOverlay("overlay"+i);
- }
- if (i % 3 == 1) {
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(
- OverlayFile4, 640, 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaItem2, "overlay" + i,
- mBitmap, 1000, 5000);
- mediaItem2.addOverlay(overlayFrame);
- mediaItem2.removeOverlay("overlay"+i);
- }
- if (i % 3 == 2) {
- mediaItem1.setExtractBoundaries(0, 10000);
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(
- OverlayFile4, 640, 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaItem1, "overlay" + i,
- mBitmap, 0, mediaItem1.getDuration());
- mediaItem1.addOverlay(overlayFrame);
- mediaItem1.removeOverlay("overlay"+i);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
-
- /**
- * To stress test Effects
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressAddRemoveEffects() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String VideoItemFileName1 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
- final String ImageItemFileName2 = INPUT_FILE_PATH +
- "IMG_1600x1200.jpg";
- final String[] loggingInfo = new String[1];
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1", VideoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
- final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
- "m2", ImageItemFileName2, 10000, renderingMode);
- int i = 0;
- mVideoEditor.addMediaItem(mediaItem2);
- writeTestCaseHeader("testStressAddRemoveEffects");
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- if (i % 5 == 0) {
- mediaItem1.setExtractBoundaries(10000, 30000);
- final EffectColor effectColor1 =
- mVideoEditorHelper.createEffectItem(mediaItem1, "effect1"+i,
- 10000, (mediaItem1.getTimelineDuration()-1000),
- EffectColor.TYPE_COLOR, EffectColor.GREEN);
- mediaItem1.addEffect(effectColor1);
- }
- if (i % 5 == 1) {
- mediaItem2.setDuration(20000);
- final EffectColor effectColor1 =
- mVideoEditorHelper.createEffectItem(mediaItem2, "effect1"+i,
- 0, 4000, EffectColor.TYPE_GRADIENT, EffectColor.GRAY);
- mediaItem2.addEffect(effectColor1);
- }
- if (i % 5 == 2) {
- mediaItem1.setExtractBoundaries(10000, 30000);
- final EffectColor effectColor1 =
- mVideoEditorHelper.createEffectItem(mediaItem1, "effect1"+i,
- (mediaItem1.getTimelineDuration() - 4000), 4000,
- EffectColor.TYPE_SEPIA, 0);
- mediaItem1.addEffect(effectColor1);
- }
- if (i % 5 == 3) {
- mediaItem2.setDuration(20000);
- final EffectColor effectColor1 =
- mVideoEditorHelper.createEffectItem(mediaItem2, "effect1"+i,
- 10000, 4000, EffectColor.TYPE_NEGATIVE, 0);
- mediaItem2.addEffect(effectColor1);
- }
- if (i % 5 == 4) {
- mediaItem2.setDuration(20000);
- final Rect startRect = new Rect((mediaItem2.getHeight() / 3),
- (mediaItem2.getWidth() / 3), (mediaItem2.getHeight() / 2),
- (mediaItem2.getWidth() / 2));
- final Rect endRect = new Rect(0, 0, mediaItem2.getWidth(),
- mediaItem2.getHeight());
- final EffectKenBurns kbEffectOnMediaItem = new EffectKenBurns(
- mediaItem2, "KBOnM2" + i, startRect, endRect, 500,
- (mediaItem2.getDuration() - 500));
- mediaItem2.addEffect(kbEffectOnMediaItem);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- for ( i = 0; i < 50; i++) {
- if (i % 5 == 0) {
- mediaItem1.removeEffect("effect1"+i);
- }
- if (i % 5 == 1) {
- mediaItem1.removeEffect("effect1"+i);
- }
- if (i % 5 == 2) {
- mediaItem1.removeEffect("effect1"+i);
- }
- if (i % 5 == 3) {
- mediaItem1.removeEffect("effect1"+i);
- }
- if (i % 5 == 4) {
- mediaItem1.removeEffect("KBOnM2"+i);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * This method will test thumbnail list extraction in a loop = 200 for Video
- * Item
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressThumbnailVideoItem() throws Exception {
- final String videoItemFileName = INPUT_FILE_PATH
- + "H264_BP_640x480_15fps_1200Kbps_AACLC_48KHz_64kps_m_0_27.3gp";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String[] loggingInfo = new String[1];
- int i = 0;
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "m1", videoItemFileName, renderingMode);
- writeTestCaseHeader("testStressThumbnailVideoItem");
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- if (i % 4 == 0) {
- final Bitmap[] thumbNails =
- mediaVideoItem.getThumbnailList(mediaVideoItem.getWidth()*3,
- mediaVideoItem.getHeight()/2, i, 5000, 2);
- // Recycle this Bitmap array
- for (int i1 = 0; i1 < thumbNails.length; i1++) {
- thumbNails[i1].recycle();
- }
- }
- if (i % 4 == 1) {
- final Bitmap[] thumbNails =
- mediaVideoItem.getThumbnailList(mediaVideoItem.getWidth()/2,
- mediaVideoItem.getHeight() * 3, i, 5000, 2);
- // Recycle this Bitmap array
- for (int i1 = 0; i1 < thumbNails.length; i1++) {
- thumbNails[i1].recycle();
- }
- }
- if (i % 4 == 2) {
- final Bitmap[] thumbNails =
- mediaVideoItem.getThumbnailList(mediaVideoItem.getWidth()*2,
- mediaVideoItem.getHeight() / 3, i, 5000, 2);
- // Recycle this Bitmap array
- for (int i1 = 0; i1 < thumbNails.length; i1++) {
- thumbNails[i1].recycle();
- }
- }
- if (i % 4 == 3) {
- final Bitmap[] thumbNails =
- mediaVideoItem.getThumbnailList(mediaVideoItem.getWidth(),
- mediaVideoItem.getHeight(), i, 5000, 2);
- // Recycle this Bitmap array
- for (int i1 = 0; i1 < thumbNails.length; i1++) {
- thumbNails[i1].recycle();
- }
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
-
- /**
- * To stress test media properties
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressMediaProperties() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String VideoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String ImageItemFileName2 = INPUT_FILE_PATH +
- "IMG_640x480.jpg";
- final String AudioItemFileName3 = INPUT_FILE_PATH +
- "AACLC_44.1kHz_256kbps_s_1_17.mp4";
- final String[] loggingInfo = new String[1];
- int i = 0;
- final int videoAspectRatio = MediaProperties.ASPECT_RATIO_3_2;
- final int videoFileType = MediaProperties.FILE_MP4;
- final int videoCodecType = MediaProperties.VCODEC_H264;
- final int videoDuration = 77366;
- final int videoProfile = MediaProperties.H264Profile.H264ProfileBaseline;
- final int videoLevel = MediaProperties.H264Level.H264Level13;
- final int videoHeight = MediaProperties.HEIGHT_720;
- final int videoWidth = 1080;
-
- final int imageAspectRatio = MediaProperties.ASPECT_RATIO_4_3;
- final int imageFileType = MediaProperties.FILE_JPEG;
- final int imageWidth = 640;
- final int imageHeight = MediaProperties.HEIGHT_480;
-
- final int audioDuration = 77554;
- final int audioCodecType = MediaProperties.ACODEC_AAC_LC;
- final int audioSamplingFrequency = 44100;
- final int audioChannel = 2;
- writeTestCaseHeader("testStressMediaProperties");
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- if (i % 3 == 0) {
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1" + i, VideoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
- mediaItem1.setExtractBoundaries(0, 20000);
- assertEquals("Aspect Ratio Mismatch",
- videoAspectRatio, mediaItem1.getAspectRatio());
- assertEquals("File Type Mismatch",
- videoFileType, mediaItem1.getFileType());
- assertEquals("VideoCodec Mismatch",
- videoCodecType, mediaItem1.getVideoType());
- assertEquals("duration Mismatch",
- videoDuration, mediaItem1.getDuration());
- assertEquals("Video Profile ",
- videoProfile, mediaItem1.getVideoProfile());
- assertEquals("Video Level ",
- videoLevel, mediaItem1.getVideoLevel());
- assertEquals("Video height ",
- videoHeight, mediaItem1.getHeight());
- assertEquals("Video width ",
- videoWidth, mediaItem1.getWidth());
- mVideoEditor.removeMediaItem("m1" + i);
- }
- if (i % 3 == 1) {
- final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
- "m2" + i, ImageItemFileName2, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
- assertEquals("Aspect Ratio Mismatch",
- imageAspectRatio, mediaItem2.getAspectRatio());
- assertEquals("File Type Mismatch",
- imageFileType, mediaItem2.getFileType());
- assertEquals("Image height",
- imageHeight, mediaItem2.getHeight());
- assertEquals("Image width",
- imageWidth, mediaItem2.getWidth());
- mVideoEditor.removeMediaItem("m2" + i);
- }
- if (i % 3 == 2) {
- final AudioTrack mediaItem3 = new AudioTrack(mVideoEditor,
- "m3" + i, AudioItemFileName3);
- mVideoEditor.addAudioTrack(mediaItem3);
- assertEquals("AudioType Mismatch", audioCodecType,
- mediaItem3.getAudioType());
- assertEquals("Audio Sampling", audioSamplingFrequency,
- mediaItem3.getAudioSamplingFrequency());
- assertEquals("Audio Channels",
- audioChannel, mediaItem3.getAudioChannels());
- assertEquals("duration Mismatch", audioDuration,
- mediaItem3.getDuration());
- mVideoEditor.removeAudioTrack("m3" + i);
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
-
- /**
- * To stress test insert and move of mediaitems
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressInsertMovieItems() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String VideoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String VideoItemFileName2 = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_1_17.mp4";
- final String VideoItemFileName3 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
- final String[] loggingInfo = new String[1];
- int i = 0;
- writeTestCaseHeader("testStressInsertMovieItems");
-
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1", VideoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
- mediaItem1.setExtractBoundaries(0, 10000);
-
- final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor,
- "m2", VideoItemFileName2, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
- mediaItem2.setExtractBoundaries(0, 15000);
-
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
- "m3" + i, VideoItemFileName3, renderingMode);
- mediaItem3.setExtractBoundaries(0, 15000);
- mVideoEditor.insertMediaItem(mediaItem3, "m1");
- mVideoEditor.moveMediaItem("m2", "m3" + i);
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- for ( i = 0; i < 50; i++) {
- mVideoEditor.removeMediaItem("m3" + i);
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
- }
- mVideoEditor.removeMediaItem("m2");
- mVideoEditor.removeMediaItem("m1");
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To stress test : load and save
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressLoadAndSave() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String VideoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String VideoItemFileName2 = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_1_17.mp4";
- final String VideoItemFileName3 = INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_1200kbps_AACLC_48khz_64kbps_m_1_17.3gp";
- final String ImageItemFileName4 = INPUT_FILE_PATH +
- "IMG_640x480.jpg";
- final String ImageItemFileName5 = INPUT_FILE_PATH +
- "IMG_176x144.jpg";
- final String OverlayFile6 = INPUT_FILE_PATH +
- "IMG_640x480_Overlay1.png";
- final String[] loggingInfo = new String[1];
- int i = 0;
- final String[] projectPath = new String[10];
- writeTestCaseHeader("testStressLoadAndSave");
- getBeginMemory();
- for( i=0; i < 10; i++){
-
- projectPath[i] =
- mVideoEditorHelper.createRandomFile(PROJECT_LOCATION);
- final VideoEditor mVideoEditor1 =
- mVideoEditorHelper.createVideoEditor(projectPath[i]);
-
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor1,
- "m1", VideoItemFileName1, renderingMode);
- mVideoEditor1.addMediaItem(mediaItem1);
- mediaItem1.setExtractBoundaries(0, 10000);
-
- final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor1,
- "m2", VideoItemFileName2, renderingMode);
- mVideoEditor1.addMediaItem(mediaItem2);
- mediaItem2.setExtractBoundaries(mediaItem2.getDuration()/4,
- mediaItem2.getDuration()/2);
-
- final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor1,
- "m3", VideoItemFileName3, renderingMode);
- mVideoEditor1.addMediaItem(mediaItem3);
- mediaItem3.setExtractBoundaries(mediaItem3.getDuration()/2,
- mediaItem3.getDuration());
-
- final MediaImageItem mediaItem4 = new MediaImageItem(mVideoEditor1,
- "m4", ImageItemFileName4, 5000, renderingMode);
- mVideoEditor1.addMediaItem(mediaItem4);
-
- final MediaImageItem mediaItem5 = new MediaImageItem(mVideoEditor1,
- "m5", ImageItemFileName5, 5000, renderingMode);
- mVideoEditor1.addMediaItem(mediaItem5);
-
- final EffectColor effectColor1 =
- mVideoEditorHelper.createEffectItem(mediaItem3, "effect1",
- 10000, 2000, EffectColor.TYPE_COLOR, EffectColor.GREEN);
- mediaItem3.addEffect(effectColor1);
-
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(OverlayFile6,
- 640, 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaItem4, "overlay",
- mBitmap, 4000, 1000);
- mediaItem4.addOverlay(overlayFrame);
-
- final TransitionCrossfade tranCrossfade =
- new TransitionCrossfade("transCF", mediaItem1,
- mediaItem2, 5000, Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor1.addTransition(tranCrossfade);
-
- final EffectColor effectColor2 =
- mVideoEditorHelper.createEffectItem(mediaItem4, "effect2", 0,
- mediaItem4.getDuration(), EffectColor.TYPE_COLOR,
- EffectColor.PINK);
- mediaItem4.addEffect(effectColor2);
-
- mVideoEditor1.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- mVideoEditor1.save();
- mVideoEditor1.release();
-
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- for( i=0; i<10; i++){
- final VideoEditor mVideoEditor1b =
- VideoEditorFactory.load(projectPath[i], true);
- List<MediaItem> mediaList = mVideoEditor1b.getAllMediaItems();
- assertEquals("Media Item List Size", 5, mediaList.size());
-
- mediaList.get(3).removeEffect("effect1");
- mediaList.get(3).removeEffect("effect2");
- mediaList.get(2).removeOverlay("overlay");
- mVideoEditor1b.removeTransition("transCF");
- mVideoEditor1b.removeMediaItem("m5");
- mVideoEditor1b.removeMediaItem("m4");
- mVideoEditor1b.removeMediaItem("m3");
- mVideoEditor1b.removeMediaItem("m2");
- mVideoEditor1b.removeMediaItem("m1");
- mVideoEditor1b.release();
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To stress test : Multiple Export
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressMultipleExport() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String VideoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String VideoItemFileName2 = INPUT_FILE_PATH +
- "H264_BP_800x480_15fps_512kbps_1_17.mp4";
- final String[] loggingInfo = new String[1];
- final String outFilename = mVideoEditorHelper.createRandomFile(
- mVideoEditor.getPath() + "/") + ".3gp";
- int i = 0;
- writeTestCaseHeader("testStressMultipleExport");
- getBeginMemory();
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1", VideoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
- mediaItem1.setExtractBoundaries(0, 10000);
-
- final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor,
- "m2", VideoItemFileName2, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
- mediaItem2.setExtractBoundaries(0, 15000);
-
- for ( i = 0; i < 50; i++) {
- if(i%4 ==0){
- final int aspectRatio = MediaProperties.ASPECT_RATIO_11_9;
- mVideoEditor.setAspectRatio(aspectRatio);
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_288,
- MediaProperties.BITRATE_256K,MediaProperties.ACODEC_AAC_LC,
- MediaProperties.VCODEC_H263,
- new ExportProgressListener() {
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- }
- });
- }
- if(i%4 ==1){
- final int aspectRatio = MediaProperties.ASPECT_RATIO_5_3;
- mVideoEditor.setAspectRatio(aspectRatio);
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_144,
- MediaProperties.BITRATE_384K,MediaProperties.ACODEC_AAC_LC,
- MediaProperties.VCODEC_MPEG4,
- new ExportProgressListener() {
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- }
- });
- }
- if(i%4 ==2){
- final int aspectRatio = MediaProperties.ASPECT_RATIO_11_9;
- mVideoEditor.setAspectRatio(aspectRatio);
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_144,
- MediaProperties.BITRATE_512K,MediaProperties.ACODEC_AAC_LC,
- MediaProperties.VCODEC_H264,
- new ExportProgressListener() {
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- }
- });
- }
- if(i%4 ==3){
- final int aspectRatio = MediaProperties.ASPECT_RATIO_3_2;
- mVideoEditor.setAspectRatio(aspectRatio);
- mVideoEditor.export(outFilename, MediaProperties.HEIGHT_480,
- MediaProperties.BITRATE_800K,MediaProperties.ACODEC_AAC_LC,
- MediaProperties.VCODEC_H264,
- new ExportProgressListener() {
- public void onProgress(VideoEditor ve, String outFileName,
- int progress) {
- }
- });
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- mVideoEditor.removeMediaItem("m2");
- mVideoEditor.removeMediaItem("m1");
-
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To stress test Media Item,Overlays,Transitions and Ken Burn
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressOverlayTransKenBurn() throws Exception {
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String VideoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_640x480_30fps_256kbps_1_17.mp4";
- final String ImageItemFileName2 = INPUT_FILE_PATH +
- "IMG_640x480.jpg";
- final String OverlayFile3 = INPUT_FILE_PATH +
- "IMG_640x480_Overlay1.png";
- final String audioFilename4 = INPUT_FILE_PATH +
- "AACLC_44.1kHz_256kbps_s_1_17.mp4";
- int i = 0;
- final String[] loggingInfo = new String[1];
- writeTestCaseHeader("testStressOverlayTransKenBurn");
- getBeginMemory();
- for ( i = 0; i < 10; i++) {
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1" + i, VideoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaItem1);
- mediaItem1.setExtractBoundaries(0, 10000);
-
- final MediaImageItem mediaItem2 = new MediaImageItem(mVideoEditor,
- "m2" + i, ImageItemFileName2, 10000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem2);
-
- final EffectColor effectColor1 =
- mVideoEditorHelper.createEffectItem(mediaItem1, "effect1"+i,
- (mediaItem1.getDuration() - 4000), 4000,
- EffectColor.TYPE_SEPIA, 0);
- mediaItem1.addEffect(effectColor1);
-
- final TransitionCrossfade tranCrossfade =
- new TransitionCrossfade("transCF" + i, mediaItem1,
- mediaItem2, 4000, Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(tranCrossfade);
-
- final Bitmap mBitmap = mVideoEditorHelper.getBitmap(OverlayFile3,
- 640, 480);
- final OverlayFrame overlayFrame =
- mVideoEditorHelper.createOverlay(mediaItem1, "overlay" + i,
- mBitmap, 1000, 5000);
- mediaItem1.addOverlay(overlayFrame);
-
- final Rect startRect = new Rect((mediaItem2.getHeight() / 3),
- (mediaItem2.getWidth() / 3), (mediaItem2.getHeight() / 2),
- (mediaItem2.getWidth() / 2));
- final Rect endRect = new Rect(0, 0, mediaItem2.getWidth(),
- mediaItem2.getHeight());
-
- final EffectKenBurns kbEffectOnMediaItem = new EffectKenBurns(
- mediaItem2, "KBOnM2" + i, startRect, endRect, 500,
- (mediaItem2.getDuration()-500));
- mediaItem2.addEffect(kbEffectOnMediaItem);
-
- if(i == 5) {
- final AudioTrack audioTrack1 = new AudioTrack(mVideoEditor,
- "Audio Track1", audioFilename4);
- mVideoEditor.addAudioTrack(audioTrack1);
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- for ( i = 0; i < 10; i++) {
- MediaImageItem m2 = (MediaImageItem)mVideoEditor.getMediaItem("m2"+i);
- MediaVideoItem m1 = (MediaVideoItem)mVideoEditor.getMediaItem("m1"+i);
- m2.removeEffect("KBOnM2" + i);
- m1.removeOverlay("overlay" + i);
- mVideoEditor.removeTransition("transCF" + i);
- m1.removeEffect("effect1" + i);
- mVideoEditor.removeMediaItem("m2" + i);
- mVideoEditor.removeMediaItem("m1" + i);
- if(i == 5) {
- mVideoEditor.removeAudioTrack("Audio Track1");
- }
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To test the performance : With an audio track with Video
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressAudioTrackVideo() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "H264_BP_1080x720_30fps_800kbps_1_17.mp4";
- final String audioFilename1 = INPUT_FILE_PATH +
- "AACLC_44.1kHz_256kbps_s_1_17.mp4";
- final String audioFilename2 = INPUT_FILE_PATH +
- "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int audioVolume = 50;
- final String[] loggingInfo = new String[1];
- int i = 1;
- writeTestCaseHeader("testStressAudioTrackVideo");
- getBeginMemory();
- final MediaVideoItem mediaVideoItem = new MediaVideoItem(mVideoEditor,
- "mediaItem1", videoItemFileName1, renderingMode);
- mVideoEditor.addMediaItem(mediaVideoItem);
-
- final AudioTrack audioTrack1 = new AudioTrack(mVideoEditor,
- "Audio Track1", audioFilename1);
- audioTrack1.disableDucking();
- audioTrack1.setVolume(audioVolume);
- mVideoEditor.addAudioTrack(audioTrack1);
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
-
- mVideoEditor.removeAudioTrack("Audio Track1");
-
- final AudioTrack audioTrack2 = new AudioTrack(mVideoEditor,
- "Audio Track2", audioFilename2);
- audioTrack2.enableLoop();
-
- mVideoEditor.generatePreview(new MediaProcessingProgressListener() {
- public void onProgress(Object item, int action, int progress) {
- }
- });
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- mVideoEditor.removeMediaItem("mediaItem1");
-
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To Test Stress : Story Board creation with out preview or export
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressStoryBoard() throws Exception {
- final String videoItemFileName1 = INPUT_FILE_PATH +
- "MPEG4_SP_720x480_30fps_280kbps_AACLC_48kHz_161kbps_s_0_26.mp4";
- final String videoItemFileName2 = INPUT_FILE_PATH +
- "MPEG4_SP_854x480_15fps_256kbps_AACLC_16khz_48kbps_s_0_26.mp4";
- final String videoItemFileName3= INPUT_FILE_PATH +
- "MPEG4_SP_640x480_15fps_512kbps_AACLC_48khz_132kbps_s_0_26.mp4";
- final String imageItemFileName4 = INPUT_FILE_PATH +
- "IMG_1600x1200.jpg";
- final String imageItemFileName5 = INPUT_FILE_PATH +
- "IMG_176x144.jpg";
- final String audioFilename6 = INPUT_FILE_PATH +
- "AMRNB_8KHz_12.2Kbps_m_1_17.3gp";
- final String audioFilename7 = INPUT_FILE_PATH +
- "AACLC_44.1kHz_256kbps_s_1_17.mp4";
-
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final int audioVolume = 50;
- final String[] loggingInfo = new String[1];
- int i = 1;
-
- writeTestCaseHeader("testStressStoryBoard");
- getBeginMemory();
- final MediaVideoItem mediaItem1 = new MediaVideoItem(mVideoEditor,
- "m1", videoItemFileName1, renderingMode);
- mediaItem1.setExtractBoundaries(0, 10000);
- mVideoEditor.addMediaItem(mediaItem1);
-
- final MediaVideoItem mediaItem2 = new MediaVideoItem(mVideoEditor,
- "m2", videoItemFileName2, renderingMode);
- mediaItem2.setExtractBoundaries(mediaItem2.getDuration()/4,
- mediaItem2.getDuration()/2);
- mVideoEditor.addMediaItem(mediaItem2);
-
- final MediaVideoItem mediaItem3 = new MediaVideoItem(mVideoEditor,
- "m3", videoItemFileName3, renderingMode);
- mediaItem3.setExtractBoundaries(mediaItem3.getDuration()/2,
- mediaItem3.getDuration());
- mVideoEditor.addMediaItem(mediaItem3);
-
- final MediaImageItem mediaItem4 = new MediaImageItem(mVideoEditor,
- "m4", imageItemFileName4, 5000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem4);
-
- final MediaImageItem mediaItem5 = new MediaImageItem(mVideoEditor,
- "m5", imageItemFileName5, 5000, renderingMode);
- mVideoEditor.addMediaItem(mediaItem5);
-
- final TransitionCrossfade tranCrossfade =
- new TransitionCrossfade("transCF", mediaItem2, mediaItem3, 2500,
- Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(tranCrossfade);
-
- final TransitionCrossfade tranCrossfade1 =
- new TransitionCrossfade("transCF1", mediaItem3, mediaItem4, 2500,
- Transition.BEHAVIOR_MIDDLE_FAST);
- mVideoEditor.addTransition(tranCrossfade1);
-
- final AudioTrack audioTrack1 = new AudioTrack(mVideoEditor,
- "Audio Track1", audioFilename6);
- mVideoEditor.addAudioTrack(audioTrack1);
-
- mVideoEditor.removeAudioTrack("Audio Track1");
- final AudioTrack audioTrack2 = new AudioTrack(mVideoEditor,
- "Audio Track2", audioFilename7);
- mVideoEditor.addAudioTrack(audioTrack2);
- audioTrack2.enableLoop();
- getAfterMemory_updateLog(loggingInfo, false, i);
-
- /** Remove items and check for memory leak if any */
- getBeginMemory();
- mVideoEditor.removeAudioTrack("Audio Track2");
- mVideoEditor.removeTransition("transCF");
- mVideoEditor.removeTransition("transCF1");
- mVideoEditor.removeMediaItem("m5");
- mVideoEditor.removeMediaItem("m4");
- mVideoEditor.removeMediaItem("m3");
- mVideoEditor.removeMediaItem("m2");
- mVideoEditor.removeMediaItem("m1");
-
- getAfterMemory_updateLog(loggingInfo, true, i);
- }
-
- /**
- * To test the performance : With an audio track Only
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressAudioTrackOnly() throws Exception {
-
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String AudioItemFileName1 = INPUT_FILE_PATH +
- "AACLC_44.1kHz_256kbps_s_1_17.mp4";
- final String[] loggingInfo = new String[1];
- int i = 0;
- writeTestCaseHeader("testStressAudioTrackOnly");
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- final AudioTrack mediaItem1 = new AudioTrack(mVideoEditor,
- "m1" + i, AudioItemFileName1);
- mVideoEditor.addAudioTrack(mediaItem1);
- mediaItem1.enableLoop();
- mVideoEditor.removeAudioTrack("m1" + i);
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
-
- /**
- * This method will test thumbnail list extraction in a loop = 200 for Image
- * Item
- *
- * @throws Exception
- */
- @LargeTest
- public void testStressThumbnailImageItem() throws Exception {
- final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg";
- final int renderingMode = MediaItem.RENDERING_MODE_BLACK_BORDER;
- final String[] loggingInfo = new String[1];
- int i = 0;
- final MediaImageItem mediaImageItem = new MediaImageItem(mVideoEditor,
- "m1", imageItemFileName, 5000, renderingMode);
- writeTestCaseHeader("testStressThumbnailImageItem");
- getBeginMemory();
- for ( i = 0; i < 50; i++) {
- if (i % 4 == 0) {
- final Bitmap[] thumbNails = mediaImageItem.getThumbnailList(
- mediaImageItem.getWidth() / 2 ,
- mediaImageItem.getHeight() / 2, i, 5000, 2);
- // Recycle this Bitmap array
- for (int i1 = 0; i1 < thumbNails.length; i1++) {
- thumbNails[i1].recycle();
- }
- }
- if (i % 4 == 1) {
- final Bitmap[] thumbNails = mediaImageItem.getThumbnailList(
- mediaImageItem.getWidth() / 2,
- mediaImageItem.getHeight() * 3, i, 5000, 2);
- // Recycle this Bitmap array
- for (int i1 = 0; i1 < thumbNails.length; i1++) {
- thumbNails[i1].recycle();
- }
- }
- if (i % 4 == 2) {
- final Bitmap[] thumbNails = mediaImageItem.getThumbnailList(
- mediaImageItem.getWidth() * 2,
- mediaImageItem.getHeight() / 3, i, 5000, 2);
- // Recycle this Bitmap array
- for (int i1 = 0; i1 < thumbNails.length; i1++) {
- thumbNails[i1].recycle();
- }
- }
- if (i % 4 == 3) {
- final Bitmap[] thumbNails = mediaImageItem.getThumbnailList(
- mediaImageItem.getWidth(),
- mediaImageItem.getHeight(), i, 5000, 2);
- // Recycle this Bitmap array
- for (int i1 = 0; i1 < thumbNails.length; i1++) {
- thumbNails[i1].recycle();
- }
- }
- if (i % 10 == 0) {
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
- }
- getAfterMemory_updateLog(loggingInfo, false, i);
- }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index edfa36a..45df065 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -309,7 +309,7 @@
});
// rational (n) -- in particular rational x 9
- checkKeyGetAndSetArray("android.sensor.calibrationTransform", Rational[].class,
+ checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
new Rational[] {
new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index fb4de9e..acfcd83 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -123,10 +123,13 @@
ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue,
ASensorEvent* events, size_t count)
{
- return static_cast<SensorEventQueue*>(queue)->read(events, count);
+ ssize_t actual = static_cast<SensorEventQueue*>(queue)->read(events, count);
+ if (actual > 0) {
+ static_cast<SensorEventQueue*>(queue)->sendAck(events, actual);
+ }
+ return actual;
}
-
/*****************************************************************************/
const char* ASensor_getName(ASensor const* sensor)
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index a9322b9..1406f6b 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -878,7 +878,7 @@
protected int[] mConfigSpec;
private int[] filterConfigSpec(int[] configSpec) {
- if (mEGLContextClientVersion != 2) {
+ if (mEGLContextClientVersion != 2 && mEGLContextClientVersion != 3) {
return configSpec;
}
/* We know none of the subclasses define EGL_RENDERABLE_TYPE.
@@ -888,7 +888,11 @@
int[] newConfigSpec = new int[len + 2];
System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
- newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
+ if (mEGLContextClientVersion == 2) {
+ newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT; /* EGL_OPENGL_ES2_BIT */
+ } else {
+ newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */
+ }
newConfigSpec[len+1] = EGL10.EGL_NONE;
return newConfigSpec;
}
diff --git a/packages/DefaultContainerService/Android.mk b/packages/DefaultContainerService/Android.mk
index 9961168..0de2c1f 100644
--- a/packages/DefaultContainerService/Android.mk
+++ b/packages/DefaultContainerService/Android.mk
@@ -7,7 +7,7 @@
LOCAL_PACKAGE_NAME := DefaultContainerService
-LOCAL_REQUIRED_MODULES := libdefcontainer_jni
+LOCAL_JNI_SHARED_LIBRARIES := libdefcontainer_jni
LOCAL_CERTIFICATE := platform
diff --git a/packages/DefaultContainerService/res/values-th/strings.xml b/packages/DefaultContainerService/res/values-th/strings.xml
index 3a7080c..621d7ed 100644
--- a/packages/DefaultContainerService/res/values-th/strings.xml
+++ b/packages/DefaultContainerService/res/values-th/strings.xml
@@ -20,5 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="service_name" msgid="4841491635055379553">"ตัวช่วยเหลือของการเข้าถึงแพคเกจ"</string>
+ <string name="service_name" msgid="4841491635055379553">"ตัวช่วยเหลือของการเข้าถึงแพ็กเกจ"</string>
</resources>
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 6b77a7c..159ee66 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -9,18 +9,17 @@
android:label="@string/app_label"
android:supportsRtl="true">
- <!-- TODO: allow rotation when state saving is in better shape -->
<activity
android:name=".DocumentsActivity"
android:theme="@style/Theme"
android:icon="@drawable/ic_doc_text">
- <intent-filter android:priority="100">
+ <intent-filter>
<action android:name="android.intent.action.OPEN_DOCUMENT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="*/*" />
</intent-filter>
- <intent-filter android:priority="100">
+ <intent-filter>
<action android:name="android.intent.action.CREATE_DOCUMENT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.OPENABLE" />
@@ -33,6 +32,10 @@
<data android:mimeType="*/*" />
</intent-filter>
<intent-filter>
+ <action android:name="android.intent.action.PICK_DIRECTORY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
<action android:name="android.provider.action.MANAGE_ROOT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.document/root" />
@@ -57,14 +60,5 @@
<data android:scheme="package" />
</intent-filter>
</receiver>
-
- <!-- TODO: remove when we have real clients -->
- <activity android:name=".TestActivity" android:enabled="false">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
</application>
</manifest>
diff --git a/packages/DocumentsUI/res/layout/fragment_pick.xml b/packages/DocumentsUI/res/layout/fragment_pick.xml
new file mode 100644
index 0000000..4a2fd03
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/fragment_pick.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <!-- Le sigh, this really should be an asset -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="#ccc" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:baselineAligned="false"
+ android:gravity="center_vertical"
+ android:background="#ddd"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall">
+
+ <Button
+ android:id="@android:id/button1"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?android:attr/selectableItemBackground"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAllCaps="false"
+ android:padding="8dp" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 41fd63a..65dbe18 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Stoor"</string>
<string name="menu_share" msgid="3075149983979628146">"Deel"</string>
<string name="menu_delete" msgid="8138799623850614177">"Vee uit"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> gekies"</string>
<string name="sort_name" msgid="9183560467917256779">"Volgens naam"</string>
<string name="sort_date" msgid="586080032956151448">"Volgens datum gewysig"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index c77a8ee..1003c0a 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"አስቀምጥ"</string>
<string name="menu_share" msgid="3075149983979628146">"አጋራ"</string>
<string name="menu_delete" msgid="8138799623850614177">"ሰርዝ"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ተመርጠዋል"</string>
<string name="sort_name" msgid="9183560467917256779">"በስም"</string>
<string name="sort_date" msgid="586080032956151448">"በተለወጠበት ቀን"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index c59c0ee..e939b3e 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"حفظ"</string>
<string name="menu_share" msgid="3075149983979628146">"مشاركة"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"تم تحديد <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string>
<string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index c3242b2..18cdb9c 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Запазване"</string>
<string name="menu_share" msgid="3075149983979628146">"Споделяне"</string>
<string name="menu_delete" msgid="8138799623850614177">"Изтриване"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Избрахте <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"По име"</string>
<string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 68c7b0e..b883869 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Desa"</string>
<string name="menu_share" msgid="3075149983979628146">"Comparteix"</string>
<string name="menu_delete" msgid="8138799623850614177">"Suprimeix"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Seleccionats: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Per nom"</string>
<string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index f089c8b..3827b94 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Uložit"</string>
<string name="menu_share" msgid="3075149983979628146">"Sdílet"</string>
<string name="menu_delete" msgid="8138799623850614177">"Smazat"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Vybráno: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string>
<string name="sort_date" msgid="586080032956151448">"Podle data úpravy"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 816f9a7..25c74e3 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Gem"</string>
<string name="menu_share" msgid="3075149983979628146">"Del"</string>
<string name="menu_delete" msgid="8138799623850614177">"Slet"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> er valgt"</string>
<string name="sort_name" msgid="9183560467917256779">"Efter navn"</string>
<string name="sort_date" msgid="586080032956151448">"Efter ændringsdato"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index e43a1e2..93fad32 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Speichern"</string>
<string name="menu_share" msgid="3075149983979628146">"Teilen"</string>
<string name="menu_delete" msgid="8138799623850614177">"Löschen"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ausgewählt"</string>
<string name="sort_name" msgid="9183560467917256779">"Nach Name"</string>
<string name="sort_date" msgid="586080032956151448">"Nach Änderungsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 5a91484..db83aea 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Αποθήκευση"</string>
<string name="menu_share" msgid="3075149983979628146">"Κοινοποίηση"</string>
<string name="menu_delete" msgid="8138799623850614177">"Διαγραφή"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Επιλέχθηκαν <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Κατά όνομα"</string>
<string name="sort_date" msgid="586080032956151448">"Κατά ημερομηνία τροποποίησης"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index a95e7f1..a0fe3b7 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Save"</string>
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index a95e7f1..a0fe3b7 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Save"</string>
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string>
<string name="sort_name" msgid="9183560467917256779">"By name"</string>
<string name="sort_date" msgid="586080032956151448">"By date modified"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 4a3ff33..3319011 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> seleccionado(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 1682542..7189f1d 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Seleccionado: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
<string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 5412956..a12b695 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Salvesta"</string>
<string name="menu_share" msgid="3075149983979628146">"Jaga"</string>
<string name="menu_delete" msgid="8138799623850614177">"Kustuta"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> on valitud"</string>
<string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string>
<string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index c922b37..ba04522 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"ذخیره"</string>
<string name="menu_share" msgid="3075149983979628146">"اشتراکگذاری"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> انتخاب شد"</string>
<string name="sort_name" msgid="9183560467917256779">"بر اساس نام"</string>
<string name="sort_date" msgid="586080032956151448">"بر اساس تاریخ اصلاح"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 5e40ecd..8ea10be 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Tallenna"</string>
<string name="menu_share" msgid="3075149983979628146">"Jaa"</string>
<string name="menu_delete" msgid="8138799623850614177">"Poista"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valittua"</string>
<string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string>
<string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index a837379..0549707 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string>
<string name="menu_share" msgid="3075149983979628146">"Partager"</string>
<string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> sélectionné(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
<string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index ff9aeda..292ec86 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string>
<string name="menu_share" msgid="3075149983979628146">"Partager"</string>
<string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> élément(s) sélectionné(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
<string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 8d7fcba..579bd37 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"सहेजें"</string>
<string name="menu_share" msgid="3075149983979628146">"साझा करें"</string>
<string name="menu_delete" msgid="8138799623850614177">"हटाएं"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> चयनित"</string>
<string name="sort_name" msgid="9183560467917256779">"नाम के अनुसार"</string>
<string name="sort_date" msgid="586080032956151448">"बदलाव के दिनांक के अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 73c2f04..6baae95 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Spremi"</string>
<string name="menu_share" msgid="3075149983979628146">"Dijeli"</string>
<string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Odabrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Po korisniku"</string>
<string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index db7854b..b8ef2d4 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Mentés"</string>
<string name="menu_share" msgid="3075149983979628146">"Megosztás"</string>
<string name="menu_delete" msgid="8138799623850614177">"Törlés"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> kiválasztva"</string>
<string name="sort_name" msgid="9183560467917256779">"Név szerint"</string>
<string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index c683f3e..69fdfb6 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Պահել"</string>
<string name="menu_share" msgid="3075149983979628146">"Համօգտագործել"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ջնջել"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ընտրված"</string>
<string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string>
<string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index d9f4475..d5c69bf 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Simpan"</string>
<string name="menu_share" msgid="3075149983979628146">"Bagikan"</string>
<string name="menu_delete" msgid="8138799623850614177">"Hapus"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string>
<string name="sort_name" msgid="9183560467917256779">"Menurut nama"</string>
<string name="sort_date" msgid="586080032956151448">"Menurut tanggal diubah"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index baca387..9d1fc94 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Salva"</string>
<string name="menu_share" msgid="3075149983979628146">"Condividi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Elimina"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selezionati"</string>
<string name="sort_name" msgid="9183560467917256779">"Per nome"</string>
<string name="sort_date" msgid="586080032956151448">"Per data di modifica"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 712c060..af47c6c 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"שמור"</string>
<string name="menu_share" msgid="3075149983979628146">"שתף"</string>
<string name="menu_delete" msgid="8138799623850614177">"מחק"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> נבחרו"</string>
<string name="sort_name" msgid="9183560467917256779">"לפי שם"</string>
<string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 996496d..ca64914 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"保存"</string>
<string name="menu_share" msgid="3075149983979628146">"共有"</string>
<string name="menu_delete" msgid="8138799623850614177">"削除"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>件選択済み"</string>
<string name="sort_name" msgid="9183560467917256779">"名前順"</string>
<string name="sort_date" msgid="586080032956151448">"更新日順"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index f3e1274..3e3d509 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"შენახვა"</string>
<string name="menu_share" msgid="3075149983979628146">"გაზიარება"</string>
<string name="menu_delete" msgid="8138799623850614177">"წაშლა"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> მონიშნული"</string>
<string name="sort_name" msgid="9183560467917256779">"სახელით"</string>
<string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 80f3698..2ecbba7 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"រក្សាទុក"</string>
<string name="menu_share" msgid="3075149983979628146">"ចែករំលែក"</string>
<string name="menu_delete" msgid="8138799623850614177">"លុប"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"បានជ្រើស <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"តាមឈ្មោះ"</string>
<string name="sort_date" msgid="586080032956151448">"តាមកាលបរិច្ឆេទបានកែប្រែ"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 2cd0d44..0ece450 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"저장"</string>
<string name="menu_share" msgid="3075149983979628146">"공유"</string>
<string name="menu_delete" msgid="8138799623850614177">"삭제"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>개 선택됨"</string>
<string name="sort_name" msgid="9183560467917256779">"이름순"</string>
<string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 9a6f32f..0bc0b8b 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"ບັນທຶກ"</string>
<string name="menu_share" msgid="3075149983979628146">"ແບ່ງປັນ"</string>
<string name="menu_delete" msgid="8138799623850614177">"ລຶບ"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"ເລືອກແລ້ວ <xliff:g id="COUNT">%1$d</xliff:g> ລາຍການ"</string>
<string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string>
<string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index f861b99..04825f9 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Išsaugoti"</string>
<string name="menu_share" msgid="3075149983979628146">"Bendrinti"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ištrinti"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Pasirinkta: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string>
<string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 651a59fe0d..5157327 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Saglabāt"</string>
<string name="menu_share" msgid="3075149983979628146">"Kopīgot"</string>
<string name="menu_delete" msgid="8138799623850614177">"Dzēst"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Atlasīts: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string>
<string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 22c9fcd..8fd8f52 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Хадгалах"</string>
<string name="menu_share" msgid="3075149983979628146">"Хуваалцах"</string>
<string name="menu_delete" msgid="8138799623850614177">"Устгах"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> сонгогдсон"</string>
<string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string>
<string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 7e09c57..48e30305 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Simpan"</string>
<string name="menu_share" msgid="3075149983979628146">"Kongsi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Padam"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string>
<string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string>
<string name="sort_date" msgid="586080032956151448">"Diubah suai mengikut tarikh"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 8831bd8..09a11d5 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Lagre"</string>
<string name="menu_share" msgid="3075149983979628146">"Del"</string>
<string name="menu_delete" msgid="8138799623850614177">"Slett"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valgt"</string>
<string name="sort_name" msgid="9183560467917256779">"Etter navn"</string>
<string name="sort_date" msgid="586080032956151448">"«Etter dato» endret"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 08862e8..ca626a86 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Opslaan"</string>
<string name="menu_share" msgid="3075149983979628146">"Delen"</string>
<string name="menu_delete" msgid="8138799623850614177">"Verwijderen"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> geselecteerd"</string>
<string name="sort_name" msgid="9183560467917256779">"Op naam"</string>
<string name="sort_date" msgid="586080032956151448">"Op aanpassingsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 42cec9c..7a7978b 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Zapisz"</string>
<string name="menu_share" msgid="3075149983979628146">"Udostępnij"</string>
<string name="menu_delete" msgid="8138799623850614177">"Usuń"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Wybrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
<string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index f1be722..0443c35 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Guardar"</string>
<string name="menu_share" msgid="3075149983979628146">"Partilhar"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionado(s)"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 78fcaf8..f9038d1 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Salvar"</string>
<string name="menu_share" msgid="3075149983979628146">"Compartilhar"</string>
<string name="menu_delete" msgid="8138799623850614177">"Excluir"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionados"</string>
<string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
<string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 5fd44c8..26cd77f 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Salvați"</string>
<string name="menu_share" msgid="3075149983979628146">"Distribuiți"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ștergeți"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selectate"</string>
<string name="sort_name" msgid="9183560467917256779">"După nume"</string>
<string name="sort_date" msgid="586080032956151448">"După data modificării"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 85fd70e0..f8e1f1b 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Сохранить"</string>
<string name="menu_share" msgid="3075149983979628146">"Поделиться"</string>
<string name="menu_delete" msgid="8138799623850614177">"Удалить"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Выбрано: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"По названию"</string>
<string name="sort_date" msgid="586080032956151448">"По дате изменения"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 4b5ebcd..cb4b718 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Uložiť"</string>
<string name="menu_share" msgid="3075149983979628146">"Zdieľať"</string>
<string name="menu_delete" msgid="8138799623850614177">"Odstrániť"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Vybraté: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string>
<string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index f984a0a..a6dc20b 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Shrani"</string>
<string name="menu_share" msgid="3075149983979628146">"Skupna raba"</string>
<string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Št. izbranih: <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Po imenu"</string>
<string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index eb0b197..06e0d08 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Сачувај"</string>
<string name="menu_share" msgid="3075149983979628146">"Дели"</string>
<string name="menu_delete" msgid="8138799623850614177">"Избриши"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Изабрано је <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Према имену"</string>
<string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 7aa5c50..da8432e 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Spara"</string>
<string name="menu_share" msgid="3075149983979628146">"Dela"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ta bort"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Har valt <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Efter namn"</string>
<string name="sort_date" msgid="586080032956151448">"Efter ändringsdatum"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index 299fda7..c769a59 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Hifadhi"</string>
<string name="menu_share" msgid="3075149983979628146">"Shiriki"</string>
<string name="menu_delete" msgid="8138799623850614177">"Futa"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> zimechaguliwa"</string>
<string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string>
<string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 6ac8810..bf92893 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"บันทึก"</string>
<string name="menu_share" msgid="3075149983979628146">"แชร์"</string>
<string name="menu_delete" msgid="8138799623850614177">"ลบ"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"เลือกไว้ <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string>
<string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index e0fd8c8..bc363e7 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"I-save"</string>
<string name="menu_share" msgid="3075149983979628146">"Ibahagi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Tanggalin"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ang pinili"</string>
<string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string>
<string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 699a5cd..5d7a2be 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Kaydet"</string>
<string name="menu_share" msgid="3075149983979628146">"Paylaş"</string>
<string name="menu_delete" msgid="8138799623850614177">"Sil"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> tane seçildi"</string>
<string name="sort_name" msgid="9183560467917256779">"Ada göre"</string>
<string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index f87b6a2..dbd44b7 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Зберегти"</string>
<string name="menu_share" msgid="3075149983979628146">"Поділитися"</string>
<string name="menu_delete" msgid="8138799623850614177">"Видалити"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Вибрано <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"За назвою"</string>
<string name="sort_date" msgid="586080032956151448">"За датою змінення"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 41e29fa..919708f 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Lưu"</string>
<string name="menu_share" msgid="3075149983979628146">"Chia sẻ"</string>
<string name="menu_delete" msgid="8138799623850614177">"Xóa"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"Đã chọn <xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="sort_name" msgid="9183560467917256779">"Theo tên"</string>
<string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 742cda7..a916b87 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"保存"</string>
<string name="menu_share" msgid="3075149983979628146">"分享"</string>
<string name="menu_delete" msgid="8138799623850614177">"删除"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"已选择<xliff:g id="COUNT">%1$d</xliff:g>项"</string>
<string name="sort_name" msgid="9183560467917256779">"按名称"</string>
<string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 67ed587..7cae910 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"儲存"</string>
<string name="menu_share" msgid="3075149983979628146">"分享"</string>
<string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個"</string>
<string name="sort_name" msgid="9183560467917256779">"按名稱"</string>
<string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 75ecbcf..387fdba 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"儲存"</string>
<string name="menu_share" msgid="3075149983979628146">"共用"</string>
<string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個項目"</string>
<string name="sort_name" msgid="9183560467917256779">"依名稱"</string>
<string name="sort_date" msgid="586080032956151448">"依修改日期"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index bedd2cdf..564b2d7 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -29,6 +29,8 @@
<string name="menu_save" msgid="2394743337684426338">"Londoloza"</string>
<string name="menu_share" msgid="3075149983979628146">"Yabelana"</string>
<string name="menu_delete" msgid="8138799623850614177">"Susa"</string>
+ <!-- no translation found for menu_select (8711270657353563424) -->
+ <skip />
<string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> okukhethiwe"</string>
<string name="sort_name" msgid="9183560467917256779">"Ngegama"</string>
<string name="sort_date" msgid="586080032956151448">"Ngedethi yokuguqula"</string>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 92c30ba..c1a9d72 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -44,6 +44,8 @@
<string name="menu_share">Share</string>
<!-- Menu item title that deletes the selected documents [CHAR LIMIT=24] -->
<string name="menu_delete">Delete</string>
+ <!-- Menu item title that selects the current directory [CHAR LIMIT=48] -->
+ <string name="menu_select">Select \"<xliff:g id="directory" example="My Directory">^1</xliff:g>\"</string>
<!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
<string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 4212e96..9f76991 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -24,6 +24,7 @@
import static com.android.documentsui.DocumentsActivity.State.ACTION_GET_CONTENT;
import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
import static com.android.documentsui.DocumentsActivity.State.ACTION_OPEN;
+import static com.android.documentsui.DocumentsActivity.State.ACTION_PICK_DIRECTORY;
import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
@@ -202,6 +203,8 @@
final String mimeType = getIntent().getType();
final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
SaveFragment.show(getFragmentManager(), mimeType, title);
+ } else if (mState.action == ACTION_PICK_DIRECTORY) {
+ PickFragment.show(getFragmentManager());
}
if (mState.action == ACTION_GET_CONTENT) {
@@ -209,7 +212,8 @@
moreApps.setComponent(null);
moreApps.setPackage(null);
RootsFragment.show(getFragmentManager(), moreApps);
- } else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE) {
+ } else if (mState.action == ACTION_OPEN || mState.action == ACTION_CREATE
+ || mState.action == ACTION_PICK_DIRECTORY) {
RootsFragment.show(getFragmentManager(), null);
}
@@ -236,6 +240,8 @@
mState.action = ACTION_CREATE;
} else if (Intent.ACTION_GET_CONTENT.equals(action)) {
mState.action = ACTION_GET_CONTENT;
+ } else if (Intent.ACTION_PICK_DIRECTORY.equals(action)) {
+ mState.action = ACTION_PICK_DIRECTORY;
} else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) {
mState.action = ACTION_MANAGE;
}
@@ -434,7 +440,8 @@
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setIcon(new ColorDrawable());
- if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
+ if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT
+ || mState.action == ACTION_PICK_DIRECTORY) {
actionBar.setTitle(R.string.title_open);
} else if (mState.action == ACTION_CREATE) {
actionBar.setTitle(R.string.title_save);
@@ -576,7 +583,7 @@
sortSize.setVisible(mState.showSize);
final boolean searchVisible;
- if (mState.action == ACTION_CREATE) {
+ if (mState.action == ACTION_CREATE || mState.action == ACTION_PICK_DIRECTORY) {
createDir.setVisible(cwd != null && cwd.isCreateSupported());
searchVisible = false;
@@ -586,7 +593,9 @@
list.setVisible(false);
}
- SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
+ if (mState.action == ACTION_CREATE) {
+ SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
+ }
} else {
createDir.setVisible(false);
@@ -819,7 +828,7 @@
if (cwd == null) {
// No directory means recents
- if (mState.action == ACTION_CREATE) {
+ if (mState.action == ACTION_CREATE || mState.action == ACTION_PICK_DIRECTORY) {
RecentsCreateFragment.show(fm);
} else {
DirectoryFragment.showRecentsOpen(fm, anim);
@@ -848,6 +857,15 @@
}
}
+ if (mState.action == ACTION_PICK_DIRECTORY) {
+ final PickFragment pick = PickFragment.get(fm);
+ if (pick != null) {
+ final CharSequence displayName = (mState.stack.size() <= 1) ? root.title
+ : cwd.displayName;
+ pick.setPickTarget(cwd, displayName);
+ }
+ }
+
final RootsFragment roots = RootsFragment.get(fm);
if (roots != null) {
roots.onCurrentRootChanged();
@@ -1002,12 +1020,18 @@
new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
}
+ public void onPickRequested(DocumentInfo pickTarget) {
+ final Uri viaUri = DocumentsContract.buildViaUri(pickTarget.authority,
+ pickTarget.documentId);
+ new PickFinishTask(viaUri).executeOnExecutor(getCurrentExecutor());
+ }
+
private void saveStackBlocking() {
final ContentResolver resolver = getContentResolver();
final ContentValues values = new ContentValues();
final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
- if (mState.action == ACTION_CREATE) {
+ if (mState.action == ACTION_CREATE || mState.action == ACTION_PICK_DIRECTORY) {
// Remember stack for last create
values.clear();
values.put(RecentColumns.KEY, mState.stack.buildKey());
@@ -1040,6 +1064,11 @@
if (mState.action == ACTION_GET_CONTENT) {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ } else if (mState.action == ACTION_PICK_DIRECTORY) {
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
} else {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
@@ -1121,6 +1150,25 @@
}
}
+ private class PickFinishTask extends AsyncTask<Void, Void, Void> {
+ private final Uri mUri;
+
+ public PickFinishTask(Uri uri) {
+ mUri = uri;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ saveStackBlocking();
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ onFinished(mUri);
+ }
+ }
+
public static class State implements android.os.Parcelable {
public int action;
public String[] acceptMimes;
@@ -1154,7 +1202,8 @@
public static final int ACTION_OPEN = 1;
public static final int ACTION_CREATE = 2;
public static final int ACTION_GET_CONTENT = 3;
- public static final int ACTION_MANAGE = 4;
+ public static final int ACTION_PICK_DIRECTORY = 4;
+ public static final int ACTION_MANAGE = 5;
public static final int MODE_UNKNOWN = 0;
public static final int MODE_LIST = 1;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
new file mode 100644
index 0000000..a9e488a1
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -0,0 +1,89 @@
+/*
+ * 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.documentsui;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.Locale;
+
+/**
+ * Display pick confirmation bar, usually for selecting a directory.
+ */
+public class PickFragment extends Fragment {
+ public static final String TAG = "PickFragment";
+
+ private DocumentInfo mPickTarget;
+
+ private View mContainer;
+ private Button mPick;
+
+ public static void show(FragmentManager fm) {
+ final PickFragment fragment = new PickFragment();
+
+ final FragmentTransaction ft = fm.beginTransaction();
+ ft.replace(R.id.container_save, fragment, TAG);
+ ft.commitAllowingStateLoss();
+ }
+
+ public static PickFragment get(FragmentManager fm) {
+ return (PickFragment) fm.findFragmentByTag(TAG);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ mContainer = inflater.inflate(R.layout.fragment_pick, container, false);
+
+ mPick = (Button) mContainer.findViewById(android.R.id.button1);
+ mPick.setOnClickListener(mPickListener);
+
+ setPickTarget(null, null);
+
+ return mContainer;
+ }
+
+ private View.OnClickListener mPickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final DocumentsActivity activity = DocumentsActivity.get(PickFragment.this);
+ activity.onPickRequested(mPickTarget);
+ }
+ };
+
+ public void setPickTarget(DocumentInfo pickTarget, CharSequence displayName) {
+ mPickTarget = pickTarget;
+
+ if (mPickTarget != null) {
+ mContainer.setVisibility(View.VISIBLE);
+ final Locale locale = getResources().getConfiguration().locale;
+ final String raw = getString(R.string.menu_select).toUpperCase(locale);
+ mPick.setText(TextUtils.expandTemplate(raw, displayName));
+ } else {
+ mContainer.setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index f1dca1d..933dbe0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -104,7 +104,8 @@
mRecentsRoot.authority = null;
mRecentsRoot.rootId = null;
mRecentsRoot.icon = R.drawable.ic_root_recent;
- mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE;
+ mRecentsRoot.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE
+ | Root.FLAG_SUPPORTS_DIR_SELECTION;
mRecentsRoot.title = mContext.getString(R.string.root_recent);
mRecentsRoot.availableBytes = -1;
@@ -349,12 +350,15 @@
final List<RootInfo> matching = Lists.newArrayList();
for (RootInfo root : roots) {
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
+ final boolean supportsDir = (root.flags & Root.FLAG_SUPPORTS_DIR_SELECTION) != 0;
final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
final boolean empty = (root.flags & Root.FLAG_EMPTY) != 0;
// Exclude read-only devices when creating
if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
+ // Exclude roots that don't support directory picking
+ if (state.action == State.ACTION_PICK_DIRECTORY && !supportsDir) continue;
// Exclude advanced devices when not requested
if (!state.showAdvanced && advanced) continue;
// Exclude non-local devices when local only
diff --git a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java b/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
deleted file mode 100644
index 1a47308..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/TestActivity.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2013 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.documentsui;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.DocumentsContract;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public class TestActivity extends Activity {
- private static final String TAG = "TestActivity";
-
- private static final int CODE_READ = 42;
- private static final int CODE_WRITE = 43;
-
- private TextView mResult;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- final Context context = this;
-
- final LinearLayout view = new LinearLayout(context);
- view.setOrientation(LinearLayout.VERTICAL);
-
- mResult = new TextView(context);
- view.addView(mResult);
-
- final CheckBox multiple = new CheckBox(context);
- multiple.setText("ALLOW_MULTIPLE");
- view.addView(multiple);
- final CheckBox localOnly = new CheckBox(context);
- localOnly.setText("LOCAL_ONLY");
- view.addView(localOnly);
-
- Button button;
- button = new Button(context);
- button.setText("OPEN_DOC */*");
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("*/*");
- if (multiple.isChecked()) {
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
- }
- if (localOnly.isChecked()) {
- intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
- }
- startActivityForResult(intent, CODE_READ);
- }
- });
- view.addView(button);
-
- button = new Button(context);
- button.setText("OPEN_DOC image/*");
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("image/*");
- if (multiple.isChecked()) {
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
- }
- if (localOnly.isChecked()) {
- intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
- }
- startActivityForResult(intent, CODE_READ);
- }
- });
- view.addView(button);
-
- button = new Button(context);
- button.setText("OPEN_DOC audio/ogg");
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("audio/ogg");
- if (multiple.isChecked()) {
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
- }
- if (localOnly.isChecked()) {
- intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
- }
- startActivityForResult(intent, CODE_READ);
- }
- });
- view.addView(button);
-
- button = new Button(context);
- button.setText("OPEN_DOC text/plain, application/msword");
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("*/*");
- intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {
- "text/plain", "application/msword" });
- if (multiple.isChecked()) {
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
- }
- if (localOnly.isChecked()) {
- intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
- }
- startActivityForResult(intent, CODE_READ);
- }
- });
- view.addView(button);
-
- button = new Button(context);
- button.setText("CREATE_DOC text/plain");
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("text/plain");
- intent.putExtra(Intent.EXTRA_TITLE, "foobar.txt");
- if (localOnly.isChecked()) {
- intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
- }
- startActivityForResult(intent, CODE_WRITE);
- }
- });
- view.addView(button);
-
- button = new Button(context);
- button.setText("CREATE_DOC image/png");
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("image/png");
- intent.putExtra(Intent.EXTRA_TITLE, "mypicture.png");
- if (localOnly.isChecked()) {
- intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
- }
- startActivityForResult(intent, CODE_WRITE);
- }
- });
- view.addView(button);
-
- button = new Button(context);
- button.setText("GET_CONTENT */*");
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType("*/*");
- if (multiple.isChecked()) {
- intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
- }
- if (localOnly.isChecked()) {
- intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
- }
- startActivityForResult(Intent.createChooser(intent, "Kittens!"), CODE_READ);
- }
- });
- view.addView(button);
-
- final ScrollView scroll = new ScrollView(context);
- scroll.addView(view);
-
- setContentView(scroll);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- mResult.setText(null);
- String result = "resultCode=" + resultCode + ", data=" + String.valueOf(data);
-
- if (requestCode == CODE_READ) {
- final Uri uri = data != null ? data.getData() : null;
- if (uri != null) {
- if (DocumentsContract.isDocumentUri(this, uri)) {
- result += "; DOC_ID";
- }
- try {
- getContentResolver().takePersistableUriPermission(
- uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
- } catch (SecurityException e) {
- result += "; FAILED TO TAKE";
- Log.e(TAG, "Failed to take", e);
- }
- InputStream is = null;
- try {
- is = getContentResolver().openInputStream(uri);
- final int length = Streams.readFullyNoClose(is).length;
- result += "; read length=" + length;
- } catch (Exception e) {
- result += "; ERROR";
- Log.e(TAG, "Failed to read " + uri, e);
- } finally {
- IoUtils.closeQuietly(is);
- }
- } else {
- result += "no uri?";
- }
- } else if (requestCode == CODE_WRITE) {
- final Uri uri = data != null ? data.getData() : null;
- if (uri != null) {
- if (DocumentsContract.isDocumentUri(this, uri)) {
- result += "; DOC_ID";
- }
- try {
- getContentResolver().takePersistableUriPermission(
- uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- } catch (SecurityException e) {
- result += "; FAILED TO TAKE";
- Log.e(TAG, "Failed to take", e);
- }
- OutputStream os = null;
- try {
- os = getContentResolver().openOutputStream(uri);
- os.write("THE COMPLETE WORKS OF SHAKESPEARE".getBytes());
- } catch (Exception e) {
- result += "; ERROR";
- Log.e(TAG, "Failed to write " + uri, e);
- } finally {
- IoUtils.closeQuietly(os);
- }
- } else {
- result += "no uri?";
- }
- }
-
- Log.d(TAG, result);
- mResult.setText(result);
- }
-}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 559e052..16fc3e5 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -27,6 +27,7 @@
import android.os.CancellationSignal;
import android.os.Environment;
import android.os.FileObserver;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
@@ -143,7 +144,7 @@
final RootInfo root = new RootInfo();
root.rootId = rootId;
root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
- | Root.FLAG_SUPPORTS_SEARCH;
+ | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_DIR_SELECTION;
if (ROOT_ID_PRIMARY_EMULATED.equals(rootId)) {
root.title = getContext().getString(R.string.root_internal_storage);
} else {
@@ -240,8 +241,8 @@
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
} else {
flags |= Document.FLAG_SUPPORTS_WRITE;
+ flags |= Document.FLAG_SUPPORTS_DELETE;
}
- flags |= Document.FLAG_SUPPORTS_DELETE;
}
final String displayName = file.getName();
@@ -284,11 +285,26 @@
}
@Override
+ public boolean isChildDocument(String parentDocId, String docId) {
+ try {
+ final File parent = getFileForDocId(parentDocId).getCanonicalFile();
+ final File doc = getFileForDocId(docId).getCanonicalFile();
+ return FileUtils.contains(parent, doc);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(
+ "Failed to determine if " + docId + " is child of " + parentDocId + ": " + e);
+ }
+ }
+
+ @Override
public String createDocument(String docId, String mimeType, String displayName)
throws FileNotFoundException {
final File parent = getFileForDocId(docId);
- File file;
+ if (!parent.isDirectory()) {
+ throw new IllegalArgumentException("Parent document isn't a directory");
+ }
+ File file;
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
file = new File(parent, displayName);
if (!file.mkdir()) {
@@ -317,6 +333,7 @@
@Override
public void deleteDocument(String docId) throws FileNotFoundException {
+ // TODO: extend to delete directories
final File file = getFileForDocId(docId);
if (!file.delete()) {
throw new IllegalStateException("Failed to delete " + file);
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-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index d12f9bf..bd08eae 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -119,7 +119,7 @@
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
- <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (адреса е-поште)"</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (имејл адреса)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
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 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/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
index 2e4dbdf..ede23ef 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
@@ -27,11 +27,10 @@
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.MutableInt;
import android.view.View;
import android.widget.TextView;
-import libcore.util.MutableInt;
-
import java.lang.ref.WeakReference;
import com.android.internal.widget.LockPatternUtils;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 73c2840..ba67a82 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -215,8 +215,29 @@
mUserHasTrust.put(userId, enabled);
}
+ private boolean isTrustDisabled(int userId) {
+ final DevicePolicyManager dpm =
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ // TODO once UI is finalized
+ final boolean disabledByGlobalActions = false;
+ final boolean disabledBySettings = false;
+
+ // Don't allow trust agent if device is secured with a SIM PIN. This is here
+ // mainly because there's no other way to prompt the user to enter their SIM PIN
+ // once they get past the keyguard screen.
+ final boolean disabledBySimPin = isSimPinSecure();
+
+ final boolean disabledByDpm = (dpm.getKeyguardDisabledFeatures(null, userId)
+ & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+ return disabledByDpm || disabledByGlobalActions || disabledBySettings
+ || disabledBySimPin;
+ }
+ return false;
+ }
+
public boolean getUserHasTrust(int userId) {
- return mUserHasTrust.get(userId);
+ return !isTrustDisabled(userId) && mUserHasTrust.get(userId);
}
static class DisplayClientState {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e1c17cb..56f5a3a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -88,7 +88,7 @@
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
- <uses-permission android:name="android.permission.RENDER_STATS" />
+ <uses-permission android:name="android.permission.FRAME_STATS" />
<application android:label="@string/app_label">
<provider
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d371d70..327df8d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -273,7 +273,8 @@
<service
android:name=".keyguard.KeyguardService"
- android:exported="true" />
+ android:exported="true"
+ android:enabled="@bool/config_enableKeyguardService" />
<activity android:name=".Somnambulator"
android:label="@string/start_dreams"
diff --git a/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png
new file mode 100644
index 0000000..85db9c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png
new file mode 100644
index 0000000..c4941a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png
new file mode 100644
index 0000000..4618f40
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png b/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png
new file mode 100644
index 0000000..36e7e45
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/recents_task_shadow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png
new file mode 100644
index 0000000..c0bf31d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml
index 28d9625..f3c1b90 100644
--- a/packages/SystemUI/res/layout/flip_settings.xml
+++ b/packages/SystemUI/res/layout/flip_settings.xml
@@ -22,4 +22,5 @@
android:layout_height="wrap_content"
android:background="#5f000000"
android:animateLayoutChanges="true"
+ android:visibility="gone"
android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
new file mode 100644
index 0000000..809adcd
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -0,0 +1,44 @@
+<?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
+ -->
+
+<com.android.systemui.statusbar.phone.KeyguardBottomAreaView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ android:id="@+id/keyguard_bottom_area"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ >
+ <com.android.systemui.statusbar.policy.KeyButtonView
+ android:id="@+id/camera_button"
+ android:layout_height="80dp"
+ android:layout_width="80dp"
+ android:layout_gravity="bottom|right"
+ android:src="@drawable/ic_sysbar_camera"
+ android:scaleType="center"
+ android:contentDescription="@string/accessibility_camera_button"
+ systemui:glowBackground="@drawable/ic_sysbar_highlight_land" />
+
+ <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+ android:id="@+id/keyguard_indication_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="100dp"
+ android:layout_gravity="bottom|center_horizontal"
+ android:textStyle="italic"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index a6fb443..2398849 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -159,18 +159,6 @@
android:visibility="gone"
android:contentDescription="@string/accessibility_search_light"
/>
-
- <com.android.systemui.statusbar.policy.KeyButtonView
- android:id="@+id/camera_button"
- android:layout_height="match_parent"
- android:layout_width="80dp"
- android:layout_gravity="center_vertical|right"
- android:src="@drawable/ic_sysbar_camera"
- android:scaleType="center"
- android:visibility="gone"
- android:contentDescription="@string/accessibility_camera_button"
- systemui:glowBackground="@drawable/ic_sysbar_highlight_land"
- />
</FrameLayout>
<com.android.systemui.statusbar.policy.DeadZone
diff --git a/packages/SystemUI/res/layout/quick_settings.xml b/packages/SystemUI/res/layout/quick_settings.xml
deleted file mode 100644
index 75082ba..0000000
--- a/packages/SystemUI/res/layout/quick_settings.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<com.android.systemui.statusbar.phone.SettingsPanelView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/settings_panel"
- android:background="@drawable/notification_panel_bg"
- >
- <!-- TODO: Put into ScrollView -->
- <com.android.systemui.statusbar.phone.QuickSettingsScrollView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/close_handle_underlap"
- android:overScrollMode="ifContentScrolls"
- >
- <com.android.systemui.statusbar.phone.QuickSettingsContainerView
- android:id="@+id/quick_settings_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:animateLayoutChanges="true"
- android:columnCount="@integer/quick_settings_num_columns"
- />
- </com.android.systemui.statusbar.phone.QuickSettingsScrollView>
-
- <View
- android:id="@+id/handle"
- android:layout_width="match_parent"
- android:layout_height="@dimen/close_handle_height"
- android:background="@drawable/status_bar_close"
- android:visibility="invisible"
- />
-
-</com.android.systemui.statusbar.phone.SettingsPanelView >
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_search_bar.xml b/packages/SystemUI/res/layout/recents_search_bar.xml
new file mode 100644
index 0000000..915283e
--- /dev/null
+++ b/packages/SystemUI/res/layout/recents_search_bar.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/search_bg_transparent">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/recents_search_bar_label"
+ android:textColor="#99ffffff"
+ android:textSize="18sp"
+ android:textAllCaps="true" />
+</FrameLayout>
+
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 7f64032..ddc0dbf 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -22,26 +22,26 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.android.systemui.recents.views.TaskInfoView
- android:id="@+id/task_view_info_pane"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"
- android:background="#e6444444">
+ android:id="@+id/task_view_info_pane"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="invisible"
+ android:background="@color/recents_task_bar_default_background_color">
<Button
- android:id="@+id/task_view_app_info_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="20dp"
- android:layout_marginEnd="20dp"
- android:layout_gravity="top|center_horizontal"
- android:text="@string/recents_app_info_button_label" />
+ android:id="@+id/task_view_app_info_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="20dp"
+ android:layout_marginEnd="20dp"
+ android:layout_gravity="top|center_horizontal"
+ android:text="@string/recents_app_info_button_label" />
</com.android.systemui.recents.views.TaskInfoView>
<com.android.systemui.recents.views.TaskBarView
android:id="@+id/task_view_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
- android:background="#e6444444">
+ android:background="@color/recents_task_bar_default_background_color">
<ImageView
android:id="@+id/application_icon"
android:layout_width="@dimen/recents_task_view_application_icon_size"
@@ -54,8 +54,8 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|left"
android:layout_marginStart="@dimen/recents_task_view_application_icon_size"
- android:layout_marginEnd="@dimen/recents_task_view_activity_icon_size"
- android:textSize="24sp"
+ android:layout_marginEnd="8dp"
+ android:textSize="22sp"
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
android:fontFamily="sans-serif-thin"
@@ -63,13 +63,6 @@
android:maxLines="2"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
- <ImageView
- android:id="@+id/activity_icon"
- android:layout_width="@dimen/recents_task_view_activity_icon_size"
- android:layout_height="@dimen/recents_task_view_activity_icon_size"
- android:layout_gravity="center_vertical|end"
- android:padding="12dp"
- android:visibility="invisible" />
</com.android.systemui.recents.views.TaskBarView>
</com.android.systemui.recents.views.TaskView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 8a3f090..24ccb2b 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -36,14 +36,24 @@
android:layout_gravity="bottom"
/>
- <ViewStub android:id="@+id/keyguard_flip_stub"
- android:layout="@layout/status_bar_flip_button"
+ <include
+ layout="@layout/status_bar_flip_button"
+ android:id="@+id/keyguard_flipper"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="right|top"
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"
@@ -76,8 +86,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
- <ViewStub android:id="@+id/flip_settings_stub"
- android:layout="@layout/flip_settings"
+ <include
+ layout="@layout/flip_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
@@ -89,4 +99,8 @@
/>
</FrameLayout>
</LinearLayout>
+
+ <include
+ layout="@layout/keyguard_bottom_area"
+ android:visibility="gone" />
</com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 56523db..8975728 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -84,6 +84,7 @@
/>
<include layout="@layout/status_bar_flip_button"
+ android:id="@+id/header_flipper"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginStart="12dp" />
diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml
index db672ea..b7dff8c 100644
--- a/packages/SystemUI/res/layout/status_bar_flip_button.xml
+++ b/packages/SystemUI/res/layout/status_bar_flip_button.xml
@@ -16,7 +16,6 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/settings_button_holder"
android:layout_width="50dp"
android:layout_height="50dp">
<ImageView android:id="@+id/settings_button"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 2b01a06..61d43d7 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -23,6 +23,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
+ android:fitsSystemWindows="true"
android:descendantFocusability="afterDescendants">
<include layout="@layout/status_bar"
@@ -33,16 +34,11 @@
android:id="@+id/panel_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginTop="@dimen/panel_holder_padding_top"
- android:layout_marginBottom="@dimen/navigation_bar_height">
+ android:layout_marginTop="@dimen/panel_holder_padding_top">
<include layout="@layout/status_bar_expanded"
android:layout_width="@dimen/notification_panel_width"
android:layout_height="wrap_content"
android:layout_gravity="start|top" />
- <ViewStub android:id="@+id/quick_settings_stub"
- android:layout="@layout/quick_settings"
- android:layout_width="@dimen/notification_panel_width"
- android:layout_height="match_parent" />
</com.android.systemui.statusbar.phone.PanelHolder>
</com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 098ecdd..285978b 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Kleurregstellingmodus"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ONLANGS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk word\ndalk gemonitor"</string>
<string name="description_target_search" msgid="3091587249776033139">"Soek"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Gly op vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d kennisgewings versteek"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Raak om te wys"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Moenie steur nie"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d meer"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 75fbaf0..430c209 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"የቀለም እርማት ሁነታ"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"የቅርብ ጊዜዎች"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"አውታረ መረብ\nክትትል ሊደረግበት ይችላል"</string>
<string name="description_target_search" msgid="3091587249776033139">"ፍለጋ"</string>
<string name="description_direction_up" msgid="7169032478259485180">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ላይ አንሸራትት።"</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d ማሳወቂያዎች ተደብቀዋል"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ለማሳየት ነካ ያድርጉ"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ተጨማሪ"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index fd7f791..3186791 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"وضع تصحيح الألوان"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"الأخيرة"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string>
<string name="description_target_search" msgid="3091587249776033139">"بحث"</string>
<string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"تم إخفاء %d من الإشعارات"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"المس للعرض"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"الرجاء عدم الإزعاج"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d أخرى"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 426471c..b79429c 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим на коригиране на цветовете"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"СКОРОШНИ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежата може\nда се наблюдава"</string>
<string name="description_target_search" msgid="3091587249776033139">"Търсене"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Плъзнете нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d известия са скрити"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Докоснете за показване"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Още %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7365377..1841622 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correcció de color"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string>
<string name="description_target_search" msgid="3091587249776033139">"Cerca"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Fes lliscar el dit cap amunt per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notificacions ocultes"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca per mostrar-ho."</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"No molesteu"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d més"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 8455e43..1c2e122 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Režim korekce barev"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"POSLEDNÍ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Síť může být\nmonitorována"</string>
<string name="description_target_search" msgid="3091587249776033139">"Vyhledávání"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Přejeďte prstem nahoru: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"Skrytá oznámení: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Oznámení zobrazíte kliknutím"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Další: %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 56bf53b..62ab0c3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Farvekorrigeringstilstand"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"SENESTE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string>
<string name="description_target_search" msgid="3091587249776033139">"Søgning"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d underretninger er skjult"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryk for at vise"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Vil ikke forstyrres"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d mere"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 04b1767..a73e6d7 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -165,7 +165,7 @@
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Daten erneut aktivieren"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
- <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht"</string>
+ <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht..."</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Standort durch GPS festgelegt"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"Standortanfragen aktiv"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Alle Benachrichtigungen löschen"</string>
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Farbkorrekturmodus"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"Letzte"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string>
<string name="description_target_search" msgid="3091587249776033139">"Suche"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d Benachrichtigungen ausgeblendet"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Zum Ansehen tippen"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Nicht stören"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d mehr"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index b3404be..caf64f5 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Λειτουργία διόρθωσης χρώματος"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ΠΡΟΣΦΑΤΑ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string>
<string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"Έγινε απόκρυψη %d ειδοποιήσεων"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Αγγίξτε για εμφάνιση"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Μην ενοχλείτε"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ακόμη"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index ff2e525..7eff6ee 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
<string name="description_target_search" msgid="3091587249776033139">"Search"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d more"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index ff2e525..7eff6ee 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
<string name="description_target_search" msgid="3091587249776033139">"Search"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d more"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index bdd5885..d2a1125 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de corrección de color"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Es posible que la red\nesté supervisada."</string>
<string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notificaciones ocultas"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca para mostrar"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"No molestar"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d más"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c8e26d2..822db03 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de corrección de color"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string>
<string name="description_target_search" msgid="3091587249776033139">"Buscar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notificaciones ocultas"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toca para mostrar"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"No molestar"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d más"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 2a8314d..027de0c 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -205,7 +205,8 @@
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Täiustatud kontrasti režiim"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Värviparandusrežiim"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"HILJUTISED"</string>
- <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduse teave"</string>
+ <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Võrku võidakse\njälgida"</string>
<string name="description_target_search" msgid="3091587249776033139">"Otsing"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -213,6 +214,8 @@
<!-- String.format failed for translation -->
<!-- no translation found for zen_mode_notification_title:other (7388721375827338153) -->
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Puudutage kuvamiseks"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Veel %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 9461948..53353ae 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"حالت تصحیح رنگ"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"موارد اخیر"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ممکن است شبکه\nتحت نظارت باشد"</string>
<string name="description_target_search" msgid="3091587249776033139">"جستجو"</string>
<string name="description_direction_up" msgid="7169032478259485180">"لغزاندن به بالا برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d اعلان پنهان شده"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"برای نمایش لمس کنید"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d بیشتر"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index bb81ffa..dad857c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -206,6 +206,8 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Värinkorjaustila"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"VIIMEISIMMÄT"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
+ <skip />
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string>
<string name="description_target_search" msgid="3091587249776033139">"Haku"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Liu\'uta ylös ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +217,8 @@
<item quantity="other" msgid="7388721375827338153">"%d ilmoitusta piilotettu"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Näytä koskettamalla"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d muuta"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 5232d22..f0eb784 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correction des couleurs"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RÉCENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
<string name="description_target_search" msgid="3091587249776033139">"Recherche"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Faire glisser le doigt vers le haut : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notifications masquées"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Touchez pour afficher la notification"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Ne pas déranger"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d autres"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1cc8072..84dae3f 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correction des couleurs"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RÉCENTS"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informations sur l\'application"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
<string name="description_target_search" msgid="3091587249776033139">"Rechercher"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Faites glisser vers le haut pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"%d notifications masquées"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Appuyer pour afficher"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"+ %d autres"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index fd7783d..2cdff20 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"रंग सुधार मोड"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"हाल ही का"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्लिकेशन जानकारी"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string>
<string name="description_target_search" msgid="3091587249776033139">"खोजें"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्लाइड करें."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d सूचनाएं छिपी हुई हैं"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"दिखाने के लिए स्पर्श करें"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"परेशान न करें"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d और"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b7c69d5..8b69a4d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Način korekcije boje"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNO"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"Broj skrivenih obavijesti: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dodirnite za prikaz"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Još %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index f374743..e9c7c7b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Színjavítás mód"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"LEGUTÓBBIAK"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string>
<string name="description_target_search" msgid="3091587249776033139">"Keresés"</string>
<string name="description_direction_up" msgid="7169032478259485180">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa felfelé."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d értesítés elrejtve"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"A megtekintéshez érintse meg"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Ne zavarjanak"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d további"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f2bbb7c..e2d69a0 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -206,6 +206,8 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Գույների կարգավորման ռեժիմ"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ՎԵՐՋԻՆՆԵՐԸ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
+ <skip />
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string>
<string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string>
@@ -215,6 +217,8 @@
<item quantity="other" msgid="7388721375827338153">"%d ծանուցում թաքցված է"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Հպեք՝ ցուցադրելու համար"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Եվս %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index ccd6c68..c3ec03b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode koreksi warna"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"TERBARU"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string>
<string name="description_target_search" msgid="3091587249776033139">"Telusuri"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d pemberitahuan disembunyikan"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menampilkan"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Jangan ganggu"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d lainnya"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 1c0f712..60f9fc8 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modalità di correzione del colore"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"MESSAGGI RECENTI"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string>
<string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notifiche nascoste"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tocca per visualizzare"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Non disturbare"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Altre %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 67ed8c5..f9dc2e7 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"מצב תיקון צבע"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"אחרונים"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ייתכן שהרשת\nמנוטרת"</string>
<string name="description_target_search" msgid="3091587249776033139">"חיפוש"</string>
<string name="description_direction_up" msgid="7169032478259485180">"הסט למעלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d הודעות הוסתרו"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"גע כדי להציג"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"נא לא להפריע"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"עוד %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 14309ab..73fb622 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"色補正モード"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"最近"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ネットワークが監視される\n場合があります"</string>
<string name="description_target_search" msgid="3091587249776033139">"検索します"</string>
<string name="description_direction_up" msgid="7169032478259485180">"上にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"%d件の通知が非表示"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"表示するにはタップします"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"他%d件"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 904ae01..0cd7812 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -205,7 +205,8 @@
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"გაუმჯობესებული კონტრასტის რეჟიმი"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"ფერთა კორექციის რეჟიმი"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ბოლო დროის"</string>
- <!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
+ <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
<skip />
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string>
<string name="description_target_search" msgid="3091587249776033139">"ძიება"</string>
@@ -216,6 +217,8 @@
<item quantity="other" msgid="7388721375827338153">"%d შეტყობინება დამალულია"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"შეეხეთ საჩვენებლად"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d სხვა"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 5ce1be3..30eae2e 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"របៀបកែពណ៌"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ថ្មីៗ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មានកម្មវិធី"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string>
<string name="description_direction_up" msgid="7169032478259485180">"រុញឡើងលើដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"បានលាក់ការជូនដំណឹង %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ប៉ះដើម្បីបង្ហាញ"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"កុំរំខាន"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ទៀត"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 99e1ac0..e1ab831 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"색상 보정 모드"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"최근"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"네트워크가\n모니터링될 수 있음"</string>
<string name="description_target_search" msgid="3091587249776033139">"검색"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 위로 슬라이드"</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"알림 %d개 숨김"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"표시하려면 터치"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d개 더보기"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index a09a310..3ade551 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"ໂໝດການແກ້ໄຂສີ"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ບໍ່ດົນມານີ້"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ຂໍ້ມູນແອັບພລິເຄຊັນ"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string>
<string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"ເຊື່ອງ %d ການແຈ້ງເຕືອນແລ້ວ"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"ແຕະເພື່ອສະແດງ"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ເພີ່ມເຕີມ"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 6fa96aa..3dc6a7a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Spalvų taisymo režimas"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"PASTARIEJI"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string>
<string name="description_target_search" msgid="3091587249776033139">"Paieška"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"Paslėpta pranešimų: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Palieskite, kad būtų rodoma"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Netrukdyti"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Dar %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 19602a6..9405545 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Krāsu korekcijas režīms"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"JAUNĀKIE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string>
<string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d paziņojumi paslēpti"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Pieskarieties, lai rādītu"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Netraucēt"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"vēl %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 1ff647f..99ecacf 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Өнгө залруулах горим"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"СҮҮЛИЙН"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Сүлжээ хянагдаж\nбайж болзошгүй"</string>
<string name="description_target_search" msgid="3091587249776033139">"Хайх"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-г гулсуулах."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d мэдэгдлийг нуусан"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Харуулах бол хүрнэ үү"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Бүү саад бол"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"өөр %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 77c1c9d..886d644 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -205,8 +205,8 @@
<string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mod kontras dipertingkat"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mod pembetulan warna"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"TERBAHARU"</string>
- <!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
- <skip />
+ <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string>
<string name="description_target_search" msgid="3091587249776033139">"Carian"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -216,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d pemberitahuan disembunyikan"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menunjukkan"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d lagi"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index dd8c531..1892632 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus for fargekorrigering"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NYLIGE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string>
<string name="description_target_search" msgid="3091587249776033139">"Søk"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d varsler er skjult"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Trykk for å vise"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d til"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a4d8d22..bf4d765 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus voor kleurcorrectie"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string>
<string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d meldingen verborgen"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Raak aan om weer te geven"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Niet storen"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Nog %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 2a5b0f8..57605b2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Tryb korekcji kolorów"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"OSTATNIE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieć może być\nmonitorowana"</string>
<string name="description_target_search" msgid="3091587249776033139">"Szukaj"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Przesuń w górę: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"Ukryte powiadomienia: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dotknij, by zobaczyć"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Nie przeszkadzać"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d więcej"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 39cfe4d..fc71887 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Deslize para cima para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d notificações ocultas"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Não incomodar"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 6d712c3..d1ed7ac 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do aplicativo"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode estar\nsob monitoração"</string>
<string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para cima."</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"%d notificações ocultas"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Mais %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 4ab5e75..4e0f0f6 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -382,6 +382,8 @@
<skip />
<!-- no translation found for recents_app_info_button_label (2890317189376000030) -->
<skip />
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
+ <skip />
<!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
<skip />
<!-- no translation found for description_target_search (3091587249776033139) -->
@@ -394,5 +396,7 @@
<!-- no translation found for zen_mode_notification_title:other (7388721375827338153) -->
<!-- no translation found for zen_mode_notification_text (8336623711388065713) -->
<skip />
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<!-- no translation found for keyguard_more_overflow_text:other (9180696159506883684) -->
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2e8c7a6..cef305c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -206,6 +206,8 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mod de corectare a culorilor"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
+ <!-- no translation found for recents_search_bar_label (8074997400187836677) -->
+ <skip />
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
<string name="description_target_search" msgid="3091587249776033139">"Căutaţi"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +217,8 @@
<item quantity="other" msgid="7388721375827338153">"%d de notificări ascunse"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Atingeți pentru a afișa"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Încă %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 643759f..ef4b6ee 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -178,9 +178,7 @@
<string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
<string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим полета"</string>
<string name="quick_settings_battery_charging_label" msgid="490074774465309209">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
- <!-- String.format failed for translation -->
- <!-- no translation found for quick_settings_battery_charged_label (8865413079414246081) -->
- <skip />
+ <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"100%%"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth выкл."</string>
@@ -210,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Коррекция цвета"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"НЕДАВНИЕ СООБЩЕНИЯ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Действия в сети\nмогут отслеживаться"</string>
<string name="description_target_search" msgid="3091587249776033139">"Поиск"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Проведите вверх, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -219,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"Скрыто оповещений: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Нажмите, чтобы открыть"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Ещё %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 3daf9f9..11e8b26 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Režim korekcie farieb"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NEDÁVNE"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieť môže byť\nmonitorovaná"</string>
<string name="description_target_search" msgid="3091587249776033139">"Vyhľadávanie"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Prejdite prstom nahor: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"Skryté upozornenia: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Upozornenie zobrazíte dotykom"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d ďalších"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index acda247..00d0086 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Način popravljanja barv"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNI"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string>
<string name="description_target_search" msgid="3091587249776033139">"Iskanje"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Povlecite navzgor za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"Skritih je toliko obvestil: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Dotaknite se za prikaz"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Ne moti"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"še %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 4331c7f..0f8686c 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим корекције боје"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"НАЈНОВИЈЕ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
<string name="description_target_search" msgid="3091587249776033139">"Претрага"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"Сакривена обавештења: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Додирните за приказ"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Још %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index cb591c12..a0e1468 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Färgkorrigeringsläge"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"NYA"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string>
<string name="description_target_search" msgid="3091587249776033139">"Sök"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d aviseringar har dolts"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Tryck här om du vill visa aviseringar"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Stör ej"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d till"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 11e2435..2c84b19 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -204,6 +204,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Hali ya kusahihisha rangi"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"YA HIVI KARIBUNI"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string>
<string name="description_target_search" msgid="3091587249776033139">"Tafuta"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Sogeza juu kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string>
@@ -213,6 +214,8 @@
<item quantity="other" msgid="7388721375827338153">"Arifa %d zimefichwa"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Gusa ili zionekane"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d zaidi"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index c6bc44d..fe2224e 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -20,9 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
- <!-- Enable quick settings on tablets -->
- <bool name="config_hasSettingsPanel">true</bool>
-
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">3</integer>
@@ -31,7 +28,4 @@
<!-- The number of columns that the top level tiles span in the QuickSettings -->
<integer name="quick_settings_user_time_settings_tile_span">1</integer>
-
- <!-- Enable the "flip settings" panel -->
- <bool name="config_hasFlipSettingsPanel">true</bool>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index b4fafec..5b5587d 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -23,10 +23,9 @@
<dimen name="notification_panel_margin_bottom">192dp</dimen>
<dimen name="notification_panel_margin_left">16dp</dimen>
- <!-- Gravity for the notification & quick settings panels -->
- <!-- 0x31 = top|center_horizontal ; 0x800035 = end|top -->
+ <!-- Gravity for the notification panel -->
+ <!-- 0x31 = top|center_horizontal -->
<integer name="notification_panel_layout_gravity">0x31</integer>
- <integer name="settings_panel_layout_gravity">0x800035</integer>
<!-- Diameter of outer shape drawable shown in navbar search-->
<dimen name="navbar_search_outerring_diameter">430dip</dimen>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 33fded2..1ebe21c 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"โหมดการแก้ไขสี"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ล่าสุด"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"เครือข่ายอาจ\nถูกตรวจสอบ"</string>
<string name="description_target_search" msgid="3091587249776033139">"ค้นหา"</string>
<string name="description_direction_up" msgid="7169032478259485180">"เลื่อนขึ้นเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"ซ่อน %d การแจ้งเตือนแล้ว"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"แตะเพื่อแสดง"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"ห้ามรบกวน"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"อีก %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 57b882c..eb8f236 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode ng pagtatama ng kulay"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"MGA KAMAKAILAN"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Maaaring\nsinusubaybayan ang network"</string>
<string name="description_target_search" msgid="3091587249776033139">"Maghanap"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Mag-slide pataas para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"Nakatago ang %d (na) notification"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Pindutin upang ipakita"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d pa"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 43e199e..1b57a94 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Renk düzeltme modu"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"SON İLETİLER"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ağ izleniyor\nolabilir"</string>
<string name="description_target_search" msgid="3091587249776033139">"Ara"</string>
<string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için yukarı kaydırın."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d bildirim gizli"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Görüntülemek için dokunun"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d adet daha"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index cab6b65..60192d7 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим коригування кольору"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"ОСТАННІ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string>
<string name="description_target_search" msgid="3091587249776033139">"Пошук"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"Сховано сповіщень: %d"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Торкніться, щоб показати"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Не турбувати"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"Ще %d"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index bfbbf01..8770854 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Chế độ hiệu chỉnh màu sắc"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"GẦN ĐÂY"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mạng có thể\nđược giám sát"</string>
<string name="description_target_search" msgid="3091587249776033139">"Tìm kiếm"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Trượt lên để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,8 @@
<item quantity="other" msgid="7388721375827338153">"%d thông báo ẩn"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Chạm để hiển thị"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d thông báo khác"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ede3b61..89250a5 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"颜色校正模式"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"最近"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"网络可能会\n受到监控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜索"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"隐藏了%d条通知"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"触摸即可显示"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"还有%d条"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 006ce3e..6fb723e 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"色彩校準模式"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"近期"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -217,6 +218,7 @@
<item quantity="other" msgid="7388721375827338153">"已隱藏 %d 則通知"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"請勿騷擾"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"還有 %d 個"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 2a56c3f..9ceb4e9 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -208,6 +208,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"色彩校正模式"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"近期"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網路可能\n受到監控"</string>
<string name="description_target_search" msgid="3091587249776033139">"搜尋"</string>
<string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string>
@@ -217,6 +218,8 @@
<item quantity="other" msgid="7388721375827338153">"已隱藏 %d 則通知"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string>
+ <!-- no translation found for zen_mode_title (8793432092004749188) -->
+ <skip />
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"還有 %d 則"</item>
</plurals>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index a2defee..81a08d9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -206,6 +206,7 @@
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Imodi yokulungisa umbala"</string>
<string name="recents_empty_message" msgid="2269156590813544104">"OKWAKAMUVA"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
<string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string>
<string name="description_target_search" msgid="3091587249776033139">"Sesha"</string>
<string name="description_direction_up" msgid="7169032478259485180">"Shelelisela ngenhla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -215,6 +216,7 @@
<item quantity="other" msgid="7388721375827338153">"%d izaziso zifihliwe"</item>
</plurals>
<string name="zen_mode_notification_text" msgid="8336623711388065713">"Thinta ukuze ubonise"</string>
+ <string name="zen_mode_title" msgid="8793432092004749188">"Ungaphazamisi"</string>
<plurals name="keyguard_more_overflow_text">
<item quantity="other" msgid="9180696159506883684">"%d okuningi"</item>
</plurals>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 59e8360..9281265 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -49,4 +49,14 @@
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff666666</color>
+
+ <!-- The default recents task bar background color. -->
+ <color name="recents_task_bar_default_background_color">#e6444444</color>
+ <!-- The default recents task bar text color. -->
+ <color name="recents_task_bar_default_text_color">#ffffffff</color>
+ <!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
+ <color name="recents_task_bar_light_text_color">#ffffffff</color>
+ <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
+ <color name="recents_task_bar_dark_text_color">#ff222222</color>
+
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f908a1e..722ca15 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -72,7 +72,7 @@
<!-- decay duration (from size_max -> size), in ms -->
<integer name="navigation_bar_deadzone_hold">333</integer>
<integer name="navigation_bar_deadzone_decay">333</integer>
-
+
<bool name="config_dead_zone_flash">false</bool>
<!-- Min alpha % that recent items will fade to while being dismissed -->
@@ -99,11 +99,8 @@
<integer name="blinds_pop_duration_ms">10</integer>
- <!-- Disable the separate quick settings panel -->
- <bool name="config_hasSettingsPanel">true</bool>
-
- <!-- Enable the "flip settings" panel -->
- <bool name="config_hasFlipSettingsPanel">true</bool>
+ <!-- The device supports quick settings. -->
+ <bool name="config_hasQuickSettings">true</bool>
<!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
<bool name="config_show4GForLTE">true</bool>
@@ -125,6 +122,9 @@
<!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
<integer name="recents_max_task_stack_view_dim">96</integer>
+ <!-- Whether to enable KeyguardService or not -->
+ <bool name="config_enableKeyguardService">true</bool>
+
<!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
card. -->
<integer name="keyguard_max_notification_count">4</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9aacf42..0604817 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -174,18 +174,9 @@
<dimen name="notification_panel_margin_bottom">0dp</dimen>
<dimen name="notification_panel_margin_left">0dp</dimen>
- <!-- Gravity for the notification & quick settings panels -->
+ <!-- Gravity for the notification panel -->
<!-- 0x37 = fill_horizontal|top -->
<integer name="notification_panel_layout_gravity">0x37</integer>
- <integer name="settings_panel_layout_gravity">0x37</integer>
-
- <!-- Fraction of the status bar that, when dragged, will produce the quick settings panel
- instead of the notification panel. See also @dimen/settings_panel_dragzone_min.
- If zero, the settings panel will not be directly draggable from the status bar. -->
- <item type="dimen" name="settings_panel_dragzone_fraction">0%</item>
-
- <!-- Quick settings dragzone, if used, should be at least this big (may be zero). -->
- <dimen name="settings_panel_dragzone_min">100dp</dimen>
<!-- Height of the carrier/wifi name label -->
<dimen name="carrier_label_height">24dp</dimen>
@@ -245,6 +236,12 @@
<!-- The amount of space a user has to scroll to dismiss any info panes. -->
<dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
+ <!-- The height of the search bar space. -->
+ <dimen name="recents_search_bar_space_height">40dp</dimen>
+
+ <!-- The search bar edge margins. -->
+ <dimen name="recents_search_bar_space_edge_margins">12dp</dimen>
+
<!-- Used to calculate the translation animation duration, the expected amount of movement
in dps over one second of time. -->
<dimen name="recents_animation_movement_in_dps_per_second">800dp</dimen>
@@ -253,7 +250,7 @@
<dimen name="notification_stack_margin_bottom">0dp</dimen>
<!-- Space reserved for the cards behind the top card in the top stack -->
- <dimen name="top_stack_peek_amount">24dp</dimen>
+ <dimen name="top_stack_peek_amount">12dp</dimen>
<!-- Space reserved for the cards behind the top card in the bottom stack -->
<dimen name="bottom_stack_peek_amount">18dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 73e5e19..b4a13d4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -511,6 +511,8 @@
<string name="recents_empty_message">RECENTS</string>
<!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] -->
<string name="recents_app_info_button_label">Application Info</string>
+ <!-- Recents: Temporary string for the button in the recents search bar. [CHAR LIMIT=NONE] -->
+ <string name="recents_search_bar_label">search</string>
<!-- Glyph to be overlaid atop the battery when the level is extremely low. Do not translate. -->
@@ -537,8 +539,17 @@
<!-- Zen mode: Summary notification content text. [CHAR LIMIT=NONE] -->
<string name="zen_mode_notification_text">Touch to show</string>
+ <!-- Zen mode: Short title. [CHAR LIMIT=40] -->
+ <string name="zen_mode_title">Do not disturb</string>
+
<!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=12] -->
<plurals name="keyguard_more_overflow_text">
<item quantity="other">%d more</item>
</plurals>
+
+ <!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
+ <string name="notification_tap_again">Tap again to open</string>
+
+ <!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] -->
+ <string name="keyguard_unlock">Swipe up to unlock</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 1832d37..8dd3f8d 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -195,6 +195,12 @@
mGravity = Gravity.TOP;
mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
mScaleAnimation.setDuration(EXPAND_DURATION);
+ mScaleAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCallback.setUserLockedChild(mCurrView, false);
+ }
+ });
mPopLimit = mContext.getResources().getDimension(R.dimen.blinds_pop_threshold);
mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
@@ -549,8 +555,9 @@
mScaleAnimation.setFloatValues(targetHeight);
mScaleAnimation.setupStartValues();
mScaleAnimation.start();
+ } else {
+ mCallback.setUserLockedChild(mCurrView, false);
}
- mCallback.setUserLockedChild(mCurrView, false);
mExpanding = false;
mExpansionStyle = NONE;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java
index cb624ad..85befff 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUI.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java
@@ -35,6 +35,9 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
}
+ protected void onBootCompleted() {
+ }
+
@SuppressWarnings("unchecked")
public <T> T getComponent(Class<T> interfaceType) {
return (T) (mComponents != null ? mComponents.get(interfaceType) : null);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 0f55683..103991a 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -17,7 +17,12 @@
package com.android.systemui;
import android.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Configuration;
+import android.os.SystemProperties;
import android.util.Log;
import java.util.HashMap;
@@ -49,6 +54,7 @@
*/
private final SystemUI[] mServices = new SystemUI[SERVICES.length];
private boolean mServicesStarted;
+ private boolean mBootCompleted;
private final Map<Class<?>, Object> mComponents = new HashMap<Class<?>, Object>();
@Override
@@ -58,6 +64,23 @@
// application theme in the manifest does only work for activities. Keep this in sync with
// the theme set there.
setTheme(R.style.systemui_theme);
+
+ registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mBootCompleted) return;
+
+ if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
+ unregisterReceiver(this);
+ mBootCompleted = true;
+ if (mServicesStarted) {
+ final int N = mServices.length;
+ for (int i = 0; i < N; i++) {
+ mServices[i].onBootCompleted();
+ }
+ }
+ }
+ }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
}
/**
@@ -71,6 +94,17 @@
if (mServicesStarted) {
return;
}
+
+ if (!mBootCompleted) {
+ // check to see if maybe it was already completed long before we began
+ // see ActivityManagerService.finishBooting()
+ if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
+ mBootCompleted = true;
+ if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
+ }
+ }
+
+ Log.v(TAG, "Starting SystemUI services.");
final int N = SERVICES.length;
for (int i=0; i<N; i++) {
Class<?> cl = SERVICES[i];
@@ -86,6 +120,10 @@
mServices[i].mComponents = mComponents;
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
mServices[i].start();
+
+ if (mBootCompleted) {
+ mServices[i].onBootCompleted();
+ }
}
mServicesStarted = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index cbfc266..ffdb620 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -157,24 +157,6 @@
private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000;
/**
- * Allow the user to expand the status bar when the keyguard is engaged
- * (without a pattern or password).
- */
- private static final boolean ENABLE_INSECURE_STATUS_BAR_EXPAND = true;
-
- /**
- * Allow the user to expand the status bar when a SECURE keyguard is engaged
- * and {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS} is set
- * (private notifications will be masked).
- */
- private static final boolean ENABLE_SECURE_STATUS_BAR_EXPAND = true;
-
- /**
- * Default value of {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
- */
- private static final boolean ALLOW_NOTIFICATIONS_DEFAULT = false;
-
- /**
* Secure setting whether analytics are collected on the keyguard.
*/
private static final String KEYGUARD_ANALYTICS_SETTING = "keyguard_analytics";
@@ -277,11 +259,6 @@
private int mLockSoundStreamId;
/**
- * Tracks value of {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
- */
- private boolean mAllowNotificationsWhenSecure;
-
- /**
* The volume applied to the lock/unlock sounds.
*/
private float mLockSoundVolume;
@@ -895,13 +872,6 @@
return;
}
- // note whether notification access should be allowed
- mAllowNotificationsWhenSecure = ENABLE_SECURE_STATUS_BAR_EXPAND
- && 0 != Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS,
- ALLOW_NOTIFICATIONS_DEFAULT ? 1 : 0);
-
// if the keyguard is already showing, don't bother
if (mStatusBarKeyguardViewManager.isShowing()) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
@@ -1271,16 +1241,6 @@
// (like recents). Temporary enable/disable (e.g. the "back" button) are
// done in KeyguardHostView.
flags |= StatusBarManager.DISABLE_RECENT;
- if ((isSecure() && !mAllowNotificationsWhenSecure)
- || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
- // showing secure lockscreen; disable expanding.
- flags |= StatusBarManager.DISABLE_EXPAND;
- }
- if (isSecure()) {
- // showing secure lockscreen; disable ticker and switch private notifications
- // to show their public versions, if available.
- flags |= StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS;
- }
if (!isAssistantAvailable()) {
flags |= StatusBarManager.DISABLE_SEARCH;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index 10b6d49..ae18aa8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -26,6 +26,7 @@
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.DisplayMetrics;
@@ -45,10 +46,12 @@
// Which recents to use
boolean mUseAlternateRecents;
AlternateRecentsComponent mAlternateRecents;
+ boolean mBootCompleted = false;
@Override
public void start() {
- mUseAlternateRecents = SystemProperties.getBoolean("persist.recents.use_alternate", false);
+ Configuration config = mContext.getResources().getConfiguration();
+ mUseAlternateRecents = (config.smallestScreenWidthDp < 600);
if (mUseAlternateRecents) {
if (mAlternateRecents == null) {
mAlternateRecents = new AlternateRecentsComponent(mContext);
@@ -60,6 +63,11 @@
}
@Override
+ protected void onBootCompleted() {
+ mBootCompleted = true;
+ }
+
+ @Override
public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
if (mUseAlternateRecents) {
// Launch the alternate recents if required
@@ -197,13 +205,11 @@
Intent intent =
new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT);
intent.setPackage("com.android.systemui");
- mContext.sendBroadcastAsUser(intent,
- new UserHandle(UserHandle.USER_CURRENT));
+ sendBroadcastSafely(intent);
}
});
intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true);
- mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
- UserHandle.USER_CURRENT));
+ startActivitySafely(intent, opts.toBundle());
}
} catch (ActivityNotFoundException e) {
Log.e(TAG, "Failed to launch RecentAppsIntent", e);
@@ -225,7 +231,7 @@
Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
intent.setClassName("com.android.systemui",
"com.android.systemui.recent.RecentsPreloadReceiver");
- mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ sendBroadcastSafely(intent);
RecentTasksLoader.getInstance(mContext).preloadFirstTask();
}
@@ -239,7 +245,7 @@
Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
intent.setClassName("com.android.systemui",
"com.android.systemui.recent.RecentsPreloadReceiver");
- mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ sendBroadcastSafely(intent);
RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
}
@@ -252,9 +258,25 @@
} else {
Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
intent.setPackage("com.android.systemui");
- mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ sendBroadcastSafely(intent);
RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
}
}
+
+ /**
+ * Send broadcast only if BOOT_COMPLETED
+ */
+ private void sendBroadcastSafely(Intent intent) {
+ if (!mBootCompleted) return;
+ mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ }
+
+ /**
+ * Start activity only if BOOT_COMPLETED
+ */
+ private void startActivitySafely(Intent intent, Bundle opts) {
+ if (!mBootCompleted) return;
+ mContext.startActivityAsUser(intent, opts, new UserHandle(UserHandle.USER_CURRENT));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 4fb90cb..f2e322d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -44,6 +44,7 @@
import android.view.WindowManager;
import com.android.systemui.R;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -240,12 +241,10 @@
}
/** Returns whether there is are multiple recents tasks */
- boolean hasMultipleRecentsTask() {
+ boolean hasMultipleRecentsTask(List<ActivityManager.RecentTaskInfo> tasks) {
// NOTE: Currently there's no method to get the number of non-home tasks, so we have to
// compute this ourselves
SystemServicesProxy ssp = mSystemServicesProxy;
- List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(4,
- UserHandle.CURRENT.getIdentifier());
Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
while (iter.hasNext()) {
ActivityManager.RecentTaskInfo t = iter.next();
@@ -259,6 +258,17 @@
return (tasks.size() > 1);
}
+ /** Returns whether the base intent of the top task stack was launched with the flag
+ * Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. */
+ boolean isTopTaskExcludeFromRecents(List<ActivityManager.RecentTaskInfo> tasks) {
+ if (tasks.size() > 0) {
+ ActivityManager.RecentTaskInfo t = tasks.get(0);
+ Console.log(t.baseIntent.toString());
+ return (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
+ }
+ return false;
+ }
+
/** Converts from the device rotation to the degree */
float getDegreesForRotation(int value) {
switch (value) {
@@ -334,10 +344,18 @@
isTopTaskHome = ssp.isInHomeStack(topTask.id);
}
- // Otherwise, Recents is not the front-most activity and we should animate into it
- boolean hasMultipleTasks = hasMultipleRecentsTask();
+ // Otherwise, Recents is not the front-most activity and we should animate into it. If
+ // the activity at the root of the top task stack is excluded from recents, or if that
+ // task stack is in the home stack, then we just do a simple transition. Otherwise, we
+ // animate to the rects defined by the Recents service, which can differ depending on the
+ // number of items in the list.
+ List<ActivityManager.RecentTaskInfo> recentTasks =
+ ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier());
+ boolean hasMultipleTasks = hasMultipleRecentsTask(recentTasks);
+ boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks);
Rect taskRect = hasMultipleTasks ? mMultipleCountFirstTaskRect : mSingleCountFirstTaskRect;
- if (!isTopTaskHome && taskRect != null && taskRect.width() > 0 && taskRect.height() > 0) {
+ if (!isTopTaskHome && !isTaskExcludedFromRecents &&
+ (taskRect != null) && (taskRect.width() > 0) && (taskRect.height() > 0)) {
// Loading from thumbnail
Bitmap thumbnail;
Bitmap firstThumbnail = loadFirstTaskThumbnail();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 64770a4..72d9a52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -29,6 +29,7 @@
public static final boolean EnableTaskFiltering = true;
public static final boolean EnableTaskStackClipping = false;
public static final boolean EnableInfoPane = true;
+ public static final boolean EnableSearchButton = false;
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
@@ -84,6 +85,9 @@
public static final int TaskStackOverscrollRange = 150;
public static final int FilterStartDelay = 25;
+ // The amount to inverse scale the movement if we are overscrolling
+ public static final float TouchOverscrollScaleFactor = 3f;
+
// The padding will be applied to the smallest dimension, and then applied to all sides
public static final float StackPaddingPct = 0.15f;
// The overlap height relative to the task height
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 5e5b841..d54df13 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -44,6 +44,8 @@
public int taskStackMaxDim;
public int taskViewInfoPaneAnimDuration;
public int taskViewRoundedCornerRadiusPx;
+ public int searchBarSpaceHeightPx;
+ public int searchBarSpaceEdgeMarginsPx;
public boolean launchedWithThumbnailAnimation;
@@ -92,6 +94,9 @@
res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
taskViewRoundedCornerRadiusPx =
res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
+ searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
+ searchBarSpaceEdgeMarginsPx =
+ res.getDimensionPixelSize(R.dimen.recents_search_bar_space_edge_margins);
}
/** Updates the system insets */
@@ -99,6 +104,26 @@
systemInsets.set(insets);
}
+ /** Returns the search bar bounds in the specified orientation */
+ public void getSearchBarBounds(int width, int height,
+ Rect searchBarSpaceBounds, Rect searchBarBounds) {
+ // Return empty rects if search is not enabled
+ if (!Constants.DebugFlags.App.EnableSearchButton) {
+ searchBarSpaceBounds.set(0, 0, 0, 0);
+ searchBarBounds.set(0, 0, 0, 0);
+ return;
+ }
+
+ // Calculate the search bar bounds, and account for the system insets
+ int edgeMarginPx = searchBarSpaceEdgeMarginsPx;
+ int availableWidth = width - systemInsets.left - systemInsets.right;
+ searchBarSpaceBounds.set(0, 0, availableWidth, 2 * edgeMarginPx + searchBarSpaceHeightPx);
+
+ // Inset from the search bar space to get the search bar bounds
+ searchBarBounds.set(searchBarSpaceBounds);
+ searchBarBounds.inset(edgeMarginPx, edgeMarginPx);
+ }
+
/** Converts from DPs to PXs */
public int pxFromDp(float size) {
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 06ca9e2..36b761e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -66,22 +66,33 @@
Bundle replyData = new Bundle();
TaskViewTransform transform;
+ // Get the search bar bounds so that we can account for its height in the children
+ Rect searchBarSpaceBounds = new Rect();
+ Rect searchBarBounds = new Rect();
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ config.getSearchBarBounds(windowRect.width(), windowRect.height(),
+ searchBarSpaceBounds, searchBarBounds);
+
// Calculate the target task rect for when there is one task
// NOTE: Since the nav bar height is already accounted for in the windowRect, don't
// pass in a bottom inset
stack.addTask(new Task());
- tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
+ tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
+ systemInsets.bottom - searchBarSpaceBounds.height(), 0);
tsv.boundScroll();
transform = tsv.getStackTransform(0, tsv.getStackScroll());
+ transform.rect.offset(0, searchBarSpaceBounds.height());
replyData.putParcelable(AlternateRecentsComponent.KEY_SINGLE_TASK_STACK_RECT,
new Rect(transform.rect));
// Also calculate the target task rect when there are multiple tasks
stack.addTask(new Task());
- tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
+ tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top -
+ systemInsets.bottom - searchBarSpaceBounds.height(), 0);
tsv.setStackScrollRaw(Integer.MAX_VALUE);
tsv.boundScroll();
transform = tsv.getStackTransform(1, tsv.getStackScroll());
+ transform.rect.offset(0, searchBarSpaceBounds.height());
replyData.putParcelable(AlternateRecentsComponent.KEY_MULTIPLE_TASK_STACK_RECT,
new Rect(transform.rect));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index fd0f6d1..52bba4a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -413,9 +413,14 @@
for (int i = 0; i < taskCount; i++) {
ActivityManager.RecentTaskInfo t = tasks.get(i);
ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
+ if (info == null) continue;
+
String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
t.activityLabel.toString());
- Bitmap activityIcon = t.activityIcon;
+ BitmapDrawable activityIcon = null;
+ if (t.activityIcon != null) {
+ activityIcon = new BitmapDrawable(res, t.activityIcon);
+ }
boolean isForemostTask = (i == (taskCount - 1));
// Create a new task
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 7f0d9ee..33ac0a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -19,6 +19,8 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AppGlobals;
+import android.app.SearchManager;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -26,11 +28,15 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
import java.util.ArrayList;
import java.util.List;
@@ -45,6 +51,7 @@
PackageManager mPm;
IPackageManager mIpm;
UserManager mUm;
+ SearchManager mSm;
String mPackage;
Bitmap mDummyIcon;
@@ -55,6 +62,7 @@
mPm = context.getPackageManager();
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
mIpm = AppGlobals.getPackageManager();
+ mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
mPackage = context.getPackageName();
if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
@@ -199,4 +207,28 @@
}
return icon;
}
+
+
+ /**
+ * Composes an intent to launch the global search activity.
+ */
+ public Intent getGlobalSearchIntent(Rect sourceBounds) {
+ if (mSm == null) return null;
+
+ // Try and get the global search activity
+ ComponentName globalSearchActivity = mSm.getGlobalSearchActivity();
+ if (globalSearchActivity == null) return null;
+
+ // Bundle the source of the search
+ Bundle appSearchData = new Bundle();
+ appSearchData.putString("source", mPackage);
+
+ // Compose the intent and Start the search activity
+ Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(globalSearchActivity);
+ intent.putExtra(SearchManager.APP_DATA, appSearchData);
+ intent.setSourceBounds(sourceBounds);
+ return intent;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index ff062f6c..1566a49 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -18,6 +18,7 @@
import android.content.Intent;
import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -69,8 +70,8 @@
public TaskKey key;
public Drawable applicationIcon;
+ public Drawable activityIcon;
public String activityLabel;
- public Bitmap activityIcon;
public Bitmap thumbnail;
public boolean isActive;
public int userId;
@@ -82,7 +83,7 @@
}
public Task(int id, boolean isActive, Intent intent, String activityTitle,
- Bitmap activityIcon, int userId) {
+ BitmapDrawable activityIcon, int userId) {
this.key = new TaskKey(id, intent, userId);
this.activityLabel = activityTitle;
this.activityIcon = activityIcon;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index b054a22..a04cd3e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -27,8 +27,11 @@
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
+import android.view.Gravity;
+import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
+import android.widget.TextView;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
@@ -36,6 +39,7 @@
import com.android.systemui.recents.model.SpaceNode;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.R;
import java.util.ArrayList;
@@ -53,11 +57,16 @@
// The space partitioning root of this container
SpaceNode mBSP;
+ // Search bar view
+ View mSearchBar;
// Recents view callbacks
RecentsViewCallbacks mCb;
+ LayoutInflater mInflater;
+
public RecentsView(Context context) {
super(context);
+ mInflater = LayoutInflater.from(context);
setWillNotDraw(false);
}
@@ -71,12 +80,22 @@
mBSP = n;
// Create and add all the stacks for this partition of space.
+ boolean hasTasks = false;
removeAllViews();
ArrayList<TaskStack> stacks = mBSP.getStacks();
for (TaskStack stack : stacks) {
TaskStackView stackView = new TaskStackView(getContext(), stack);
stackView.setCallbacks(this);
addView(stackView);
+ hasTasks |= (stack.getTaskCount() > 0);
+ }
+
+ // Create the search bar (and hide it if we have no recent tasks)
+ if (Constants.DebugFlags.App.EnableSearchButton) {
+ createSearchBar();
+ if (!hasTasks) {
+ mSearchBar.setVisibility(View.GONE);
+ }
}
}
@@ -85,29 +104,45 @@
// Get the first stack view
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
- TaskStackView stackView = (TaskStackView) getChildAt(i);
- TaskStack stack = stackView.mStack;
- ArrayList<Task> tasks = stack.getTasks();
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView) {
+ TaskStackView stackView = (TaskStackView) child;
+ TaskStack stack = stackView.mStack;
+ ArrayList<Task> tasks = stack.getTasks();
- // Get the first task in the stack
- if (!tasks.isEmpty()) {
- Task task = tasks.get(tasks.size() - 1);
- TaskView tv = null;
+ // Get the first task in the stack
+ if (!tasks.isEmpty()) {
+ Task task = tasks.get(tasks.size() - 1);
+ TaskView tv = null;
- // Try and use the first child task view as the source of the launch animation
- if (stackView.getChildCount() > 0) {
- TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1);
- if (stv.getTask() == task) {
- tv = stv;
+ // Try and use the first child task view as the source of the launch animation
+ if (stackView.getChildCount() > 0) {
+ TaskView stv = (TaskView) stackView.getChildAt(stackView.getChildCount() - 1);
+ if (stv.getTask() == task) {
+ tv = stv;
+ }
}
+ onTaskLaunched(stackView, tv, stack, task);
+ return true;
}
- onTaskLaunched(stackView, tv, stack, task);
- return true;
}
}
return false;
}
+ /** Creates and adds the search bar */
+ void createSearchBar() {
+ // Create a temporary search bar
+ mSearchBar = mInflater.inflate(R.layout.recents_search_bar, this, false);
+ mSearchBar.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onSearchTriggered();
+ }
+ });
+ addView(mSearchBar);
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
@@ -120,16 +155,26 @@
Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
- // We measure our stack views sans the status bar. It will handle the nav bar itself.
+ // Get the search bar bounds so that we can account for its height in the children
+ Rect searchBarSpaceBounds = new Rect();
+ Rect searchBarBounds = new Rect();
RecentsConfiguration config = RecentsConfiguration.getInstance();
+ config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
+ searchBarSpaceBounds, searchBarBounds);
+ if (mSearchBar != null) {
+ mSearchBar.measure(MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), widthMode),
+ MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), heightMode));
+ }
+
+ // We measure our stack views sans the status bar. It will handle the nav bar itself.
int childWidth = width - config.systemInsets.right;
- int childHeight = height - config.systemInsets.top;
+ int childHeight = height - config.systemInsets.top - searchBarSpaceBounds.height();
// Measure each child
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() != GONE) {
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView && child.getVisibility() != GONE) {
child.measure(MeasureSpec.makeMeasureSpec(childWidth, widthMode),
MeasureSpec.makeMeasureSpec(childHeight, heightMode));
}
@@ -145,18 +190,30 @@
Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout");
- // We offset our stack views by the status bar height. It will handle the nav bar itself.
+ // Get the search bar bounds so that we can account for its height in the children
+ Rect searchBarSpaceBounds = new Rect();
+ Rect searchBarBounds = new Rect();
RecentsConfiguration config = RecentsConfiguration.getInstance();
- top += config.systemInsets.top;
+ config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
+ searchBarSpaceBounds, searchBarBounds);
+ if (mSearchBar != null) {
+ mSearchBar.layout(config.systemInsets.left + searchBarSpaceBounds.left,
+ config.systemInsets.top + searchBarSpaceBounds.top,
+ config.systemInsets.left + mSearchBar.getMeasuredWidth(),
+ config.systemInsets.top + mSearchBar.getMeasuredHeight());
+ }
+
+ // We offset our stack views by the status bar height. It will handle the nav bar itself.
+ top += config.systemInsets.top + searchBarSpaceBounds.height();
// Layout each child
// XXX: Based on the space node for that task view
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() != GONE) {
- final int width = child.getMeasuredWidth();
- final int height = child.getMeasuredHeight();
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView && child.getVisibility() != GONE) {
+ int width = child.getMeasuredWidth();
+ int height = child.getMeasuredHeight();
child.layout(left, top, left + width, top + height);
}
}
@@ -188,9 +245,12 @@
// Get the first stack view
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
- TaskStackView stackView = (TaskStackView) getChildAt(i);
- if (stackView.closeOpenInfoPanes()) {
- return true;
+ View child = getChildAt(i);
+ if (child instanceof TaskStackView) {
+ TaskStackView stackView = (TaskStackView) child;
+ if (stackView.closeOpenInfoPanes()) {
+ return true;
+ }
}
}
}
@@ -266,7 +326,6 @@
b, offsetX, offsetY);
}
-
if (task.isActive) {
// Bring an active task to the foreground
RecentsTaskLoader.getInstance().getSystemServicesProxy()
@@ -315,4 +374,24 @@
TaskStackBuilder.create(getContext())
.addNextIntentWithParentStack(intent).startActivities();
}
+
+ public void onSearchTriggered() {
+ // Get the search bar source bounds
+ Rect searchBarSpaceBounds = new Rect();
+ Rect searchBarBounds = new Rect();
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
+ config.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
+ searchBarSpaceBounds, searchBarBounds);
+
+ // Get the search intent and start it
+ Intent searchIntent = RecentsTaskLoader.getInstance().getSystemServicesProxy()
+ .getGlobalSearchIntent(searchBarBounds);
+ if (searchIntent != null) {
+ try {
+ getContext().startActivity(searchIntent);
+ } catch (ActivityNotFoundException anfe) {
+ Console.logError(getContext(), "Could not start Search activity");
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index c9a6d67..124f11e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -31,7 +31,6 @@
Task mTask;
ImageView mApplicationIcon;
- ImageView mActivityIcon;
TextView mActivityDescription;
public TaskBarView(Context context) {
@@ -54,23 +53,22 @@
protected void onFinishInflate() {
// Initialize the icon and description views
mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
- mActivityIcon = (ImageView) findViewById(R.id.activity_icon);
mActivityDescription = (TextView) findViewById(R.id.activity_description);
}
/** Binds the bar view to the task */
void rebindToTask(Task t, boolean animate) {
mTask = t;
- if (t.applicationIcon != null) {
+ // If an activity icon is defined, then we use that as the primary icon to show in the bar,
+ // otherwise, we fall back to the application icon
+ if (t.activityIcon != null) {
+ mApplicationIcon.setImageDrawable(t.activityIcon);
+ } else if (t.applicationIcon != null) {
mApplicationIcon.setImageDrawable(t.applicationIcon);
- mActivityDescription.setText(t.activityLabel);
- if (t.activityIcon != null) {
- mActivityIcon.setImageBitmap(t.activityIcon);
- mActivityIcon.setVisibility(View.VISIBLE);
- }
- if (animate) {
- // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
- }
+ }
+ mActivityDescription.setText(t.activityLabel);
+ if (animate) {
+ // XXX: Investigate how expensive it will be to create a second bitmap and crossfade
}
}
@@ -78,8 +76,6 @@
void unbindFromTask() {
mTask = null;
mApplicationIcon.setImageDrawable(null);
- mActivityIcon.setImageBitmap(null);
- mActivityIcon.setVisibility(View.INVISIBLE);
mActivityDescription.setText("");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
index 233e38c..a81d01c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -70,10 +70,8 @@
/** Updates the positions of each of the items to fit in the rect specified */
void updateContents(Rect visibleRect) {
// Offset the app info button
- LayoutParams lp = (LayoutParams) mAppInfoButton.getLayoutParams();
- lp.topMargin = visibleRect.top +
- (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2;
- requestLayout();
+ mAppInfoButton.setTranslationY(visibleRect.top +
+ (visibleRect.height() - mAppInfoButton.getMeasuredHeight()) / 2);
}
/** Sets the circular clip radius on this panel */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index ee92b16..a77e61d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -395,9 +395,12 @@
return false;
}
- /** Returns whether the current scroll is out of bounds */
+ /** Returns whether the specified scroll is out of bounds */
+ boolean isScrollOutOfBounds(int scroll) {
+ return (scroll < mMinScroll) || (scroll > mMaxScroll);
+ }
boolean isScrollOutOfBounds() {
- return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll);
+ return isScrollOutOfBounds(getStackScroll());
}
/** Updates the min and max virtual scroll bounds */
@@ -556,7 +559,14 @@
int smallestDimension = Math.min(width, height);
int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f);
- mStackRect.inset(padding, padding);
+ if (Constants.DebugFlags.App.EnableSearchButton) {
+ // Don't need to pad the top since we have some padding on the search bar already
+ mStackRect.left += padding;
+ mStackRect.right -= padding;
+ mStackRect.bottom -= padding;
+ } else {
+ mStackRect.inset(padding, padding);
+ }
mStackRectSansPeek.set(mStackRect);
mStackRectSansPeek.top += Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height();
@@ -1275,7 +1285,12 @@
}
}
if (mIsScrolling) {
- mSv.setStackScroll(mSv.getStackScroll() + deltaY);
+ int curStackScroll = mSv.getStackScroll();
+ if (mSv.isScrollOutOfBounds(curStackScroll + deltaY)) {
+ // Scale the touch if we are overscrolling
+ deltaY /= Constants.Values.TaskStackView.TouchOverscrollScaleFactor;
+ }
+ mSv.setStackScroll(curStackScroll + deltaY);
if (mSv.isScrollOutOfBounds()) {
mVelocityTracker.clear();
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
index 87ebcc1..d67e7cb 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
@@ -38,6 +38,7 @@
import android.widget.TextView;
import java.util.ArrayList;
+import java.util.List;
/**
* A quick and dirty view to show a user switcher.
@@ -118,7 +119,12 @@
public void refreshUsers() {
mUserInfo.clear();
- mUserInfo.addAll(mUserManager.getUsers(true));
+ List<UserInfo> users = mUserManager.getUsers(true);
+ for (UserInfo user : users) {
+ if (!user.isManagedProfile()) {
+ mUserInfo.add(user);
+ }
+ }
mAdapter.notifyDataSetChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2ea5add..8f3c078 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -737,8 +737,9 @@
return false;
}
- Log.v(TAG, "publicNotification: "
- + sbn.getNotification().publicVersion);
+ if (DEBUG) {
+ Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion);
+ }
Notification publicNotification = sbn.getNotification().publicVersion;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index fdf4dbf..bb481ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -54,6 +54,7 @@
private boolean mMaxHeightNeedsUpdate;
private NotificationActivator mActivator;
private LatestItemView.OnActivatedListener mOnActivatedListener;
+ private boolean mSelfInitiatedLayout;
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -162,15 +163,28 @@
}
private void updateMaxExpandHeight() {
+
+ // We don't want this method to trigger a layout of the whole view hierarchy,
+ // as the layout parameters in the end are the same which they were in the beginning.
+ // Otherwise a loop may occur if this method is called on the layout of a parent.
+ mSelfInitiatedLayout = true;
ViewGroup.LayoutParams lp = getLayoutParams();
int oldHeight = lp.height;
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
setLayoutParams(lp);
- measure(View.MeasureSpec.makeMeasureSpec(getMeasuredWidth(), View.MeasureSpec.EXACTLY),
+ measure(View.MeasureSpec.makeMeasureSpec(getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(mRowMaxHeight, View.MeasureSpec.AT_MOST));
lp.height = oldHeight;
setLayoutParams(lp);
mMaxExpandHeight = getMeasuredHeight();
+ mSelfInitiatedLayout = false;
+ }
+
+ @Override
+ public void requestLayout() {
+ if (!mSelfInitiatedLayout) {
+ super.requestLayout();
+ }
}
/**
@@ -257,4 +271,11 @@
public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
mLatestItemView.setBackgroundResourceIds(bgResId, dimmedBgResId);
}
+
+ /**
+ * @return the potential height this view could expand in addition.
+ */
+ public int getExpandPotential() {
+ return getMaximumAllowedExpandHeight() - getHeight();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
new file mode 100644
index 0000000..3cc22ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -0,0 +1,232 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.app.ActivityManagerNative;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.MediaStore;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+/**
+ * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
+ * text.
+ */
+public class KeyguardBottomAreaView extends FrameLayout {
+
+ final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
+
+ private View mCameraButton;
+ private float mCameraDragDistance;
+ private PowerManager mPowerManager;
+ private int mScaledTouchSlop;
+
+ public KeyguardBottomAreaView(Context context) {
+ super(context);
+ }
+
+ public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mCameraButton = findViewById(R.id.camera_button);
+ watchForDevicePolicyChanges();
+ watchForAccessibilityChanges();
+ updateCameraVisibility();
+ mCameraDragDistance = getResources().getDimension(R.dimen.camera_drag_distance);
+ mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ }
+
+ private void updateCameraVisibility() {
+ boolean visible = !isCameraDisabledByDpm();
+ mCameraButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+
+ private boolean isCameraDisabledByDpm() {
+ final DevicePolicyManager dpm =
+ (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ try {
+ final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
+ final boolean disabledBecauseKeyguardSecure =
+ (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
+ && KeyguardTouchDelegate.getInstance(getContext()).isSecure();
+ return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't get userId", e);
+ }
+ }
+ return false;
+ }
+
+ private void watchForDevicePolicyChanges() {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ getContext().registerReceiver(new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ updateCameraVisibility();
+ }
+ });
+ }
+ }, filter);
+ }
+
+ private void watchForAccessibilityChanges() {
+ final AccessibilityManager am =
+ (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+
+ // Set the initial state
+ enableAccessibility(am.isTouchExplorationEnabled());
+
+ // Watch for changes
+ am.addTouchExplorationStateChangeListener(
+ new AccessibilityManager.TouchExplorationStateChangeListener() {
+ @Override
+ public void onTouchExplorationStateChanged(boolean enabled) {
+ enableAccessibility(enabled);
+ }
+ });
+ }
+
+ private void enableAccessibility(boolean touchExplorationEnabled) {
+
+ // Add a touch handler or accessibility click listener for camera button.
+ if (touchExplorationEnabled) {
+ mCameraButton.setOnTouchListener(null);
+ mCameraButton.setOnClickListener(mCameraClickListener);
+ } else {
+ mCameraButton.setOnTouchListener(mCameraTouchListener);
+ mCameraButton.setOnClickListener(null);
+ }
+ }
+
+ private void launchCamera() {
+ mContext.startActivityAsUser(
+ new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE),
+ UserHandle.CURRENT);
+ }
+
+ private final OnClickListener mCameraClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ launchCamera();
+ }
+ };
+
+ private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
+ private float mStartX;
+ private boolean mTouchSlopReached;
+ private boolean mSkipCancelAnimation;
+
+ @Override
+ public boolean onTouch(final View cameraButtonView, MotionEvent event) {
+ float realX = event.getRawX();
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mStartX = realX;
+ mTouchSlopReached = false;
+ mSkipCancelAnimation = false;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (realX > mStartX) {
+ realX = mStartX;
+ }
+ if (realX < mStartX - mCameraDragDistance) {
+ cameraButtonView.setPressed(true);
+ mPowerManager.userActivity(event.getEventTime(), false);
+ } else {
+ cameraButtonView.setPressed(false);
+ }
+ if (realX < mStartX - mScaledTouchSlop) {
+ mTouchSlopReached = true;
+ }
+ cameraButtonView.setTranslationX(Math.max(realX - mStartX,
+ -mCameraDragDistance));
+ break;
+ case MotionEvent.ACTION_UP:
+ if (realX < mStartX - mCameraDragDistance) {
+ launchCamera();
+ cameraButtonView.animate().x(-cameraButtonView.getWidth())
+ .setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
+ new Runnable() {
+ @Override
+ public void run() {
+ cameraButtonView.setTranslationX(0);
+ }
+ });
+ mSkipCancelAnimation = true;
+ }
+ if (realX < mStartX - mScaledTouchSlop) {
+ mTouchSlopReached = true;
+ }
+ if (!mTouchSlopReached) {
+ mSkipCancelAnimation = true;
+ cameraButtonView.animate().translationX(-mCameraDragDistance / 2).
+ setInterpolator(new DecelerateInterpolator()).withEndAction(
+ new Runnable() {
+ @Override
+ public void run() {
+ cameraButtonView.animate().translationX(0).
+ setInterpolator(new AccelerateInterpolator());
+ }
+ });
+ }
+ case MotionEvent.ACTION_CANCEL:
+ cameraButtonView.setPressed(false);
+ if (!mSkipCancelAnimation) {
+ cameraButtonView.animate().translationX(0)
+ .setInterpolator(new AccelerateInterpolator(2f));
+ }
+ break;
+ }
+ return true;
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index f2054a2..1ffb4ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -83,7 +83,7 @@
}
public void onScreenTurnedOff() {
- if (mKeyguardView != null && mRoot.getVisibility() == View.VISIBLE) {
+ if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
mKeyguardView.onPause();
}
}
@@ -143,6 +143,10 @@
return false;
}
+ public boolean isSecure() {
+ return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
+ }
+
public boolean onMenuPressed() {
ensureView();
if (mKeyguardView.handleMenuKey()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
new file mode 100644
index 0000000..769b1b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -0,0 +1,62 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+/**
+ * A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open").
+ */
+public class KeyguardIndicationTextView extends TextView {
+
+ public KeyguardIndicationTextView(Context context) {
+ super(context);
+ }
+
+ public KeyguardIndicationTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public KeyguardIndicationTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public KeyguardIndicationTextView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ /**
+ * Changes the text with an animation and makes sure a single indication is shown long enough.
+ *
+ * @param text The text to show.
+ */
+ public void switchIndication(CharSequence text) {
+
+ // TODO: Animation, make sure that we will show one indication long enough.
+ setText(text);
+ }
+
+ /**
+ * See {@link #switchIndication}.
+ */
+ public void switchIndication(int textResId) {
+ switchIndication(getResources().getText(textResId));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index d26b32f..a0582ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -82,7 +82,6 @@
setKeyButtonViewQuiescentAlpha(mView.getMenuButton(), alpha, animate);
setKeyButtonViewQuiescentAlpha(mView.getSearchLight(), KEYGUARD_QUIESCENT_ALPHA, animate);
- setKeyButtonViewQuiescentAlpha(mView.getCameraButton(), KEYGUARD_QUIESCENT_ALPHA, animate);
applyBackButtonQuiescentAlpha(mode, animate);
@@ -98,7 +97,6 @@
public void applyBackButtonQuiescentAlpha(int mode, boolean animate) {
float backAlpha = 0;
backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getSearchLight());
- backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getCameraButton());
backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getHomeButton());
backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getRecentsButton());
backAlpha = maxVisibleQuiescentAlpha(backAlpha, mView.getMenuButton());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 7ca672d..3fae3f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -21,36 +21,24 @@
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
-import android.app.ActivityManagerNative;
import android.app.StatusBarManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -63,8 +51,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import static com.android.systemui.statusbar.phone.KeyguardTouchDelegate.OnKeyguardConnectionListener;
-
public class NavigationBarView extends LinearLayout {
final static boolean DEBUG = false;
final static String TAG = "PhoneStatusBar/NavigationBarView";
@@ -98,16 +84,9 @@
final static boolean WORKAROUND_INVALID_LAYOUT = true;
final static int MSG_CHECK_INVALID_LAYOUT = 8686;
- private final float mCameraDragDistance;
-
- // used to disable the camera icon in navbar when disabled by DPM
- private boolean mCameraDisabledByDpm;
-
// performs manual animation in sync with layout transitions
private final NavTransitionListener mTransitionListener = new NavTransitionListener();
- private final PowerManager mPowerManager;
-
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
private boolean mHomeAppearing;
@@ -157,112 +136,12 @@
private final OnClickListener mAccessibilityClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
- if (v.getId() == R.id.camera_button) {
- KeyguardTouchDelegate.getInstance(getContext()).launchCamera();
- } else if (v.getId() == R.id.search_light) {
+ if (v.getId() == R.id.search_light) {
KeyguardTouchDelegate.getInstance(getContext()).showAssistant();
}
}
};
- private final int mScaledTouchSlop;
-
- private final OnTouchListener mCameraTouchListener = new OnTouchListener() {
- private float mStartX;
- private boolean mTouchSlopReached;
- private boolean mSkipCancelAnimation;
-
- @Override
- public boolean onTouch(final View cameraButtonView, MotionEvent event) {
- float realX = event.getRawX();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- // disable search gesture while interacting with camera
- mDelegateHelper.setDisabled(true);
- mBarTransitions.setContentVisible(false);
- mStartX = realX;
- mTouchSlopReached = false;
- mSkipCancelAnimation = false;
- break;
- case MotionEvent.ACTION_MOVE:
- if (realX > mStartX) {
- realX = mStartX;
- }
- if (realX < mStartX - mCameraDragDistance) {
- ((KeyButtonView) cameraButtonView).setPressed(true);
- mPowerManager.userActivity(event.getEventTime(), false);
- } else {
- ((KeyButtonView) cameraButtonView).setPressed(false);
- }
- if (realX < mStartX - mScaledTouchSlop) {
- mTouchSlopReached = true;
- }
- cameraButtonView.setTranslationX(Math.max(realX - mStartX,
- -mCameraDragDistance));
- break;
- case MotionEvent.ACTION_UP:
- if (realX < mStartX - mCameraDragDistance) {
- mContext.startActivityAsUser(
- new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE),
- UserHandle.CURRENT);
- cameraButtonView.animate().x(-cameraButtonView.getWidth())
- .setInterpolator(new AccelerateInterpolator(2f)).withEndAction(
- new Runnable() {
- @Override
- public void run() {
- cameraButtonView.setTranslationX(0);
- }
- });
- mSkipCancelAnimation = true;
- }
- if (realX < mStartX - mScaledTouchSlop) {
- mTouchSlopReached = true;
- }
- if (!mTouchSlopReached) {
- mSkipCancelAnimation = true;
- cameraButtonView.animate().translationX(-mCameraDragDistance / 2).
- setInterpolator(new DecelerateInterpolator()).withEndAction(
- new Runnable() {
- @Override
- public void run() {
- cameraButtonView.animate().translationX(0).
- setInterpolator(new AccelerateInterpolator());
- }
- });
- }
- case MotionEvent.ACTION_CANCEL:
- ((KeyButtonView) cameraButtonView).setPressed(false);
- mDelegateHelper.setDisabled(false);
- mBarTransitions.setContentVisible(true);
- if (!mSkipCancelAnimation) {
- cameraButtonView.animate().translationX(0)
- .setInterpolator(new AccelerateInterpolator(2f));
- }
- break;
- }
- return true;
- }
- };
-
- private final OnKeyguardConnectionListener mKeyguardConnectionListener =
- new OnKeyguardConnectionListener() {
- @Override
- public void onKeyguardServiceConnected(
- KeyguardTouchDelegate keyguardTouchDelegate) {
- post(new Runnable() {
- @Override
- public void run() {
- mCameraDisabledByDpm = isCameraDisabledByDpm();
- }
- });
- }
-
- @Override
- public void onKeyguardServiceDisconnected(
- KeyguardTouchDelegate keyguardTouchDelegate) {
- }
- };
-
private class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
@@ -301,28 +180,6 @@
getIcons(res);
mBarTransitions = new NavigationBarTransitions(this);
-
- KeyguardTouchDelegate.addListener(mKeyguardConnectionListener);
- mCameraDisabledByDpm = isCameraDisabledByDpm();
- watchForDevicePolicyChanges();
- mCameraDragDistance = res.getDimension(R.dimen.camera_drag_distance);
- mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- }
-
- private void watchForDevicePolicyChanges() {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- getContext().registerReceiver(new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- post(new Runnable() {
- @Override
- public void run() {
- mCameraDisabledByDpm = isCameraDisabledByDpm();
- }
- });
- }
- }, filter);
}
public BarTransitions getBarTransitions() {
@@ -381,11 +238,6 @@
return mCurrentView.findViewById(R.id.search_light);
}
- // shown when keyguard is visible and camera is available
- public View getCameraButton() {
- return mCurrentView.findViewById(R.id.camera_button);
- }
-
private void getIcons(Resources res) {
mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land);
@@ -475,9 +327,7 @@
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
final boolean showSearch = disableHome && !disableSearch;
- final boolean showCamera = showSearch && !mCameraDisabledByDpm;
setVisibleOrGone(getSearchLight(), showSearch);
- setVisibleOrGone(getCameraButton(), showCamera);
mBarTransitions.applyBackButtonQuiescentAlpha(mBarTransitions.getMode(), true /*animate*/);
}
@@ -488,24 +338,6 @@
}
}
- private boolean isCameraDisabledByDpm() {
- final DevicePolicyManager dpm =
- (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
- if (dpm != null) {
- try {
- final int userId = ActivityManagerNative.getDefault().getCurrentUser().id;
- final int disabledFlags = dpm.getKeyguardDisabledFeatures(null, userId);
- final boolean disabledBecauseKeyguardSecure =
- (disabledFlags & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0
- && KeyguardTouchDelegate.getInstance(getContext()).isSecure();
- return dpm.getCameraDisabled(null) || disabledBecauseKeyguardSecure;
- } catch (RemoteException e) {
- Log.e(TAG, "Can't get userId", e);
- }
- }
- return false;
- }
-
public void setSlippery(boolean newSlippery) {
WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
if (lp != null) {
@@ -572,25 +404,12 @@
// Add a touch handler or accessibility click listener for camera and search buttons
// for all view orientations.
final OnClickListener onClickListener = touchEnabled ? mAccessibilityClickListener : null;
- final OnTouchListener onTouchListener = touchEnabled ? null : mCameraTouchListener;
- boolean hasCamera = false;
for (int i = 0; i < mRotatedViews.length; i++) {
- final View cameraButton = mRotatedViews[i].findViewById(R.id.camera_button);
final View searchLight = mRotatedViews[i].findViewById(R.id.search_light);
- if (cameraButton != null) {
- hasCamera = true;
- cameraButton.setOnTouchListener(onTouchListener);
- cameraButton.setOnClickListener(onClickListener);
- }
if (searchLight != null) {
searchLight.setOnClickListener(onClickListener);
}
}
- if (hasCamera) {
- // Warm up KeyguardTouchDelegate so it's ready by the time the camera button is touched.
- // This will connect to KeyguardService so that touch events are processed.
- KeyguardTouchDelegate.getInstance(getContext());
- }
}
public boolean isVertical() {
@@ -727,7 +546,6 @@
dumpButton(pw, "rcnt", getRecentsButton());
dumpButton(pw, "menu", getMenuButton());
dumpButton(pw, "srch", getSearchLight());
- dumpButton(pw, "cmra", getCameraButton());
pw.println(" }");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 45ac50b..5d75801 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -38,6 +38,7 @@
private int[] mTempChildLocation = new int[2];
private View mNotificationParent;
private boolean mTrackingSettings;
+ private float mExpandedHeight = -1;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -173,6 +174,8 @@
* @param expandedHeight the new expanded height
*/
private void updateNotificationStackHeight(float expandedHeight) {
+ if (mExpandedHeight == expandedHeight) return;
+ mExpandedHeight = expandedHeight;
mNotificationStackScroller.setIsExpanded(expandedHeight > 0.0f);
float childOffset = getRelativeTop(mNotificationStackScroller)
- mNotificationParent.getTranslationY();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 0266144c..328a1728 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -46,7 +46,6 @@
}
public static final boolean BRAKES = false;
- private boolean mRubberbandingEnabled = true;
private float mSelfExpandVelocityPx; // classic value: 2000px/s
private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
@@ -68,14 +67,12 @@
private float mExpandBrakingDistancePx = 150; // XXX Resource
private float mBrakingSpeedPx = 150; // XXX Resource
- private View mHandleView;
private float mPeekHeight;
private float mInitialOffsetOnTouch;
private float mExpandedFraction = 0;
private float mExpandedHeight = 0;
private boolean mJustPeeked;
private boolean mClosing;
- private boolean mRubberbanding;
private boolean mTracking;
private int mTrackingPointer;
private int mTouchSlop;
@@ -214,7 +211,6 @@
public void run() {
if (mTimeAnimator != null && mTimeAnimator.isStarted()) {
mTimeAnimator.end();
- mRubberbanding = false;
mClosing = false;
onExpandingFinished();
}
@@ -225,12 +221,9 @@
protected int mMaxPanelHeight = 0;
private String mViewName;
protected float mInitialTouchY;
+ protected float mInitialTouchX;
protected float mFinalTouchY;
- public void setRubberbandingEnabled(boolean enable) {
- mRubberbandingEnabled = enable;
- }
-
protected void onExpandingFinished() {
}
@@ -260,12 +253,7 @@
mTimeAnimator.start();
- mRubberbanding = mRubberbandingEnabled // is it enabled at all?
- && mExpandedHeight > getMaxPanelHeight() // are we past the end?
- && mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture?
- if (mRubberbanding) {
- mClosing = true;
- } else if (mVel == 0) {
+ if (mVel == 0) {
// if the panel is less than halfway open, close it
mClosing = (mFinalTouchY / getMaxPanelHeight()) < 0.5f;
} else {
@@ -308,10 +296,6 @@
float h = mExpandedHeight + mVel * dt;
- if (mRubberbanding && h < fh) {
- h = fh;
- }
-
if (DEBUG) logf("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");
setExpandedHeightInternal(h);
@@ -320,7 +304,7 @@
if (mVel == 0
|| (mClosing && mExpandedHeight == 0)
- || ((mRubberbanding || !mClosing) && mExpandedHeight == fh)) {
+ || (!mClosing && mExpandedHeight == fh)) {
post(mStopAnimator);
}
} else {
@@ -358,8 +342,7 @@
mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
mPeekHeight = res.getDimension(R.dimen.peek_height)
- + getPaddingBottom() // our window might have a dropshadow
- - (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow
+ + getPaddingBottom(); // our window might have a dropshadow
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
@@ -393,16 +376,14 @@
mTrackingPointer = event.getPointerId(pointerIndex);
}
final float y = event.getY(pointerIndex);
+ final float x = event.getX(pointerIndex);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mTracking = true;
- if (mHandleView != null) {
- mHandleView.setPressed(true);
- postInvalidate(); // catch the press state change
- }
mInitialTouchY = y;
+ mInitialTouchX = x;
initVelocityTracker();
trackMovement(event);
mTimeAnimator.cancel(); // end any outstanding animations
@@ -420,9 +401,11 @@
// gesture is ongoing, find a new pointer to track
final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
final float newY = event.getY(newIndex);
+ final float newX = event.getX(newIndex);
mTrackingPointer = event.getPointerId(newIndex);
mInitialOffsetOnTouch = mExpandedHeight;
mInitialTouchY = newY;
+ mInitialTouchX = newX;
}
break;
@@ -447,10 +430,6 @@
mFinalTouchY = y;
mTracking = false;
mTrackingPointer = -1;
- if (mHandleView != null) {
- mHandleView.setPressed(false);
- postInvalidate(); // catch the press state change
- }
onTrackingStopped();
trackMovement(event);
@@ -541,23 +520,17 @@
pointerIndex = 0;
mTrackingPointer = event.getPointerId(pointerIndex);
}
+ final float x = event.getX(pointerIndex);
final float y = event.getY(pointerIndex);
boolean scrolledToBottom = isScrolledToBottom();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- if (mHandleView != null) {
- mHandleView.setPressed(true);
- // catch the press state change
- postInvalidate();
- }
mInitialTouchY = y;
+ mInitialTouchX = x;
initVelocityTracker();
trackMovement(event);
mTimeAnimator.cancel(); // end any outstanding animations
- if (mExpandedHeight == 0 || y > getContentHeight()) {
- return true;
- }
break;
case MotionEvent.ACTION_POINTER_UP:
final int upPointer = event.getPointerId(event.getActionIndex());
@@ -565,8 +538,8 @@
// gesture is ongoing, find a new pointer to track
final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
mTrackingPointer = event.getPointerId(newIndex);
- final float newY = event.getY(newIndex);
- mInitialTouchY = newY;
+ mInitialTouchX = event.getX(newIndex);
+ mInitialTouchY = event.getY(newIndex);
}
break;
@@ -574,9 +547,10 @@
final float h = y - mInitialTouchY;
trackMovement(event);
if (scrolledToBottom) {
- if (h < -mTouchSlop) {
+ if (h < -mTouchSlop && h < -Math.abs(x - mInitialTouchX)) {
mInitialOffsetOnTouch = mExpandedHeight;
mInitialTouchY = y;
+ mInitialTouchX = x;
mTracking = true;
onTrackingStarted();
return true;
@@ -605,7 +579,6 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mHandleView = findViewById(R.id.handle);
loadDimens();
}
@@ -631,10 +604,6 @@
return mViewName;
}
- public View getHandle() {
- return mHandleView;
- }
-
// Rubberbands the panel to hold its contents.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@@ -648,14 +617,14 @@
if (newHeight != mMaxPanelHeight) {
mMaxPanelHeight = newHeight;
// If the user isn't actively poking us, let's rubberband to the content
- if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
+ if (!mTracking && !mTimeAnimator.isStarted()
&& mExpandedHeight > 0 && mExpandedHeight != mMaxPanelHeight
&& mMaxPanelHeight > 0) {
mExpandedHeight = mMaxPanelHeight;
}
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- getDesiredMeasureHeight(), MeasureSpec.AT_MOST);
+ getDesiredMeasureHeight(), MeasureSpec.AT_MOST);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
@@ -666,7 +635,6 @@
public void setExpandedHeight(float height) {
if (DEBUG) logf("setExpandedHeight(%.1f)", height);
- mRubberbanding = false;
if (mTimeAnimator.isStarted()) {
post(mStopAnimator);
}
@@ -686,7 +654,7 @@
float currentMaxPanelHeight = getMaxPanelHeight();
// If the user isn't actively poking us, let's update the height
- if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
+ if (!mTracking && !mTimeAnimator.isStarted()
&& mExpandedHeight > 0 && currentMaxPanelHeight != mExpandedHeight) {
setExpandedHeightInternal(currentMaxPanelHeight);
}
@@ -708,13 +676,13 @@
}
if (h < 0) h = 0;
- if (!(mRubberbandingEnabled && (mTracking || mRubberbanding)) && h > fh) h = fh;
+ if (h > fh) h = fh;
mExpandedHeight = h;
if (DEBUG) {
- logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh,
- mTracking ? "T" : "f", mRubberbanding ? "T" : "f");
+ logf("setExpansion: height=%.1f fh=%.1f tracking=%s", h, fh,
+ mTracking ? "T" : "f");
}
onHeightUpdated(mExpandedHeight);
@@ -793,7 +761,6 @@
mClosing = true;
onExpandingStarted();
// collapse() should never be a rubberband, even if an animation is already running
- mRubberbanding = false;
fling(-mSelfCollapseVelocityPx, /*always=*/ true);
}
}
@@ -817,14 +784,13 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%d closing=%s"
- + " tracking=%s rubberbanding=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s"
+ + " tracking=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s"
+ "]",
this.getClass().getSimpleName(),
getExpandedHeight(),
getMaxPanelHeight(),
mClosing?"T":"f",
mTracking?"T":"f",
- mRubberbanding?"T":"f",
mJustPeeked?"T":"f",
mPeekAnimator, ((mPeekAnimator!=null && mPeekAnimator.isStarted())?" (started)":""),
mTimeAnimator, ((mTimeAnimator!=null && mTimeAnimator.isStarted())?" (started)":"")
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 d577070..0e5e2f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -25,7 +25,6 @@
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
-import static com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -77,7 +76,7 @@
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewPropertyAnimator;
-import android.view.ViewStub;
+import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
@@ -147,6 +146,11 @@
private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10; // see NotificationManagerService
private static final int HIDE_ICONS_BELOW_SCORE = Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
+ /**
+ * Default value of {@link android.provider.Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
+ */
+ private static final boolean ALLOW_NOTIFICATIONS_DEFAULT = false;
+
private static final int STATUS_OR_NAV_TRANSIENT =
View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
private static final long AUTOHIDE_TIMEOUT_MS = 3000;
@@ -220,15 +224,18 @@
// settings
QuickSettings mQS;
- boolean mHasSettingsPanel, mHasFlipSettings;
- SettingsPanelView mSettingsPanel;
+ boolean mHasQuickSettings;
View mFlipSettingsView;
QuickSettingsContainerView mSettingsContainer;
- int mSettingsPanelGravity;
// top bar
View mNotificationPanelHeader;
View mKeyguardStatusView;
+ View mKeyguardBottomArea;
+ KeyguardIndicationTextView mKeyguardIndicationTextView;
+
+ // TODO: Fetch phrase from search/hotword provider.
+ String mKeyguardHotwordPhrase = "";
int mKeyguardMaxNotificationCount;
View mDateTimeView;
View mClearButton;
@@ -240,6 +247,7 @@
private int mCarrierLabelHeight;
private TextView mEmergencyCallLabel;
private int mNotificationHeaderHeight;
+ private View mKeyguardCarrierLabel;
private boolean mShowCarrierInPanel = false;
@@ -315,9 +323,6 @@
mHeaderFlipper.userSetup(userSetup);
mKeyguardFlipper.userSetup(userSetup);
- if (mSettingsPanel != null) {
- mSettingsPanel.setEnabled(userSetup);
- }
if (userSetup != mUserSetup) {
mUserSetup = userSetup;
if (!mUserSetup && mStatusBarView != null)
@@ -371,6 +376,7 @@
private InterceptedNotifications mIntercepted;
private VelocityTracker mSettingsTracker;
private float mSettingsDownY;
+ private boolean mSettingsStarted;
private boolean mSettingsCancelled;
private boolean mSettingsClosing;
private int mNotificationPadding;
@@ -611,13 +617,16 @@
(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;
mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
-
+ mKeyguardBottomArea = mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
+ mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
+ R.id.keyguard_indication_text);
mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
mClearButton.setOnClickListener(mClearButtonListener);
mClearButton.setAlpha(0f);
@@ -625,8 +634,7 @@
mClearButton.setEnabled(false);
mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
- mHasSettingsPanel = res.getBoolean(R.bool.config_hasSettingsPanel);
- mHasFlipSettings = res.getBoolean(R.bool.config_hasFlipSettingsPanel);
+ mHasQuickSettings = res.getBoolean(R.bool.config_hasQuickSettings);
mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
if (mDateTimeView != null) {
@@ -634,10 +642,8 @@
mDateTimeView.setEnabled(true);
}
- mHeaderFlipper = new FlipperButton(mNotificationPanelHeader
- .findViewById(R.id.settings_button_holder));
- ViewStub flipStub = (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_flip_stub);
- mKeyguardFlipper = new FlipperButton(flipStub.inflate());
+ mHeaderFlipper = new FlipperButton(mStatusBarWindow.findViewById(R.id.header_flipper));
+ mKeyguardFlipper =new FlipperButton(mStatusBarWindow.findViewById(R.id.keyguard_flipper));
if (!mNotificationPanelIsFullScreenWidth) {
mNotificationPanel.setSystemUiVisibility(
@@ -715,37 +721,11 @@
// Quick Settings (where available, some restrictions apply)
mNotificationPadding = mContext.getResources()
.getDimensionPixelSize(R.dimen.notification_side_padding);
- if (mHasSettingsPanel) {
- // first, figure out where quick settings should be inflated
- final View settings_stub;
- if (mHasFlipSettings) {
- // a version of quick settings that flips around behind the notifications
- settings_stub = mStatusBarWindow.findViewById(R.id.flip_settings_stub);
- if (settings_stub != null) {
- mFlipSettingsView = ((ViewStub)settings_stub).inflate();
- mFlipSettingsView.setVisibility(View.GONE);
- mFlipSettingsView.setVerticalScrollBarEnabled(false);
- }
- } else {
- // full quick settings panel
- settings_stub = mStatusBarWindow.findViewById(R.id.quick_settings_stub);
- if (settings_stub != null) {
- mSettingsPanel = (SettingsPanelView) ((ViewStub)settings_stub).inflate();
- } else {
- mSettingsPanel = (SettingsPanelView) mStatusBarWindow.findViewById(R.id.settings_panel);
- }
-
- if (mSettingsPanel != null) {
- if (!ActivityManager.isHighEndGfx()) {
- mSettingsPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
- R.color.notification_panel_solid_background)));
- }
- }
- }
-
- // wherever you find it, Quick Settings needs a container to survive
+ if (mHasQuickSettings) {
+ // Quick Settings needs a container to survive
mSettingsContainer = (QuickSettingsContainerView)
mStatusBarWindow.findViewById(R.id.quick_settings_container);
+ mFlipSettingsView = mSettingsContainer;
if (mSettingsContainer != null) {
mQS = new QuickSettings(mContext, mSettingsContainer);
if (!mNotificationPanelIsFullScreenWidth) {
@@ -753,9 +733,6 @@
View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
| View.STATUS_BAR_DISABLE_SYSTEM_INFO);
}
- if (mSettingsPanel != null) {
- mSettingsPanel.setQuickSettings(mQS);
- }
mQS.setService(this);
mQS.setBar(mStatusBarView);
mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
@@ -784,19 +761,24 @@
}
public boolean onSettingsEvent(MotionEvent event) {
+ userActivity();
+ if (mSettingsClosing
+ && mFlipSettingsViewAnim != null && mFlipSettingsViewAnim.isRunning()) {
+ return true;
+ }
if (mSettingsTracker != null) {
mSettingsTracker.addMovement(event);
}
-
+ final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mSettingsTracker = VelocityTracker.obtain();
mSettingsDownY = event.getY();
mSettingsCancelled = false;
+ mSettingsStarted = false;
mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE;
- mFlipSettingsView.setVisibility(View.VISIBLE);
- mStackScroller.setVisibility(View.VISIBLE);
- positionSettings(0);
- if (!mSettingsClosing) {
+ if (mSettingsClosing) {
+ mStackScroller.setVisibility(View.VISIBLE);
+ } else {
mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight());
}
dispatchSettingsEvent(event);
@@ -805,15 +787,15 @@
final float dy = event.getY() - mSettingsDownY;
final FlipperButton flipper = mOnKeyguard ? mKeyguardFlipper : mHeaderFlipper;
final boolean inButton = flipper.inHolderBounds(event);
- final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
+ final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
if (!qsTap && !inButton) {
mSettingsTracker.computeCurrentVelocity(1000);
final float vy = mSettingsTracker.getYVelocity();
+ final boolean animate = true;
if (dy <= slop || vy <= 0) {
- flipToNotifications();
+ flipToNotifications(animate);
} else {
- flipToSettings();
+ flipToSettings(animate);
}
}
mSettingsTracker.recycle();
@@ -821,10 +803,9 @@
dispatchSettingsEvent(event);
} else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) {
final float dy = event.getY() - mSettingsDownY;
- positionSettings(dy);
if (mSettingsClosing) {
- final boolean qsTap =
- Math.abs(dy) < ViewConfiguration.get(mContext).getScaledTouchSlop();
+ positionSettings(dy);
+ final boolean qsTap = Math.abs(dy) < slop;
if (!mSettingsCancelled && !qsTap) {
MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
@@ -832,6 +813,14 @@
mSettingsCancelled = true;
}
} else {
+ if (!mSettingsStarted && dy > slop) {
+ mSettingsStarted = true;
+ mFlipSettingsView.setVisibility(View.VISIBLE);
+ mStackScroller.setVisibility(View.VISIBLE);
+ }
+ if (mSettingsStarted) {
+ positionSettings(dy);
+ }
dispatchSettingsEvent(event);
}
}
@@ -851,15 +840,15 @@
}
private void positionSettings(float dy) {
- final int h = mFlipSettingsView.getMeasuredHeight();
- final int ph = mNotificationPanel.getMeasuredHeight();
if (mSettingsClosing) {
+ final int ph = mNotificationPanel.getMeasuredHeight();
dy = Math.min(Math.max(-ph, dy), 0);
mFlipSettingsView.setTranslationY(dy);
mStackScroller.setTranslationY(ph + dy);
} else {
- dy = Math.min(Math.max(0, dy), ph);
- mFlipSettingsView.setTranslationY(-h + dy - mNotificationPadding * 2);
+ final int h = mFlipSettingsView.getBottom();
+ dy = Math.min(Math.max(0, dy), h);
+ mFlipSettingsView.setTranslationY(-h + dy);
mStackScroller.setTranslationY(dy);
}
}
@@ -1357,7 +1346,8 @@
!(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
&& mStackScroller.getHeight() < (mNotificationPanel.getHeight()
- mCarrierLabelHeight - mNotificationHeaderHeight)
- && mStackScroller.getVisibility() == View.VISIBLE;
+ && mStackScroller.getVisibility() == View.VISIBLE
+ && !mOnKeyguard;
if (force || mCarrierLabelVisible != makeVisible) {
mCarrierLabelVisible = makeVisible;
@@ -1397,8 +1387,7 @@
+ " any=" + any + " clearable=" + clearable);
}
- if (mHasFlipSettings
- && mFlipSettingsView != null
+ if (mFlipSettingsView != null
&& mFlipSettingsView.getVisibility() == View.VISIBLE
&& mStackScroller.getVisibility() != View.VISIBLE) {
// the flip settings panel is unequivocally showing; we should not be shown
@@ -1482,8 +1471,6 @@
flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
flagdbg.append(((diff & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
- flagdbg.append(((state & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) ? "PRIVATE" : "private");
- flagdbg.append(((diff & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) ? "* " : " ");
flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
flagdbg.append(((diff & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
@@ -1568,15 +1555,6 @@
.setDuration(175)
.start();
}
- } else if ((diff & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) {
- if ((state & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) {
- // we are outside a secure keyguard, so we need to switch to "public" mode
- setLockscreenPublicMode(true);
- } else {
- // user has authenticated the device; full notifications may be shown
- setLockscreenPublicMode(false);
- }
- updateNotificationIcons();
}
}
@@ -1699,7 +1677,7 @@
mStatusBarWindow.cancelExpandHelper();
mStatusBarView.collapseAllPanels(true);
if (isFlippedToSettings()) {
- flipToNotifications();
+ flipToNotifications(true /*animate*/);
}
}
}
@@ -1758,39 +1736,50 @@
}
mNotificationPanel.expand();
- if (mHasFlipSettings && mStackScroller.getVisibility() != View.VISIBLE) {
- flipToNotifications();
+ if (mStackScroller.getVisibility() != View.VISIBLE) {
+ flipToNotifications(true /*animate*/);
}
if (false) postStartTracing();
}
- public void flipToNotifications() {
- if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
- if (mScrollViewAnim != null) mScrollViewAnim.cancel();
+ private static void cancelAnim(Animator anim) {
+ if (anim != null) {
+ anim.cancel();
+ }
+ }
+
+ public void flipToNotifications(boolean animate) {
+ cancelAnim(mFlipSettingsViewAnim);
+ cancelAnim(mScrollViewAnim);
+ cancelAnim(mClearButtonAnim);
mHeaderFlipper.cancel();
mKeyguardFlipper.cancel();
- if (mClearButtonAnim != null) mClearButtonAnim.cancel();
-
mStackScroller.setVisibility(View.VISIBLE);
final int h = mNotificationPanel.getMeasuredHeight();
- final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0;
- final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h;
- mScrollViewAnim = start(
- startDelay(0,
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0)
- .setDuration(FLIP_DURATION)
- )));
- mFlipSettingsViewAnim = start(
- setVisibilityWhenDone(
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h)
- )
- .setDuration(FLIP_DURATION),
- mFlipSettingsView, View.INVISIBLE));
- mHeaderFlipper.flipToNotifications();
- mKeyguardFlipper.flipToNotifications();
+ if (animate) {
+ final float settingsY =
+ mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0;
+ final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h;
+ mScrollViewAnim = start(
+ interpolator(mDecelerateInterpolator,
+ ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0)
+ .setDuration(FLIP_DURATION)
+ ));
+ mFlipSettingsViewAnim = start(
+ setVisibilityWhenDone(
+ interpolator(mDecelerateInterpolator,
+ ObjectAnimator.ofFloat(
+ mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h))
+ .setDuration(FLIP_DURATION),
+ mFlipSettingsView, View.INVISIBLE));
+ } else {
+ mStackScroller.setTranslationY(0);
+ mFlipSettingsView.setTranslationY(-h);
+ mFlipSettingsView.setVisibility(View.INVISIBLE);
+ }
+ mHeaderFlipper.flipToNotifications(animate);
+ mKeyguardFlipper.flipToNotifications(animate);
mClearButton.setVisibility(View.VISIBLE);
mClearButton.setAlpha(0f);
setAreThereNotifications(); // this will show/hide the button as necessary
@@ -1798,7 +1787,7 @@
public void run() {
updateCarrierLabelVisibility(false);
}
- }, FLIP_DURATION - 150);
+ }, animate ? FLIP_DURATION - 150 : 0);
if (mOnFlipRunnable != null) {
mOnFlipRunnable.run();
}
@@ -1814,14 +1803,10 @@
// Settings are not available in setup
if (!mUserSetup) return;
- if (mHasFlipSettings) {
- mNotificationPanel.expand();
- if (mFlipSettingsView.getVisibility() != View.VISIBLE
- || mFlipSettingsView.getTranslationY() < 0) {
- flipToSettings();
- }
- } else if (mSettingsPanel != null) {
- mSettingsPanel.expand();
+ mNotificationPanel.expand();
+ if (mFlipSettingsView.getVisibility() != View.VISIBLE
+ || mFlipSettingsView.getTranslationY() < 0) {
+ flipToSettings(true /*animate*/);
}
if (false) postStartTracing();
@@ -1834,60 +1819,63 @@
return false;
}
- public void flipToSettings() {
+ public void flipToSettings(boolean animate) {
// Settings are not available in setup
if (!mUserSetup) return;
- if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
- if (mScrollViewAnim != null) mScrollViewAnim.cancel();
+ cancelAnim(mFlipSettingsViewAnim);
+ cancelAnim(mScrollViewAnim);
mHeaderFlipper.cancel();
mKeyguardFlipper.cancel();
- if (mClearButtonAnim != null) mClearButtonAnim.cancel();
+ cancelAnim(mClearButtonAnim);
mFlipSettingsView.setVisibility(View.VISIBLE);
final int h = mNotificationPanel.getMeasuredHeight();
- final float settingsY = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h;
- final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0;
- mFlipSettingsViewAnim = start(
- startDelay(0,
+ if (animate) {
+ final float settingsY
+ = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h;
+ final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0;
+ mFlipSettingsViewAnim = start(
+ startDelay(0,
+ interpolator(mDecelerateInterpolator,
+ ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y,
+ settingsY, 0f)
+ .setDuration(FLIP_DURATION)
+ )));
+ mScrollViewAnim = start(
+ setVisibilityWhenDone(
interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y, settingsY, 0f)
- .setDuration(FLIP_DURATION)
- )));
- mScrollViewAnim = start(
- setVisibilityWhenDone(
- interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h)
- )
+ ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h)
+ )
+ .setDuration(FLIP_DURATION),
+ mStackScroller, View.INVISIBLE));
+ } else {
+ mFlipSettingsView.setTranslationY(0);
+ mStackScroller.setTranslationY(h);
+ mStackScroller.setVisibility(View.INVISIBLE);
+ }
+ mHeaderFlipper.flipToSettings(animate);
+ mKeyguardFlipper.flipToSettings(animate);
+ if (animate) {
+ mClearButtonAnim = start(
+ setVisibilityWhenDone(
+ ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
.setDuration(FLIP_DURATION),
- mStackScroller, View.INVISIBLE));
- mHeaderFlipper.flipToSettings();
- mKeyguardFlipper.flipToSettings();
- mClearButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION),
- mClearButton, View.INVISIBLE));
+ mClearButton, View.INVISIBLE));
+ } else {
+ mClearButton.setAlpha(0);
+ mClearButton.setVisibility(View.INVISIBLE);
+ }
mNotificationPanel.postDelayed(new Runnable() {
public void run() {
updateCarrierLabelVisibility(false);
}
- }, FLIP_DURATION - 150);
+ }, animate ? FLIP_DURATION - 150 : 0);
if (mOnFlipRunnable != null) {
mOnFlipRunnable.run();
}
}
- public void flipPanels() {
- if (mHasFlipSettings) {
- if (mFlipSettingsView.getVisibility() != View.VISIBLE) {
- flipToSettings();
- } else {
- flipToNotifications();
- }
- }
- }
-
public void animateCollapseQuickSettings() {
mStatusBarView.collapseAllPanels(true);
}
@@ -1907,21 +1895,19 @@
// Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
mStatusBarView.collapseAllPanels(/*animate=*/ false);
- if (mHasFlipSettings) {
- // reset things to their proper state
- if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
- if (mScrollViewAnim != null) mScrollViewAnim.cancel();
- if (mClearButtonAnim != null) mClearButtonAnim.cancel();
+ // reset things to their proper state
+ if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
+ if (mScrollViewAnim != null) mScrollViewAnim.cancel();
+ if (mClearButtonAnim != null) mClearButtonAnim.cancel();
- mStackScroller.setVisibility(View.VISIBLE);
- mNotificationPanel.setVisibility(View.GONE);
- mFlipSettingsView.setVisibility(View.GONE);
+ mStackScroller.setVisibility(View.VISIBLE);
+ mNotificationPanel.setVisibility(View.GONE);
+ mFlipSettingsView.setVisibility(View.GONE);
- setAreThereNotifications(); // show the clear button
+ setAreThereNotifications(); // show the clear button
- mHeaderFlipper.reset();
- mKeyguardFlipper.reset();
- }
+ mHeaderFlipper.reset();
+ mKeyguardFlipper.reset();
mExpandedVisible = false;
if (mNavigationBarView != null)
@@ -2111,7 +2097,8 @@
private void checkBarModes() {
if (mDemoMode) return;
int sbMode = mStatusBarMode;
- if (panelsEnabled() && (mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0) {
+ if (panelsEnabled() && (mInteractingWindows & StatusBarManager.WINDOW_STATUS_BAR) != 0
+ && !mOnKeyguard) {
// if panels are expandable, force the status bar opaque on any interaction
sbMode = MODE_OPAQUE;
}
@@ -2366,12 +2353,6 @@
pw.print (" ");
mNotificationPanel.dump(fd, pw, args);
}
- if (mSettingsPanel != null) {
- pw.println(" mSettingsPanel=" +
- mSettingsPanel + " params=" + mSettingsPanel.getLayoutParams().debug(""));
- pw.print (" ");
- mSettingsPanel.dump(fd, pw, args);
- }
if (DUMPTRUCK) {
synchronized (mNotificationData) {
@@ -2474,13 +2455,6 @@
lp.setMarginStart(mNotificationPanelMarginPx);
mNotificationPanel.setLayoutParams(lp);
- if (mSettingsPanel != null) {
- lp = (FrameLayout.LayoutParams) mSettingsPanel.getLayoutParams();
- lp.gravity = mSettingsPanelGravity;
- lp.setMarginEnd(mNotificationPanelMarginPx);
- mSettingsPanel.setLayoutParams(lp);
- }
-
if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
mStackScroller.getLocationOnScreen(mStackScrollerPosition);
@@ -2536,7 +2510,7 @@
private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
public void onClick(View v) {
- if (mHasSettingsPanel) {
+ if (mHasQuickSettings) {
animateExpandSettingsPanel();
} else {
startActivityDismissingKeyguard(
@@ -2734,11 +2708,6 @@
if (mNotificationPanelGravity <= 0) {
mNotificationPanelGravity = Gravity.START | Gravity.TOP;
}
- mSettingsPanelGravity = res.getInteger(R.integer.settings_panel_layout_gravity);
- Log.d(TAG, "mSettingsPanelGravity = " + mSettingsPanelGravity);
- if (mSettingsPanelGravity <= 0) {
- mSettingsPanelGravity = Gravity.END | Gravity.TOP;
- }
mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height);
@@ -2967,29 +2936,52 @@
public void showKeyguard() {
mOnKeyguard = true;
+ updateKeyguardState();
instantExpandNotificationsPanel();
- if (isFlippedToSettings()) {
- flipToNotifications();
- }
- mKeyguardStatusView.setVisibility(View.VISIBLE);
- mNotificationPanelHeader.setVisibility(View.GONE);
-
- mKeyguardFlipper.setVisibility(View.VISIBLE);
- mSettingsContainer.setKeyguardShowing(true);
- updateRowStates();
}
public void hideKeyguard() {
mOnKeyguard = false;
- mKeyguardStatusView.setVisibility(View.GONE);
- mNotificationPanelHeader.setVisibility(View.VISIBLE);
-
- mKeyguardFlipper.setVisibility(View.GONE);
- mSettingsContainer.setKeyguardShowing(false);
- updateRowStates();
+ updateKeyguardState();
instantCollapseNotificationPanel();
}
+ private void updatePublicMode() {
+ setLockscreenPublicMode(mOnKeyguard && mStatusBarKeyguardViewManager.isSecure());
+ }
+
+ private void updateKeyguardState() {
+ if (mOnKeyguard) {
+ if (isFlippedToSettings()) {
+ flipToNotifications(false /*animate*/);
+ }
+ mKeyguardStatusView.setVisibility(View.VISIBLE);
+ mKeyguardBottomArea.setVisibility(View.VISIBLE);
+ mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ mKeyguardCarrierLabel.setVisibility(View.VISIBLE);
+ mNotificationPanelHeader.setVisibility(View.GONE);
+
+ mKeyguardFlipper.setVisibility(View.VISIBLE);
+ mSettingsContainer.setKeyguardShowing(true);
+ } else {
+ mKeyguardStatusView.setVisibility(View.GONE);
+ mKeyguardBottomArea.setVisibility(View.GONE);
+ mKeyguardIndicationTextView.setVisibility(View.GONE);
+ mKeyguardCarrierLabel.setVisibility(View.GONE);
+ mNotificationPanelHeader.setVisibility(View.VISIBLE);
+
+ mKeyguardFlipper.setVisibility(View.GONE);
+ mSettingsContainer.setKeyguardShowing(false);
+ }
+
+ updatePublicMode();
+ updateRowStates();
+ checkBarModes();
+ updateNotificationIcons();
+ updateCarrierLabelVisibility(false);
+ }
+
public void userActivity() {
if (mOnKeyguard) {
mKeyguardViewMediatorCallback.userActivity();
@@ -3016,8 +3008,22 @@
}
private void instantExpandNotificationsPanel() {
- mExpandedVisible = true;
- mNotificationPanel.setExpandedFraction(1);
+
+ // Make our window larger.
+ mStatusBarWindowManager.setStatusBarExpanded(true);
+
+ // Wait for window manager to pickup the change, so we know the maximum height of the panel
+ // then.
+ mNotificationPanel.getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (mStatusBarWindow.getHeight() != getStatusBarHeight()) {
+ mNotificationPanel.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ mNotificationPanel.setExpandedFraction(1);
+ }
+ }
+ });
}
private void instantCollapseNotificationPanel() {
@@ -3027,24 +3033,43 @@
@Override
public void onActivated(View view) {
userActivity();
+ mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
super.onActivated(view);
}
@Override
+ public void onReset(View view) {
+ super.onReset(view);
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ }
+
+ public void onTrackingStarted() {
+ if (mOnKeyguard) {
+ mKeyguardIndicationTextView.switchIndication(R.string.keyguard_unlock);
+ }
+ }
+
+ public void onTrackingStopped() {
+ if (mOnKeyguard) {
+ mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+ }
+ }
+
+ @Override
protected int getMaxKeyguardNotifications() {
return mKeyguardMaxNotificationCount;
}
+ public NavigationBarView getNavigationBarView() {
+ return mNavigationBarView;
+ }
+
/**
* @return a ViewGroup that spans the entire panel which contains the quick settings
*/
public ViewGroup getQuickSettingsOverlayParent() {
- if (mHasSettingsPanel) {
- if (mHasFlipSettings) {
- return mNotificationPanel;
- } else {
- return mSettingsPanel;
- }
+ if (mHasQuickSettings) {
+ return mNotificationPanel;
} else {
return null;
}
@@ -3070,7 +3095,7 @@
mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button);
if (mSettingsButton != null) {
mSettingsButton.setOnClickListener(mSettingsButtonListener);
- if (mHasSettingsPanel) {
+ if (mHasQuickSettings) {
// the settings panel is hiding behind this button
mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
mSettingsButton.setVisibility(View.VISIBLE);
@@ -3080,11 +3105,9 @@
mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
}
}
- if (mHasFlipSettings) {
- mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button);
- if (mNotificationButton != null) {
- mNotificationButton.setOnClickListener(mNotificationButtonListener);
- }
+ mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button);
+ if (mNotificationButton != null) {
+ mNotificationButton.setOnClickListener(mNotificationButtonListener);
}
}
@@ -3099,7 +3122,7 @@
}
public void userSetup(boolean userSetup) {
- if (mSettingsButton != null && mHasFlipSettings) {
+ if (mSettingsButton != null) {
mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
}
}
@@ -3124,34 +3147,48 @@
}
}
- public void flipToSettings() {
- mSettingsButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION),
- mStackScroller, View.INVISIBLE));
+ public void flipToSettings(boolean animate) {
mNotificationButton.setVisibility(View.VISIBLE);
- mNotificationButtonAnim = start(
- ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
- .setDuration(FLIP_DURATION));
+ if (animate) {
+ mSettingsButtonAnim = start(
+ setVisibilityWhenDone(
+ ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
+ .setDuration(FLIP_DURATION_OUT),
+ mStackScroller, View.INVISIBLE));
+ mNotificationButtonAnim = start(
+ startDelay(FLIP_DURATION_OUT,
+ ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
+ .setDuration(FLIP_DURATION_IN)));
+ } else {
+ mSettingsButton.setAlpha(0f);
+ mSettingsButton.setVisibility(View.INVISIBLE);
+ mNotificationButton.setAlpha(1f);
+ }
}
- public void flipToNotifications() {
- mNotificationButtonAnim = start(
- setVisibilityWhenDone(
- ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
- .setDuration(FLIP_DURATION),
- mNotificationButton, View.INVISIBLE));
-
+ public void flipToNotifications(boolean animate) {
mSettingsButton.setVisibility(View.VISIBLE);
- mSettingsButtonAnim = start(
- ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
- .setDuration(FLIP_DURATION));
+ if (animate) {
+ mNotificationButtonAnim = start(
+ setVisibilityWhenDone(
+ ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
+ .setDuration(FLIP_DURATION_OUT),
+ mNotificationButton, View.INVISIBLE));
+
+ mSettingsButtonAnim = start(
+ startDelay(FLIP_DURATION_OUT,
+ ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
+ .setDuration(FLIP_DURATION_IN)));
+ } else {
+ mNotificationButton.setVisibility(View.INVISIBLE);
+ mNotificationButton.setAlpha(0f);
+ mSettingsButton.setAlpha(1f);
+ }
}
public void cancel() {
- if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
- if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
+ cancelAnim(mSettingsButtonAnim);
+ cancelAnim(mNotificationButtonAnim);
}
public void setVisibility(int vis) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 8957a77..194774d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -168,6 +168,9 @@
if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
mSimState = IccCardConstants.State.ABSENT;
}
+ else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
+ mSimState = IccCardConstants.State.CARD_IO_ERROR;
+ }
else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
mSimState = IccCardConstants.State.READY;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 583fc3e..bf7dd5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -38,13 +38,10 @@
PhoneStatusBar mBar;
int mScrimColor;
int mScrimColorKeyguard;
- float mSettingsPanelDragzoneFrac;
- float mSettingsPanelDragzoneMin;
- boolean mFullWidthNotifications;
PanelView mFadingPanel = null;
PanelView mLastFullyOpenedPanel = null;
- PanelView mNotificationPanel, mSettingsPanel;
+ PanelView mNotificationPanel;
private boolean mShouldFade;
private final PhoneStatusBarTransitions mBarTransitions;
@@ -54,13 +51,6 @@
Resources res = getContext().getResources();
mScrimColor = res.getColor(R.color.notification_panel_scrim_color);
mScrimColorKeyguard = res.getColor(R.color.notification_panel_scrim_color_keyguard);
- mSettingsPanelDragzoneMin = res.getDimension(R.dimen.settings_panel_dragzone_min);
- try {
- mSettingsPanelDragzoneFrac = res.getFraction(R.dimen.settings_panel_dragzone_fraction, 1, 1);
- } catch (NotFoundException ex) {
- mSettingsPanelDragzoneFrac = 0f;
- }
- mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f;
mBarTransitions = new PhoneStatusBarTransitions(this);
}
@@ -72,15 +62,8 @@
mBar = bar;
}
- public boolean hasFullWidthNotifications() {
- return mFullWidthNotifications;
- }
-
@Override
public void onAttachedToWindow() {
- for (PanelView pv : mPanels) {
- pv.setRubberbandingEnabled(!mFullWidthNotifications);
- }
mBarTransitions.init();
}
@@ -89,10 +72,7 @@
super.addPanel(pv);
if (pv.getId() == R.id.notification_panel) {
mNotificationPanel = pv;
- } else if (pv.getId() == R.id.settings_panel){
- mSettingsPanel = pv;
}
- pv.setRubberbandingEnabled(!mFullWidthNotifications);
}
@Override
@@ -117,34 +97,10 @@
@Override
public PanelView selectPanelForTouch(MotionEvent touch) {
- final float x = touch.getX();
- final boolean isLayoutRtl = isLayoutRtl();
-
- if (mFullWidthNotifications) {
- // No double swiping. If either panel is open, nothing else can be pulled down.
- return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight())
- + mNotificationPanel.getExpandedHeight() > 0)
- ? null
- : mNotificationPanel;
- }
-
- // We split the status bar into thirds: the left 2/3 are for notifications, and the
- // right 1/3 for quick settings. If you pull the status bar down a second time you'll
- // toggle panels no matter where you pull it down.
-
- final float w = getMeasuredWidth();
- float region = (w * mSettingsPanelDragzoneFrac);
-
- if (DEBUG) {
- Log.v(TAG, String.format(
- "w=%.1f frac=%.3f region=%.1f min=%.1f x=%.1f w-x=%.1f",
- w, mSettingsPanelDragzoneFrac, region, mSettingsPanelDragzoneMin, x, (w-x)));
- }
-
- if (region < mSettingsPanelDragzoneMin) region = mSettingsPanelDragzoneMin;
-
- final boolean showSettings = isLayoutRtl ? (x < region) : (w - region < x);
- return showSettings ? mSettingsPanel : mNotificationPanel;
+ // No double swiping. If either panel is open, nothing else can be pulled down.
+ return mNotificationPanel.getExpandedHeight() > 0
+ ? null
+ : mNotificationPanel;
}
@Override
@@ -204,6 +160,18 @@
}
@Override
+ public void onTrackingStarted(PanelView panel) {
+ super.onTrackingStarted(panel);
+ mBar.onTrackingStarted();
+ }
+
+ @Override
+ public void onTrackingStopped(PanelView panel) {
+ super.onTrackingStopped(panel);
+ mBar.onTrackingStopped();
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index b3fba76..f3ebf1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -280,6 +280,7 @@
addUserTiles(mContainerView, inflater);
addSystemTiles(mContainerView, inflater);
addTemporaryTiles(mContainerView, inflater);
+ addAccessibilityTiles(mContainerView);
queryForUserInformation();
queryForSslCaCerts();
@@ -311,6 +312,34 @@
collapsePanels();
}
+ private void addAccessibilityTiles(ViewGroup parent) {
+ if (!DEBUG_GONE_TILES && !SHOW_ACCESSIBILITY_TILES) return;
+
+ // Color inversion tile
+ final SystemSettingTile inversionTile = new SystemSettingTile(mContext);
+ inversionTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
+ SystemSettingTile.TYPE_SECURE);
+ inversionTile.setFragment("Settings$AccessibilityInversionSettingsActivity");
+ mModel.addInversionTile(inversionTile, inversionTile.getRefreshCallback());
+ parent.addView(inversionTile);
+
+ // Contrast enhancement tile
+ final SystemSettingTile contrastTile = new SystemSettingTile(mContext);
+ contrastTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED,
+ SystemSettingTile.TYPE_SECURE);
+ contrastTile.setFragment("Settings$AccessibilityContrastSettingsActivity");
+ mModel.addContrastTile(contrastTile, contrastTile.getRefreshCallback());
+ parent.addView(contrastTile);
+
+ // Color space adjustment tile
+ final SystemSettingTile colorSpaceTile = new SystemSettingTile(mContext);
+ colorSpaceTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ SystemSettingTile.TYPE_SECURE);
+ colorSpaceTile.setFragment("Settings$AccessibilityDaltonizerSettingsActivity");
+ mModel.addColorSpaceTile(colorSpaceTile, colorSpaceTile.getRefreshCallback());
+ parent.addView(colorSpaceTile);
+ }
+
private void addUserTiles(final ViewGroup parent, final LayoutInflater inflater) {
QuickSettingsTileView userTile = (QuickSettingsTileView)
inflater.inflate(R.layout.quick_settings_tile, parent, false);
@@ -384,35 +413,6 @@
new QuickSettingsModel.BasicRefreshCallback(settingsTile));
parent.addView(settingsTile);
mDynamicSpannedTiles.add(settingsTile);
-
- if (SHOW_ACCESSIBILITY_TILES) {
- // Color inversion tile
- final SystemSettingTile inversionTile = new SystemSettingTile(mContext);
- inversionTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
- SystemSettingTile.TYPE_SECURE);
- inversionTile.setFragment("Settings$AccessibilityInversionSettingsActivity");
- mModel.addInversionTile(inversionTile, inversionTile.getRefreshCallback());
- parent.addView(inversionTile);
- mDynamicSpannedTiles.add(inversionTile);
-
- // Contrast enhancement tile
- final SystemSettingTile contrastTile = new SystemSettingTile(mContext);
- contrastTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED,
- SystemSettingTile.TYPE_SECURE);
- contrastTile.setFragment("Settings$AccessibilityContrastSettingsActivity");
- mModel.addContrastTile(contrastTile, contrastTile.getRefreshCallback());
- parent.addView(contrastTile);
- mDynamicSpannedTiles.add(contrastTile);
-
- // Color space adjustment tile
- final SystemSettingTile colorSpaceTile = new SystemSettingTile(mContext);
- colorSpaceTile.setUri(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
- SystemSettingTile.TYPE_SECURE);
- colorSpaceTile.setFragment("Settings$AccessibilityDaltonizerSettingsActivity");
- mModel.addColorSpaceTile(colorSpaceTile, colorSpaceTile.getRefreshCallback());
- parent.addView(colorSpaceTile);
- mDynamicSpannedTiles.add(colorSpaceTile);
- }
}
private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
@@ -574,49 +574,6 @@
});
parent.addView(batteryTile);
- // Airplane Mode
- final QuickSettingsBasicTile airplaneTile
- = new QuickSettingsBasicTile(mContext);
- mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView unused, State state) {
- airplaneTile.setImageResource(state.iconId);
-
- String airplaneState = mContext.getString(
- (state.enabled) ? R.string.accessibility_desc_on
- : R.string.accessibility_desc_off);
- airplaneTile.setContentDescription(
- mContext.getString(R.string.accessibility_quick_settings_airplane, airplaneState));
- airplaneTile.setText(state.label);
- }
- });
- parent.addView(airplaneTile);
-
- // Zen Mode
- final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext);
- zenModeTile.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- showZenModeDialog();
- }
- });
- mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() {
- @Override
- public void refreshView(QuickSettingsTileView unused, State state) {
- zenModeTile.setImageResource(state.iconId);
- // TODO cut new assets
- zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f);
- zenModeTile.getImageView().setScaleX(1.5f);
- zenModeTile.getImageView().setScaleY(1.5f);
- // for landscape version
- zenModeTile.getTextView().setMaxLines(2);
- zenModeTile.getTextView().setEllipsize(TruncateAt.END);
- // TODO content description
- zenModeTile.setText(state.label);
- }
- });
- parent.addView(zenModeTile);
-
// Bluetooth
if (mModel.deviceSupportsBluetooth()
|| DEBUG_GONE_TILES) {
@@ -710,6 +667,50 @@
}
});
parent.addView(locationTile);
+
+ // Airplane Mode
+ final QuickSettingsBasicTile airplaneTile
+ = new QuickSettingsBasicTile(mContext);
+ mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView unused, State state) {
+ airplaneTile.setImageResource(state.iconId);
+
+ String airplaneState = mContext.getString(
+ (state.enabled) ? R.string.accessibility_desc_on
+ : R.string.accessibility_desc_off);
+ airplaneTile.setContentDescription(
+ mContext.getString(R.string.accessibility_quick_settings_airplane,
+ airplaneState));
+ airplaneTile.setText(state.label);
+ }
+ });
+ parent.addView(airplaneTile);
+
+ // Zen Mode
+ final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext);
+ zenModeTile.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ showZenModeDialog();
+ }
+ });
+ mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() {
+ @Override
+ public void refreshView(QuickSettingsTileView unused, State state) {
+ zenModeTile.setImageResource(state.iconId);
+ // TODO cut new assets
+ zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f);
+ zenModeTile.getImageView().setScaleX(1.5f);
+ zenModeTile.getImageView().setScaleY(1.5f);
+ // for landscape version
+ zenModeTile.getTextView().setMaxLines(2);
+ zenModeTile.getTextView().setEllipsize(TruncateAt.END);
+ // TODO content description
+ zenModeTile.setText(state.label);
+ }
+ });
+ parent.addView(zenModeTile);
}
private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
index 02e9c0d..c44cb0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
@@ -62,18 +62,19 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mScrim = new ScrimView(mContext);
- addView(mScrim);
- mScrim.setAlpha(sShowScrim ? 1 : 0);
+ if (sShowScrim) {
+ mScrim = new ScrimView(mContext);
+ addView(mScrim);
+ }
// TODO: Setup the layout transitions
LayoutTransition transitions = getLayoutTransition();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (mScrim.getAlpha() == 1) {
- mScrim.animate().alpha(0).setDuration(1000).start();
+ if (mScrim != null) {
sShowScrim = false;
+ removeView(mScrim);
}
return super.onTouchEvent(event);
}
@@ -144,7 +145,9 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- mScrim.bringToFront();
+ if (mScrim != null) {
+ mScrim.bringToFront();
+ }
final int N = getChildCount();
final boolean isLayoutRtl = isLayoutRtl();
final int width = getWidth();
@@ -206,6 +209,7 @@
}
private static final class ScrimView extends View {
+ private static final int SCRIM = 0x4f000000;
private static final int COLOR = 0xaf4285f4;
private final Paint mLinePaint;
@@ -240,6 +244,7 @@
final int h = getMeasuredHeight();
final int f = mStrokeWidth * 3 / 4;
+ canvas.drawColor(SCRIM);
canvas.drawPath(line(f, h / 2, w - f, h / 2), mLinePaint);
canvas.drawPath(line(w / 2, f, w / 2, h - f), mLinePaint);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 9b25046..e1ef83a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -608,7 +608,7 @@
Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
mZenModeState.enabled = mode != Settings.Global.ZEN_MODE_OFF;
mZenModeState.zenMode = mode;
- mZenModeState.label = ZenModeView.MODE_LABEL;
+ mZenModeState.label = mContext.getString(R.string.zen_mode_title);
mZenModeState.iconId = R.drawable.stat_sys_zen_limited;
mZenModeCallback.refreshView(mZenModeTile, mZenModeState);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
deleted file mode 100644
index c10a0d4..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2012 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.systemui.statusbar.phone;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.EventLog;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-
-import com.android.systemui.EventLogTags;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.GestureRecorder;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-
-public class SettingsPanelView extends PanelView {
- public static final boolean DEBUG_GESTURES = true;
-
- private QuickSettings mQS;
- private QuickSettingsContainerView mQSContainer;
-
- Drawable mHandleBar;
- int mHandleBarHeight;
- View mHandleView;
-
- public SettingsPanelView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mQSContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
-
- Resources resources = getContext().getResources();
- mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
- mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height);
- mHandleView = findViewById(R.id.handle);
- }
-
- public void setQuickSettings(QuickSettings qs) {
- mQS = qs;
- }
-
- @Override
- public void setBar(PanelBar panelBar) {
- super.setBar(panelBar);
-
- if (mQS != null) {
- mQS.setBar(panelBar);
- }
- }
-
- public void setImeWindowStatus(boolean visible) {
- if (mQS != null) {
- mQS.setImeWindowStatus(visible);
- }
- }
-
- public void setup(NetworkController networkController, BluetoothController bluetoothController,
- BatteryController batteryController, LocationController locationController,
- RotationLockController rotationLockController) {
- if (mQS != null) {
- mQS.setup(networkController, bluetoothController, batteryController,
- locationController, rotationLockController);
- }
- }
-
- void updateResources() {
- if (mQS != null) {
- mQS.updateResources();
- }
- if (mQSContainer != null) {
- mQSContainer.updateResources();
- }
- requestLayout();
- }
-
- @Override
- public void fling(float vel, boolean always) {
- GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
- if (gr != null) {
- gr.tag(
- "fling " + ((vel > 0) ? "open" : "closed"),
- "settings,v=" + vel);
- }
- super.fling(vel, always);
- }
-
- public void setService(PhoneStatusBar phoneStatusBar) {
- if (mQS != null) {
- mQS.setService(phoneStatusBar);
- }
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- event.getText()
- .add(getContext().getString(R.string.accessibility_desc_quick_settings));
- return true;
- }
-
- return super.dispatchPopulateAccessibilityEvent(event);
- }
-
- // We draw the handle ourselves so that it's always glued to the bottom of the window.
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (changed) {
- final int pl = getPaddingLeft();
- final int pr = getPaddingRight();
- mHandleBar.setBounds(pl, 0, getWidth() - pr, (int) mHandleBarHeight);
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- final int off = (int) (getHeight() - mHandleBarHeight - getPaddingBottom());
- canvas.translate(0, off);
- mHandleBar.setState(mHandleView.getDrawableState());
- mHandleBar.draw(canvas);
- canvas.translate(0, -off);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (DEBUG_GESTURES) {
- if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
- EventLog.writeEvent(EventLogTags.SYSUI_QUICKPANEL_TOUCH,
- event.getActionMasked(), (int) event.getX(), (int) event.getY());
- }
- }
- return super.onTouchEvent(event);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 460f122..c2595cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -56,7 +56,7 @@
private boolean mScreenOn = false;
private KeyguardBouncer mBouncer;
private boolean mShowing;
- private boolean mOccluded = false;
+ private boolean mOccluded;
public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils) {
@@ -103,10 +103,8 @@
}
public void showBouncer() {
- if (!mOccluded) {
- mBouncer.show();
- updateBackButtonState();
- }
+ mBouncer.show();
+ updateBackButtonState();
}
/**
@@ -156,13 +154,8 @@
public void setOccluded(boolean occluded) {
mOccluded = occluded;
- if (occluded) {
- mPhoneStatusBar.hideKeyguard();
- mBouncer.hide();
- } else {
- showBouncerOrKeyguard();
- }
mStatusBarWindowManager.setKeyguardOccluded(occluded);
+ updateBackButtonState();
}
/**
@@ -174,6 +167,7 @@
mStatusBarWindowManager.setKeyguardShowing(false);
mBouncer.hide();
mViewMediatorCallback.keyguardGone();
+ updateBackButtonState();
}
/**
@@ -185,6 +179,10 @@
}
}
+ public boolean isSecure() {
+ return mBouncer.isSecure();
+ }
+
/**
* @return Whether the keyguard is showing
*/
@@ -215,6 +213,11 @@
} else {
mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
}
+ if (!(mShowing && !mOccluded) || mBouncer.isShowing()) {
+ mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
+ } else {
+ mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+ }
}
public boolean onMenuPressed() {
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 1d675bd..c5dae85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -52,6 +53,16 @@
}
@Override
+ protected boolean fitSystemWindows(Rect insets) {
+ if (getFitsSystemWindows()) {
+ setPadding(insets.left, insets.top, insets.right, insets.bottom);
+ } else {
+ setPadding(0, 0, 0, 0);
+ }
+ return true;
+ }
+
+ @Override
protected void onAttachedToWindow () {
super.onAttachedToWindow();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
index 49cf78b..20011ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -42,13 +42,13 @@
import android.widget.TextView;
import android.widget.Toast;
+import com.android.systemui.R;
import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition;
public class ZenModeView extends RelativeLayout {
private static final String TAG = ZenModeView.class.getSimpleName();
private static final boolean DEBUG = false;
- public static final String MODE_LABEL = "Limited interruptions";
public static final int BACKGROUND = 0xff282828;
private static final Typeface CONDENSED =
@@ -91,7 +91,7 @@
LayoutParams lp = null;
mModeText = new TextView(mContext);
- mModeText.setText(MODE_LABEL);
+ mModeText.setText(R.string.zen_mode_title);
mModeText.setId(android.R.id.title);
mModeText.setTextColor(GRAY);
mModeText.setTypeface(CONDENSED);
@@ -212,6 +212,13 @@
}
}
+ @Override
+ protected void onDetachedFromWindow() {
+ if (mAdapter != null) {
+ mAdapter.dispose();
+ }
+ }
+
public void setAutoActivate(boolean value) {
mAutoActivate = value;
}
@@ -396,6 +403,7 @@
void setMode(boolean mode);
void select(ExitCondition ec);
void init();
+ void dispose();
void setCallbacks(Callbacks callbacks);
ExitCondition getExitCondition(int d);
int getExitConditionCount();
@@ -406,6 +414,7 @@
public String line1;
public String line2;
public String action;
+ public Object tag;
}
public interface Callbacks {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
index c97ba8d..a5e016a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
@@ -16,14 +16,22 @@
package com.android.systemui.statusbar.phone;
+import android.app.INotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.provider.Settings;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.util.ArrayMap;
import android.util.Log;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -34,8 +42,10 @@
private final ContentResolver mResolver;
private final Handler mHandler = new Handler();
private final SettingsObserver mObserver;
- private final List<ExitCondition> mExits = Arrays.asList(
- newExit("Until you turn this off", "Until", "You turn this off"));
+ private final List<ExitCondition> mExits = new ArrayList<ExitCondition>(Arrays.asList(
+ newExit("Until you turn this off", "Until", "You turn this off", null)));
+ private final INotificationManager mNoMan;
+ private final ArrayMap<Uri, Condition> mConditions = new ArrayMap<Uri, Condition>();
private Callbacks mCallbacks;
private int mExitIndex;
@@ -45,6 +55,13 @@
mContext = context;
mResolver = mContext.getContentResolver();
mObserver = new SettingsObserver(mHandler);
+ mNoMan = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ try {
+ mNoMan.requestZenModeConditions(mListener, true /*requested*/);
+ } catch (RemoteException e) {
+ // noop
+ }
mObserver.init();
init();
}
@@ -77,6 +94,15 @@
}
}
+ @Override
+ public void dispose() {
+ try {
+ mNoMan.requestZenModeConditions(mListener, false /*requested*/);
+ } catch (RemoteException e) {
+ // noop
+ }
+ }
+
private void dispatchChanged() {
mHandler.removeCallbacks(mChanged);
mHandler.post(mChanged);
@@ -117,13 +143,20 @@
}
mExitIndex = i;
dispatchChanged();
+ final Uri conditionUri = (Uri) ec.tag;
+ try {
+ mNoMan.setZenModeCondition(conditionUri);
+ } catch (RemoteException e) {
+ // noop
+ }
}
- private static ExitCondition newExit(String summary, String line1, String line2) {
+ private static ExitCondition newExit(String summary, String line1, String line2, Object tag) {
final ExitCondition rt = new ExitCondition();
rt.summary = summary;
rt.line1 = line1;
rt.line2 = line2;
+ rt.tag = tag;
return rt;
}
@@ -168,4 +201,21 @@
return v != Settings.Global.ZEN_MODE_OFF;
}
}
+
+ private final IConditionListener mListener = new IConditionListener.Stub() {
+ @Override
+ public void onConditionsReceived(Condition[] conditions) {
+ if (conditions == null || conditions.length == 0) return;
+ for (Condition c : conditions) {
+ mConditions.put(c.id, c);
+ }
+ for (int i = mExits.size() - 1; i > 0; i--) {
+ mExits.remove(i);
+ }
+ for (Condition c : mConditions.values()) {
+ mExits.add(newExit(c.caption, "", "", c.id));
+ }
+ dispatchChanged();
+ }
+ };
}
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 9800bc9..36d94a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -20,7 +20,6 @@
import android.content.res.Configuration;
import android.graphics.Canvas;
-import android.graphics.Outline;
import android.graphics.Paint;
import android.util.AttributeSet;
@@ -31,6 +30,7 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.widget.OverScroller;
import com.android.systemui.ExpandHelper;
@@ -55,7 +55,7 @@
private static final int INVALID_POINTER = -1;
private SwipeHelper mSwipeHelper;
- private boolean mSwipingInProgress = true;
+ private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private int mOwnScrollY;
private int mMaxLayoutHeight;
@@ -73,7 +73,6 @@
private int mSidePaddings;
private Paint mDebugPaint;
- private int mBackgroundRoundedRectCornerRadius;
private int mContentHeight;
private int mCollapsedSize;
private int mBottomStackPeekSize;
@@ -145,9 +144,6 @@
mSidePaddings = context.getResources()
.getDimensionPixelSize(R.dimen.notification_side_padding);
- mBackgroundRoundedRectCornerRadius = context.getResources()
- .getDimensionPixelSize(
- com.android.internal.R.dimen.notification_quantum_rounded_rect_radius);
mCollapsedSize = context.getResources()
.getDimensionPixelSize(R.dimen.notification_row_min_height);
mBottomStackPeekSize = context.getResources()
@@ -177,18 +173,23 @@
View child = getChildAt(i);
float width = child.getMeasuredWidth();
float height = child.getMeasuredHeight();
- int oldWidth = child.getWidth();
- int oldHeight = child.getHeight();
child.layout((int) (centerX - width / 2.0f),
0,
(int) (centerX + width / 2.0f),
(int) height);
- updateChildOutline(child, width, height, oldWidth, oldHeight);
}
setMaxLayoutHeight(getHeight() - mEmptyMarginBottom);
- updateScrollPositionIfNecessary();
- updateChildren();
updateContentHeight();
+ getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ updateScrollPositionIfNecessary();
+ updateChildren();
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
+ });
+
}
public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
@@ -227,7 +228,6 @@
mCurrentStackScrollState.setScrollY(mOwnScrollY);
mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
mCurrentStackScrollState.apply();
- mOwnScrollY = mCurrentStackScrollState.getScrollY();
if (mListener != null) {
mListener.onChildLocationsChanged(this);
}
@@ -240,31 +240,6 @@
return false;
}
- private void updateChildOutline(View child,
- float width,
- float height,
- int oldWidth,
- int oldHeight) {
- // 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.
- View container = child.findViewById(R.id.container);
- if (container != null && (oldWidth != width || oldHeight != height)) {
- Outline outline = getOutlineForSize(container.getLeft(),
- container.getTop(),
- container.getWidth(),
- container.getHeight());
- child.setOutline(outline);
- }
- }
-
- private Outline getOutlineForSize(int leftInset, int topInset, int width, int height) {
- Outline result = new Outline();
- result.setRoundRect(leftInset, topInset, leftInset + width, topInset + height,
- mBackgroundRoundedRectCornerRadius);
- return result;
- }
-
private void updateScrollPositionIfNecessary() {
int scrollRange = getScrollRange();
if (scrollRange < mOwnScrollY) {
@@ -284,7 +259,7 @@
*
* @return either the layout height or the externally defined height, whichever is smaller
*/
- private float getLayoutHeight() {
+ private int getLayoutHeight() {
return Math.min(mMaxLayoutHeight, mCurrentStackHeight);
}
@@ -640,14 +615,48 @@
private int getScrollRange() {
int scrollRange = 0;
- if (getChildCount() > 0) {
+ View firstChild = getFirstChildNotGone();
+ if (firstChild != null) {
int contentHeight = getContentHeight();
- scrollRange = Math.max(0,
- contentHeight - mMaxLayoutHeight + mBottomStackPeekSize);
+ int firstChildMaxExpandHeight = getMaxExpandHeight(firstChild);
+ int firstChildExpandPotential = firstChildMaxExpandHeight - firstChild.getHeight();
+
+ // If we already scrolled in, the first child is layouted smaller than it actually
+ // could be when expanded. We have to compensate for this loss of the contentHeight
+ // by adding the expand potential again.
+ contentHeight += firstChildExpandPotential;
+ scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize);
+ if (scrollRange > 0 && getChildCount() > 0) {
+ // We want to at least be able collapse the first item and not ending in a weird
+ // end state.
+ scrollRange = Math.max(scrollRange, firstChildMaxExpandHeight - mCollapsedSize);
+ }
}
return scrollRange;
}
+ /**
+ * @return the first child which has visibility unequal to GONE
+ */
+ private View getFirstChildNotGone() {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ private int getMaxExpandHeight(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ return row.getMaximumAllowedExpandHeight();
+ }
+ return view.getHeight();
+ }
+
private int getContentHeight() {
return mContentHeight;
}
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 431f6fe..d9e7f66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -20,6 +20,7 @@
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -47,13 +48,14 @@
private StackIndentationFunctor mTopStackIndentationFunctor;
private StackIndentationFunctor mBottomStackIndentationFunctor;
- private float mLayoutHeight;
+ private int mLayoutHeight;
private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
private boolean mIsExpansionChanging;
private int mFirstChildMaxHeight;
private boolean mIsExpanded;
private View mFirstChildWhileExpanding;
private boolean mExpandedOnStart;
+ private int mTopStackTotalSize;
public StackScrollAlgorithm(Context context) {
initConstants(context);
@@ -72,16 +74,16 @@
mZDistanceBetweenElements = context.getResources()
.getDimensionPixelSize(R.dimen.z_distance_between_notifications);
mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
-
+ mTopStackTotalSize = mCollapsedSize + mPaddingBetweenElements;
mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
MAX_ITEMS_IN_TOP_STACK,
mTopStackPeekSize,
- mCollapsedSize + mPaddingBetweenElements,
+ mTopStackTotalSize,
0.5f);
mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
MAX_ITEMS_IN_BOTTOM_STACK,
mBottomStackPeekSize,
- mBottomStackPeekSize,
+ mCollapsedSize + mPaddingBetweenElements + mBottomStackPeekSize,
0.5f);
}
@@ -94,14 +96,17 @@
// First we reset the view states to their default values.
resultState.resetViewStates();
- // The first element is always in there so it's initialized with 1.0f;
- algorithmState.itemsInTopStack = 1.0f;
+ algorithmState.itemsInTopStack = 0.0f;
algorithmState.partialInTop = 0.0f;
algorithmState.lastTopStackIndex = 0;
- algorithmState.scrollY = resultState.getScrollY();
+ algorithmState.scrolledPixelsTop = 0;
algorithmState.itemsInBottomStack = 0.0f;
+ algorithmState.partialInBottom = 0.0f;
+
updateVisibleChildren(resultState, algorithmState);
+ algorithmState.scrollY = getAlgorithmScrollPosition(resultState, algorithmState);
+
// Phase 1:
findNumberOfItemsInTopStackAndUpdateState(resultState, algorithmState);
@@ -110,9 +115,42 @@
// Phase 3:
updateZValuesForState(resultState, algorithmState);
+ }
- // write the algorithm state to the result
- resultState.setScrollY(algorithmState.scrollY);
+ /**
+ * Calculates the scroll offset of the algorithm, based on the resultState.
+ *
+ * @param resultState the state to base the calculation on
+ * @param algorithmState The state in which the current pass of the algorithm is currently in
+ * @return the scroll offset used for the algorithm
+ */
+ private int getAlgorithmScrollPosition(StackScrollState resultState,
+ StackScrollAlgorithmState algorithmState) {
+
+ int resultScroll = resultState.getScrollY() + mCollapsedSize;
+
+ // If the first child was collapsed in an earlier pass, we have to decrease the scroll
+ // position to get into the same state again.
+ if (algorithmState.visibleChildren.size() > 0) {
+ View firstView = algorithmState.visibleChildren.get(0);
+ if (firstView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow firstRow = (ExpandableNotificationRow) firstView;
+ if (firstRow.isUserLocked()) {
+ // User is currently modifying this height.
+ return resultScroll;
+ }
+ int scrolledInAmount = 0;
+ // If the child size was not decreased due to scrolling, we don't substract it,
+ if (!mIsExpansionChanging) {
+ scrolledInAmount = firstRow.getExpandPotential();
+ } else if (mExpandedOnStart && mFirstChildWhileExpanding == firstView) {
+ scrolledInAmount = firstRow.getMaximumAllowedExpandHeight() -
+ mFirstChildMaxHeight;
+ }
+ resultScroll -= scrolledInAmount;
+ }
+ }
+ return resultScroll;
}
/**
@@ -141,13 +179,12 @@
*/
private void updatePositionsForState(StackScrollState resultState,
StackScrollAlgorithmState algorithmState) {
- float stackHeight = getLayoutHeight();
// The starting position of the bottom stack peek
- float bottomPeekStart = stackHeight - mBottomStackPeekSize;
+ float bottomPeekStart = mLayoutHeight - mBottomStackPeekSize;
// The position where the bottom stack starts.
- float transitioningPositionStart = bottomPeekStart - mCollapsedSize;
+ float bottomStackStart = bottomPeekStart - mCollapsedSize;
// The y coordinate of the current child.
float currentYPosition = 0.0f;
@@ -160,76 +197,110 @@
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
- childViewState.yTranslation = currentYPosition;
childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN;
int childHeight = child.getHeight();
- // The y position after this element
- float nextYPosition = currentYPosition + childHeight + mPaddingBetweenElements;
float yPositionInScrollViewAfterElement = yPositionInScrollView
+ childHeight
+ mPaddingBetweenElements;
- float scrollOffset = yPositionInScrollViewAfterElement - algorithmState.scrollY;
- if (i < algorithmState.lastTopStackIndex) {
+ float scrollOffset = yPositionInScrollView - algorithmState.scrollY + mCollapsedSize;
+
+ if (i == algorithmState.lastTopStackIndex + 1) {
+ // Normally the position of this child is the position in the regular scrollview,
+ // but if the two stacks are very close to each other,
+ // then have have to push it even more upwards to the position of the bottom
+ // stack start.
+ currentYPosition = Math.min(scrollOffset, bottomStackStart);
+ }
+ childViewState.yTranslation = currentYPosition;
+
+ // The y position after this element
+ float nextYPosition = currentYPosition + childHeight +
+ mPaddingBetweenElements;
+
+ if (i <= algorithmState.lastTopStackIndex) {
// Case 1:
// We are in the top Stack
- nextYPosition = updateStateForTopStackChild(algorithmState,
- numberOfElementsCompletelyIn,
- i, childViewState);
- } else if (i == algorithmState.lastTopStackIndex) {
+ updateStateForTopStackChild(algorithmState,
+ numberOfElementsCompletelyIn, i, childHeight, childViewState, scrollOffset);
+ clampYTranslation(childViewState, childHeight);
+ // check if we are overlapping with the bottom stack
+ if (childViewState.yTranslation + childHeight + mPaddingBetweenElements
+ >= bottomStackStart && !mIsExpansionChanging) {
+ // TODO: handle overlapping sizes with end stack better
+ // we just collapse this element
+ childViewState.height = mCollapsedSize;
+ }
+ } else if (nextYPosition >= bottomStackStart) {
// Case 2:
- // First element of regular scrollview comes next, so the position is just the
- // scrolling position
- nextYPosition = updateStateForFirstScrollingChild(transitioningPositionStart,
- childViewState, scrollOffset);
- } else if (nextYPosition >= transitioningPositionStart) {
- if (currentYPosition >= transitioningPositionStart) {
- // Case 3:
+ // We are in the bottom stack.
+ if (currentYPosition >= bottomStackStart) {
// According to the regular scroll view we are fully translated out of the
// bottom of the screen so we are fully in the bottom stack
- nextYPosition = updateStateForChildFullyInBottomStack(algorithmState,
- transitioningPositionStart, childViewState, childHeight);
+ updateStateForChildFullyInBottomStack(algorithmState,
+ bottomStackStart, childViewState, childHeight);
} else {
- // Case 4:
// According to the regular scroll view we are currently translating out of /
// into the bottom of the screen
- nextYPosition = updateStateForChildTransitioningInBottom(
- algorithmState, stackHeight, transitioningPositionStart,
- currentYPosition, childViewState,
- childHeight, nextYPosition);
+ updateStateForChildTransitioningInBottom(algorithmState,
+ bottomStackStart, bottomPeekStart, currentYPosition,
+ childViewState, childHeight);
}
} else {
+ // Case 3:
+ // We are in the regular scroll area.
childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+ clampYTranslation(childViewState, childHeight);
}
+
// The first card is always rendered.
if (i == 0) {
childViewState.alpha = 1.0f;
+ childViewState.yTranslation = 0;
childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD;
}
if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
- nextYPosition = Math.max(0, nextYPosition);
- currentYPosition = nextYPosition;
+ currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
yPositionInScrollView = yPositionInScrollViewAfterElement;
}
}
/**
- * Update the state for the first child which is in the regular scrolling area.
+ * Clamp the yTranslation both up and down to valid positions.
*
- * @param transitioningPositionStart the transition starting position of the bottom stack
* @param childViewState the view state of the child
- * @param scrollOffset the position in the regular scroll view after this child
- * @return the next child position
+ * @param childHeight the height of this child
*/
- private float updateStateForFirstScrollingChild(float transitioningPositionStart,
- StackScrollState.ViewState childViewState, float scrollOffset) {
- childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
- if (scrollOffset < transitioningPositionStart) {
- return scrollOffset;
- } else {
- return transitioningPositionStart;
- }
+ private void clampYTranslation(StackScrollState.ViewState childViewState, int childHeight) {
+ clampPositionToBottomStackStart(childViewState, childHeight);
+ clampPositionToTopStackEnd(childViewState, childHeight);
+ }
+
+ /**
+ * Clamp the yTranslation of the child down such that its end is at most on the beginning of
+ * the bottom stack.
+ *
+ * @param childViewState the view state of the child
+ * @param childHeight the height of this child
+ */
+ private void clampPositionToBottomStackStart(StackScrollState.ViewState childViewState,
+ int childHeight) {
+ childViewState.yTranslation = Math.min(childViewState.yTranslation,
+ mLayoutHeight - mBottomStackPeekSize - childHeight);
+ }
+
+ /**
+ * Clamp the yTranslation of the child up such that its end is at lest on the end of the top
+ * stack.
+ *
+ * @param childViewState the view state of the child
+ * @param childHeight the height of this child
+ */
+ private void clampPositionToTopStackEnd(StackScrollState.ViewState childViewState,
+ int childHeight) {
+ childViewState.yTranslation = Math.max(childViewState.yTranslation,
+ mCollapsedSize - childHeight);
}
private int getMaxAllowedChildHeight(View child) {
@@ -240,41 +311,35 @@
return child.getHeight();
}
- private float updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
- float stackHeight, float transitioningPositionStart, float currentYPosition,
- StackScrollState.ViewState childViewState, int childHeight, float nextYPosition) {
- float newSize = transitioningPositionStart + mCollapsedSize - currentYPosition;
- newSize = Math.min(childHeight, newSize);
- // Transitioning element on top of bottom stack:
- algorithmState.partialInBottom = 1.0f - (
- (stackHeight - mBottomStackPeekSize - nextYPosition) / mCollapsedSize);
- // Our element can be expanded, so we might even have to scroll further than
- // mCollapsedSize
- algorithmState.partialInBottom = Math.min(1.0f, algorithmState.partialInBottom);
- float offset = mBottomStackIndentationFunctor.getValue(
- algorithmState.partialInBottom);
- nextYPosition = transitioningPositionStart + offset;
- algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
- // TODO: only temporarily collapse
- if (childHeight != (int) newSize) {
- childViewState.height = (int) newSize;
- }
- childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+ private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
+ float transitioningPositionStart, float bottomPeakStart, float currentYPosition,
+ StackScrollState.ViewState childViewState, int childHeight) {
- return nextYPosition;
+ // This is the transitioning element on top of bottom stack, calculate how far we are in.
+ algorithmState.partialInBottom = 1.0f - (
+ (transitioningPositionStart - currentYPosition) / (childHeight +
+ mPaddingBetweenElements));
+
+ // 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;
+
+ // We want at least to be at the end of the top stack when collapsing
+ clampPositionToTopStackEnd(childViewState, childHeight);
+ childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
}
- private float updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
+ private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
float transitioningPositionStart, StackScrollState.ViewState childViewState,
int childHeight) {
- float nextYPosition;
+ float currentYPosition;
algorithmState.itemsInBottomStack += 1.0f;
if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
// We are visually entering the bottom stack
- nextYPosition = transitioningPositionStart
- + mBottomStackIndentationFunctor.getValue(
- algorithmState.itemsInBottomStack);
+ currentYPosition = transitioningPositionStart
+ + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack);
childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING;
} else {
// we are fully inside the stack
@@ -285,43 +350,56 @@
childViewState.alpha = 1.0f - algorithmState.partialInBottom;
}
childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_HIDDEN;
- nextYPosition = transitioningPositionStart + mBottomStackPeekSize;
+ currentYPosition = mLayoutHeight;
}
- // TODO: only temporarily collapse
- if (childHeight != mCollapsedSize) {
- childViewState.height = mCollapsedSize;
- }
- return nextYPosition;
+ childViewState.yTranslation = currentYPosition - childHeight;
+ clampPositionToTopStackEnd(childViewState, childHeight);
}
- private float updateStateForTopStackChild(StackScrollAlgorithmState algorithmState,
- int numberOfElementsCompletelyIn, int i, StackScrollState.ViewState childViewState) {
+ private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState,
+ int numberOfElementsCompletelyIn, int i, int childHeight,
+ StackScrollState.ViewState childViewState, float scrollOffset) {
- float nextYPosition = 0;
// First we calculate the index relative to the current stack window of size at most
// {@link #MAX_ITEMS_IN_TOP_STACK}
- int paddedIndex = i
+ int paddedIndex = i - 1
- Math.max(numberOfElementsCompletelyIn - MAX_ITEMS_IN_TOP_STACK, 0);
if (paddedIndex >= 0) {
+
// We are currently visually entering the top stack
- nextYPosition = mCollapsedSize + mPaddingBetweenElements -
- mTopStackIndentationFunctor.getValue(
- algorithmState.itemsInTopStack - i - 1);
- nextYPosition = Math.min(nextYPosition, mLayoutHeight - mCollapsedSize
- - mBottomStackPeekSize);
- if (paddedIndex == 0) {
- childViewState.alpha = 1.0f - algorithmState.partialInTop;
- childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
+ float distanceToStack = childHeight - algorithmState.scrolledPixelsTop;
+ if (i == algorithmState.lastTopStackIndex && distanceToStack > mTopStackTotalSize) {
+
+ // Child is currently translating into stack but not yet inside slow down zone.
+ // Handle it like the regular scrollview.
+ childViewState.yTranslation = scrollOffset;
} else {
- childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
+ // Apply stacking logic.
+ float numItemsBefore;
+ if (i == algorithmState.lastTopStackIndex) {
+ numItemsBefore = 1.0f - (distanceToStack / mTopStackTotalSize);
+ } else {
+ numItemsBefore = algorithmState.itemsInTopStack - i;
+ }
+ // The end position of the current child
+ float currentChildEndY = mCollapsedSize + mTopStackTotalSize -
+ mTopStackIndentationFunctor.getValue(numItemsBefore);
+ childViewState.yTranslation = currentChildEndY - childHeight;
}
+ childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
} else {
- // We are hidden behind the top card and faded out, so we can hide ourselves.
- childViewState.alpha = 0.0f;
+ if (paddedIndex == -1) {
+ childViewState.alpha = 1.0f - algorithmState.partialInTop;
+ } else {
+ // We are hidden behind the top card and faded out, so we can hide ourselves.
+ childViewState.alpha = 0.0f;
+ }
+ childViewState.yTranslation = mCollapsedSize - childHeight;
childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
}
- return nextYPosition;
+
+
}
/**
@@ -347,10 +425,22 @@
+ childHeight
+ mPaddingBetweenElements;
if (yPositionInScrollView < algorithmState.scrollY) {
- if (yPositionInScrollViewAfterElement <= algorithmState.scrollY) {
+ if (i == 0 && algorithmState.scrollY == mCollapsedSize) {
+
+ // The starting position of the bottom stack peek
+ int bottomPeekStart = mLayoutHeight - mBottomStackPeekSize;
+ // Collapse and expand the first child while the shade is being expanded
+ float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
+ ? mFirstChildMaxHeight
+ : childHeight;
+ childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
+ mCollapsedSize);
+ algorithmState.itemsInTopStack = 1.0f;
+
+ } else if (yPositionInScrollViewAfterElement < algorithmState.scrollY) {
// According to the regular scroll view we are fully off screen
algorithmState.itemsInTopStack += 1.0f;
- if (childHeight != mCollapsedSize) {
+ if (i == 0) {
childViewState.height = mCollapsedSize;
}
} else {
@@ -360,45 +450,27 @@
- mPaddingBetweenElements
- algorithmState.scrollY;
+ if (i == 0) {
+ newSize += mCollapsedSize;
+ }
+
// How much did we scroll into this child
- algorithmState.partialInTop = (mCollapsedSize - newSize) / (mCollapsedSize
+ algorithmState.scrolledPixelsTop = childHeight - newSize;
+ algorithmState.partialInTop = (algorithmState.scrolledPixelsTop) / (childHeight
+ mPaddingBetweenElements);
// Our element can be expanded, so this can get negative
algorithmState.partialInTop = Math.max(0.0f, algorithmState.partialInTop);
algorithmState.itemsInTopStack += algorithmState.partialInTop;
- // TODO: handle overlapping sizes with end stack
newSize = Math.max(mCollapsedSize, newSize);
- // TODO: only temporarily collapse
- if (newSize != childHeight) {
+ if (i == 0) {
childViewState.height = (int) newSize;
-
- // We decrease scrollY by the same amount we made this child smaller.
- // The new scroll position is therefore the start of the element
- algorithmState.scrollY = (int) yPositionInScrollView;
- resultState.setScrollY(algorithmState.scrollY);
}
- if (childHeight > mCollapsedSize) {
- // If we are just resizing this child, this element is not treated to be
- // transitioning into the stack and therefore it is the last element in
- // the stack.
- algorithmState.lastTopStackIndex = i;
- break;
- }
+ algorithmState.lastTopStackIndex = i;
+ break;
}
} else {
- algorithmState.lastTopStackIndex = i;
- if (i == 0) {
-
- // The starting position of the bottom stack peek
- float bottomPeekStart = getLayoutHeight() - mBottomStackPeekSize;
- // Collapse and expand the first child while the shade is being expanded
- float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
- ? mFirstChildMaxHeight
- : childHeight;
- childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
- mCollapsedSize);
- }
+ algorithmState.lastTopStackIndex = i - 1;
// We are already past the stack so we can end the loop
break;
}
@@ -435,11 +507,11 @@
}
}
- public float getLayoutHeight() {
+ public int getLayoutHeight() {
return mLayoutHeight;
}
- public void setLayoutHeight(float layoutHeight) {
+ public void setLayoutHeight(int layoutHeight) {
this.mLayoutHeight = layoutHeight;
}
@@ -461,7 +533,23 @@
} else {
// We are expanding the shade, expand it to its full height.
- mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
+ if (mFirstChildWhileExpanding.getWidth() == 0) {
+
+ // This child was not layouted yet, wait for a layout pass
+ mFirstChildWhileExpanding
+ .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ 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);
+ }
+ });
+ } else {
+ mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
+ }
}
} else {
mFirstChildMaxHeight = 0;
@@ -512,10 +600,12 @@
public float partialInTop;
/**
+ * The number of pixels the last child in the top stack has scrolled in to the stack
+ */
+ public float scrolledPixelsTop;
+
+ /**
* The last item index which is in the top stack.
- * NOTE: In the top stack the item after the transitioning element is also in the stack!
- * This is needed to ensure a smooth transition between the y position in the regular
- * scrollview and the one in the stack.
*/
public int lastTopStackIndex;
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 06a08f3..9742e65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -16,10 +16,14 @@
package com.android.systemui.statusbar.stack;
+import android.graphics.Outline;
+import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import com.android.systemui.R;
+
import java.util.HashMap;
import java.util.Map;
@@ -34,6 +38,10 @@
private final ViewGroup mHostView;
private Map<View, ViewState> mStateMap;
private int mScrollY;
+ private final Rect mClipRect = new Rect();
+ private int mBackgroundRoundedRectCornerRadius;
+ private final Outline mChildOutline = new Outline();
+ private final int mChildDividerHeight;
public int getScrollY() {
return mScrollY;
@@ -46,6 +54,10 @@
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
mStateMap = new HashMap<View, ViewState>();
+ mBackgroundRoundedRectCornerRadius = hostView.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_quantum_rounded_rect_radius);
+ mChildDividerHeight = hostView.getResources().getDimensionPixelSize(R.dimen
+ .notification_divider_height);
}
public ViewGroup getHostView() {
@@ -83,10 +95,17 @@
*/
public void apply() {
int numChildren = mHostView.getChildCount();
+ float previousNotificationEnd = 0;
+ float previousNotificationStart = 0;
for (int i = 0; i < numChildren; i++) {
View child = mHostView.getChildAt(i);
ViewState state = mStateMap.get(child);
- if (state != null) {
+ if (state == null) {
+ Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
+ "to the hostView");
+ continue;
+ }
+ if (!state.gone) {
float alpha = child.getAlpha();
float yTranslation = child.getTranslationY();
float zTranslation = child.getTranslationZ();
@@ -117,7 +136,7 @@
// apply visibility
int oldVisibility = child.getVisibility();
int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
- if (newVisibility != oldVisibility && !state.gone) {
+ if (newVisibility != oldVisibility) {
child.setVisibility(newVisibility);
}
@@ -135,13 +154,94 @@
if (height != newHeight) {
applyNewHeight(child, newHeight);
}
- } else {
- Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
- "to the hostView");
+
+ // apply clipping and shadow
+ float newNotificationEnd = newYTranslation + newHeight;
+ updateChildClippingAndShadow(child, newHeight,
+ newNotificationEnd - (previousNotificationEnd - mChildDividerHeight),
+ newHeight - (previousNotificationStart - newYTranslation));
+
+ previousNotificationStart = newYTranslation;
+ previousNotificationEnd = newNotificationEnd;
}
}
}
+ /**
+ * Updates the shadow outline and the clipping for a view.
+ *
+ * @param child the view to update
+ * @param realHeight the currently applied height of the view
+ * @param clipHeight the desired clip height, the rest of the view will be clipped from the top
+ * @param shadowHeight the desired height of the shadow, the shadow ends on the bottom
+ */
+ private void updateChildClippingAndShadow(View child, int realHeight, float clipHeight,
+ float shadowHeight) {
+ if (realHeight > shadowHeight) {
+ updateChildOutline(child, realHeight, shadowHeight);
+ } else {
+ updateChildOutline(child, realHeight, realHeight);
+ }
+ if (realHeight > clipHeight) {
+ updateChildClip(child, realHeight, clipHeight);
+ } else {
+ child.setClipBounds(null);
+ }
+ }
+
+ /**
+ * Updates the clipping of a view
+ *
+ * @param child the view to update
+ * @param height the currently applied height of the view
+ * @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);
+ }
+ }
+
+ /**
+ * Updates the outline of a view
+ *
+ * @param child the view to update
+ * @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 getOutlineForSize(int leftInset, int topInset, int width, int height,
+ Outline result) {
+ result.setRoundRect(leftInset, topInset, leftInset + width, topInset + height,
+ mBackgroundRoundedRectCornerRadius);
+ }
+
private void applyNewHeight(View child, int newHeight) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
lp.height = newHeight;
diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk
index d9566d5..79f8a1f 100644
--- a/packages/services/PacProcessor/Android.mk
+++ b/packages/services/PacProcessor/Android.mk
@@ -25,7 +25,9 @@
LOCAL_PACKAGE_NAME := PacProcessor
LOCAL_CERTIFICATE := platform
-LOCAL_REQUIRED_MODULES := libjni_pacprocessor
+LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor
+
+LOCAL_MULTILIB := 32
include $(BUILD_PACKAGE)
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index c6972b1..fec9dda 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -51,6 +51,7 @@
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.util.ArraySet;
import android.util.Log;
import android.util.TypedValue;
import android.view.InputDevice;
@@ -83,6 +84,15 @@
private static final boolean SHOW_SILENT_TOGGLE = true;
+ /* Valid settings for global actions keys.
+ * see config.xml config_globalActionList */
+ private static final String GLOBAL_ACTION_KEY_POWER = "power";
+ private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+ private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+ private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
+ private static final String GLOBAL_ACTION_KEY_USERS = "users";
+ private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
+
private final Context mContext;
private final WindowManagerFuncs mWindowManagerFuncs;
private final AudioManager mAudioManager;
@@ -235,92 +245,36 @@
onAirplaneModeChanged();
mItems = new ArrayList<Action>();
+ String[] defaultActions = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_globalActionsList);
- // first: power off
- mItems.add(
- new SinglePressAction(
- com.android.internal.R.drawable.ic_lock_power_off,
- R.string.global_action_power_off) {
-
- public void onPress() {
- // shutdown by making sure radio and power are handled accordingly.
- mWindowManagerFuncs.shutdown(true);
- }
-
- public boolean onLongPress() {
- mWindowManagerFuncs.rebootSafeMode(true);
- return true;
- }
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return true;
- }
- });
-
- // next: airplane mode
- mItems.add(mAirplaneModeOn);
-
- // next: bug report, if enabled
- if (Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
- mItems.add(
- new SinglePressAction(com.android.internal.R.drawable.ic_lock_bugreport,
- R.string.global_action_bug_report) {
-
- public void onPress() {
- AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setTitle(com.android.internal.R.string.bugreport_title);
- builder.setMessage(com.android.internal.R.string.bugreport_message);
- builder.setNegativeButton(com.android.internal.R.string.cancel, null);
- builder.setPositiveButton(com.android.internal.R.string.report,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // Add a little delay before executing, to give the
- // dialog a chance to go away before it takes a
- // screenshot.
- mHandler.postDelayed(new Runnable() {
- @Override public void run() {
- try {
- ActivityManagerNative.getDefault()
- .requestBugReport();
- } catch (RemoteException e) {
- }
- }
- }, 500);
- }
- });
- AlertDialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.show();
- }
-
- public boolean onLongPress() {
- return false;
- }
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return false;
- }
- });
- }
-
- // last: silent mode
- if (mShowSilentToggle) {
- mItems.add(mSilentModeAction);
- }
-
- // one more thing: optionally add a list of users to switch to
- if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
- addUsersToMenu(mItems);
+ ArraySet<String> addedKeys = new ArraySet<String>();
+ for (int i = 0; i < defaultActions.length; i++) {
+ String actionKey = defaultActions[i];
+ if (addedKeys.contains(actionKey)) {
+ // If we already have added this, don't add it again.
+ continue;
+ }
+ if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
+ mItems.add(getPowerAction());
+ } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
+ mItems.add(mAirplaneModeOn);
+ } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)
+ && (Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner())) {
+ mItems.add(getBugReportAction());
+ } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey) && mShowSilentToggle) {
+ mItems.add(mSilentModeAction);
+ } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)
+ && SystemProperties.getBoolean("fw.power_user_switcher", false)) {
+ addUsersToMenu(mItems);
+ } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
+ mItems.add(getSettingsAction());
+ } else {
+ Log.e(TAG, "Invalid global action key " + actionKey);
+ }
+ // Add here so we don't add more than one.
+ addedKeys.add(actionKey);
}
mAdapter = new MyAdapter();
@@ -350,6 +304,105 @@
return dialog;
}
+ private Action getPowerAction() {
+ return new SinglePressAction(
+ com.android.internal.R.drawable.ic_lock_power_off,
+ R.string.global_action_power_off) {
+
+ public void onPress() {
+ // shutdown by making sure radio and power are handled accordingly.
+ mWindowManagerFuncs.shutdown(true);
+ }
+
+ public boolean onLongPress() {
+ mWindowManagerFuncs.rebootSafeMode(true);
+ return true;
+ }
+
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+ };
+ }
+
+ private Action getBugReportAction() {
+ return new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,
+ R.string.global_action_bug_report) {
+
+ public void onPress() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setTitle(com.android.internal.R.string.bugreport_title);
+ builder.setMessage(com.android.internal.R.string.bugreport_message);
+ builder.setNegativeButton(com.android.internal.R.string.cancel, null);
+ builder.setPositiveButton(com.android.internal.R.string.report,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Add a little delay before executing, to give the
+ // dialog a chance to go away before it takes a
+ // screenshot.
+ mHandler.postDelayed(new Runnable() {
+ @Override public void run() {
+ try {
+ ActivityManagerNative.getDefault()
+ .requestBugReport();
+ } catch (RemoteException e) {
+ }
+ }
+ }, 500);
+ }
+ });
+ AlertDialog dialog = builder.create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ dialog.show();
+ }
+
+ public boolean onLongPress() {
+ return false;
+ }
+
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+ };
+ }
+
+ private Action getSettingsAction() {
+ return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
+ R.string.global_action_settings) {
+
+ @Override
+ public void onPress() {
+ Intent intent = new Intent(Settings.ACTION_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+
+ @Override
+ public boolean onLongPress() {
+ return false;
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+ };
+ }
+
private UserInfo getCurrentUser() {
try {
return ActivityManagerNative.getDefault().getCurrentUser();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 2cf94d0..0550dd4 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -3580,6 +3580,7 @@
SwipeDismissLayout layout, float progress, float translate) {
WindowManager.LayoutParams newParams = getAttributes();
newParams.x = (int) translate;
+ newParams.alpha = 1 - progress;
setAttributes(newParams);
int flags = 0;
@@ -3595,6 +3596,7 @@
public void onSwipeCancelled(SwipeDismissLayout layout) {
WindowManager.LayoutParams newParams = getAttributes();
newParams.x = 0;
+ newParams.alpha = 1;
setAttributes(newParams);
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
}
diff --git a/preloaded-classes b/preloaded-classes
index 35c52ad..4413cd3 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -601,8 +601,6 @@
android.media.ResampleInputStream
android.media.SoundPool
android.media.ToneGenerator
-android.media.videoeditor.MediaArtistNativeHelper
-android.media.videoeditor.VideoEditorProfile
android.mtp.MtpDatabase
android.mtp.MtpDevice
android.mtp.MtpDeviceInfo
diff --git a/rs/java/android/renderscript/ScriptIntrinsicResize.java b/rs/java/android/renderscript/ScriptIntrinsicResize.java
index cc37120..fe56699 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicResize.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicResize.java
@@ -18,7 +18,6 @@
/**
* Intrinsic for performing a resize of a 2D allocation.
- * @hide
*/
public final class ScriptIntrinsicResize extends ScriptIntrinsic {
private Allocation mInput;
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 671b43de..18a2e31 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -47,24 +47,29 @@
using namespace android;
-#define PER_ARRAY_TYPE(flag, fnc, ...) { \
+#define PER_ARRAY_TYPE(flag, fnc, readonly, ...) { \
jint len = 0; \
void *ptr = NULL; \
size_t typeBytes = 0; \
+ jint relFlag = 0; \
+ if (readonly) { \
+ /* The on-release mode should only be JNI_ABORT for read-only accesses. */ \
+ relFlag = JNI_ABORT; \
+ } \
switch(dataType) { \
case RS_TYPE_FLOAT_32: \
len = _env->GetArrayLength((jfloatArray)data); \
ptr = _env->GetFloatArrayElements((jfloatArray)data, flag); \
typeBytes = 4; \
fnc(__VA_ARGS__); \
- _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, JNI_ABORT); \
+ _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, relFlag); \
return; \
case RS_TYPE_FLOAT_64: \
len = _env->GetArrayLength((jdoubleArray)data); \
ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag); \
typeBytes = 8; \
fnc(__VA_ARGS__); \
- _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, JNI_ABORT);\
+ _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, relFlag); \
return; \
case RS_TYPE_SIGNED_8: \
case RS_TYPE_UNSIGNED_8: \
@@ -72,7 +77,7 @@
ptr = _env->GetByteArrayElements((jbyteArray)data, flag); \
typeBytes = 1; \
fnc(__VA_ARGS__); \
- _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, JNI_ABORT); \
+ _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, relFlag); \
return; \
case RS_TYPE_SIGNED_16: \
case RS_TYPE_UNSIGNED_16: \
@@ -80,7 +85,7 @@
ptr = _env->GetShortArrayElements((jshortArray)data, flag); \
typeBytes = 2; \
fnc(__VA_ARGS__); \
- _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, JNI_ABORT); \
+ _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, relFlag); \
return; \
case RS_TYPE_SIGNED_32: \
case RS_TYPE_UNSIGNED_32: \
@@ -88,7 +93,7 @@
ptr = _env->GetIntArrayElements((jintArray)data, flag); \
typeBytes = 4; \
fnc(__VA_ARGS__); \
- _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, JNI_ABORT); \
+ _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, relFlag); \
return; \
case RS_TYPE_SIGNED_64: \
case RS_TYPE_UNSIGNED_64: \
@@ -96,7 +101,7 @@
ptr = _env->GetLongArrayElements((jlongArray)data, flag); \
typeBytes = 8; \
fnc(__VA_ARGS__); \
- _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, JNI_ABORT); \
+ _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, relFlag); \
return; \
default: \
break; \
@@ -672,6 +677,7 @@
}
+// Copies from the Java object data into the Allocation pointed to by _alloc.
static void
nAllocationData1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
jint count, jobject data, jint sizeBytes, jint dataType)
@@ -679,9 +685,10 @@
RsAllocation *alloc = (RsAllocation *)_alloc;
LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)",
(RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes, dataType);
- PER_ARRAY_TYPE(NULL, rsAllocation1DData, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
+ PER_ARRAY_TYPE(NULL, rsAllocation1DData, true, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
}
+// Copies from the Java array data into the Allocation pointed to by alloc.
static void
// native void rsnAllocationElementData1D(long con, long id, int xoff, int compIdx, byte[] d, int sizeBytes);
nAllocationElementData1D(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jint offset, jint lod, jint compIdx, jbyteArray data, jint sizeBytes)
@@ -693,6 +700,7 @@
_env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
}
+// Copies from the Java object data into the Allocation pointed to by _alloc.
static void
nAllocationData2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
jint w, jint h, jobject data, jint sizeBytes, jint dataType)
@@ -701,9 +709,11 @@
RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
LOG_API("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)",
(RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
- PER_ARRAY_TYPE(NULL, rsAllocation2DData, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
+ PER_ARRAY_TYPE(NULL, rsAllocation2DData, true, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
}
+// Copies from the Allocation pointed to by srcAlloc into the Allocation
+// pointed to by dstAlloc.
static void
nAllocationData2D_alloc(JNIEnv *_env, jobject _this, jlong con,
jlong dstAlloc, jint dstXoff, jint dstYoff,
@@ -728,6 +738,7 @@
srcMip, srcFace);
}
+// Copies from the Java object data into the Allocation pointed to by _alloc.
static void
nAllocationData3D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint zoff, jint lod,
jint w, jint h, jint d, jobject data, int sizeBytes, int dataType)
@@ -735,9 +746,11 @@
RsAllocation *alloc = (RsAllocation *)_alloc;
LOG_API("nAllocation3DData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i), h(%i), d(%i), sizeBytes(%i)",
(RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, sizeBytes);
- PER_ARRAY_TYPE(NULL, rsAllocation3DData, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+ PER_ARRAY_TYPE(NULL, rsAllocation3DData, true, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
}
+// Copies from the Allocation pointed to by srcAlloc into the Allocation
+// pointed to by dstAlloc.
static void
nAllocationData3D_alloc(JNIEnv *_env, jobject _this, jlong con,
jlong dstAlloc, jint dstXoff, jint dstYoff, jint dstZoff,
@@ -761,14 +774,16 @@
}
+// Copies from the Allocation pointed to by _alloc into the Java object data.
static void
nAllocationRead(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jobject data, int dataType)
{
RsAllocation *alloc = (RsAllocation *)_alloc;
LOG_API("nAllocationRead, con(%p), alloc(%p)", (RsContext)con, (RsAllocation)alloc);
- PER_ARRAY_TYPE(0, rsAllocationRead, (RsContext)con, alloc, ptr, len * typeBytes);
+ PER_ARRAY_TYPE(0, rsAllocationRead, false, (RsContext)con, alloc, ptr, len * typeBytes);
}
+// Copies from the Allocation pointed to by _alloc into the Java object data.
static void
nAllocationRead1D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint offset, jint lod,
jint count, jobject data, int sizeBytes, int dataType)
@@ -776,9 +791,10 @@
RsAllocation *alloc = (RsAllocation *)_alloc;
LOG_API("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)",
(RsContext)con, alloc, offset, count, sizeBytes, dataType);
- PER_ARRAY_TYPE(0, rsAllocation1DRead, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
+ PER_ARRAY_TYPE(0, rsAllocation1DRead, false, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
}
+// Copies from the Allocation pointed to by _alloc into the Java object data.
static void
nAllocationRead2D(JNIEnv *_env, jobject _this, jlong con, jlong _alloc, jint xoff, jint yoff, jint lod, jint _face,
jint w, jint h, jobject data, int sizeBytes, int dataType)
@@ -787,7 +803,7 @@
RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
LOG_API("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)",
(RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
- PER_ARRAY_TYPE(0, rsAllocation2DRead, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
+ PER_ARRAY_TYPE(0, rsAllocation2DRead, false, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
}
static jlong
@@ -1023,7 +1039,7 @@
jint len = _env->GetArrayLength(data);
jbyte *ptr = _env->GetByteArrayElements(data, NULL);
rsScriptGetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
- _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
+ _env->ReleaseByteArrayElements(data, ptr, 0);
}
static void
diff --git a/services/Android.mk b/services/Android.mk
index 165f456..5fcef64 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -25,7 +25,8 @@
backup \
devicepolicy \
print \
- usb
+ usb \
+ voiceinteraction
# The convention is to name each service module 'services.$(module_name)'
LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 2f56e62..87b1d32 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -50,6 +50,7 @@
import android.os.UserHandle;
import android.util.AtomicFile;
import android.util.AttributeSet;
+import android.util.MutableInt;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -86,8 +87,6 @@
import java.util.Map.Entry;
import java.util.Set;
-import libcore.util.MutableInt;
-
class AppWidgetServiceImpl {
private static final String KEYGUARD_HOST_PACKAGE = "com.android.keyguard";
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index bce85ce..7249985 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -106,22 +106,33 @@
.append("Kernel: ")
.append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
.append("\n").toString();
+ final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
String recovery = RecoverySystem.handleAftermath();
if (recovery != null && db != null) {
db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
}
+ String lastKmsgFooter = "";
+ if (bootReason != null) {
+ lastKmsgFooter = new StringBuilder(512)
+ .append("\n")
+ .append("Boot info:\n")
+ .append("Last boot reason: ").append(bootReason).append("\n")
+ .toString();
+ }
+
if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
String now = Long.toString(System.currentTimeMillis());
SystemProperties.set("ro.runtime.firstboot", now);
if (db != null) db.addText("SYSTEM_BOOT", headers);
// Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
- addFileToDropBox(db, prefs, headers, "/proc/last_kmsg",
- -LOG_SIZE, "SYSTEM_LAST_KMSG");
- addFileToDropBox(db, prefs, headers, "/sys/fs/pstore/console-ramoops",
- -LOG_SIZE, "SYSTEM_LAST_KMSG");
+ addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
+ "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
+ addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
+ "/sys/fs/pstore/console-ramoops", -LOG_SIZE,
+ "SYSTEM_LAST_KMSG");
addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
-LOG_SIZE, "SYSTEM_RECOVERY_LOG");
addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
@@ -161,6 +172,14 @@
private static void addFileToDropBox(
DropBoxManager db, SharedPreferences prefs,
String headers, String filename, int maxSize, String tag) throws IOException {
+ addFileWithFootersToDropBox(db, prefs, headers, "", filename, maxSize,
+ tag);
+ }
+
+ private static void addFileWithFootersToDropBox(
+ DropBoxManager db, SharedPreferences prefs,
+ String headers, String footers, String filename, int maxSize,
+ String tag) throws IOException {
if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled
File file = new File(filename);
@@ -176,7 +195,7 @@
}
Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
- db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"));
+ db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") + footers);
}
private static void addAuditErrorsToDropBox(DropBoxManager db, SharedPreferences prefs,
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index e6163bd..62deec2 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -450,6 +450,27 @@
if (provider == null) {
Slog.e(TAG, "no geofence provider found");
}
+
+ String[] testProviderStrings = resources.getStringArray(
+ com.android.internal.R.array.config_testLocationProviders);
+ for (String testProviderString : testProviderStrings) {
+ String fragments[] = testProviderString.split(",");
+ String name = fragments[0].trim();
+ if (mProvidersByName.get(name) != null) {
+ throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
+ }
+ ProviderProperties properties = new ProviderProperties(
+ Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
+ Boolean.parseBoolean(fragments[2]) /* requiresSatellite */,
+ Boolean.parseBoolean(fragments[3]) /* requiresCell */,
+ Boolean.parseBoolean(fragments[4]) /* hasMonetaryCost */,
+ Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
+ Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
+ Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
+ Integer.parseInt(fragments[8]) /* powerRequirement */,
+ Integer.parseInt(fragments[9]) /* accuracy */);
+ addTestProviderLocked(name, properties);
+ }
}
/**
@@ -2204,7 +2225,6 @@
long identity = Binder.clearCallingIdentity();
synchronized (mLock) {
- MockProvider provider = new MockProvider(name, this, properties);
// remove the real provider if we are replacing GPS or network provider
if (LocationManager.GPS_PROVIDER.equals(name)
|| LocationManager.NETWORK_PROVIDER.equals(name)
@@ -2214,18 +2234,23 @@
removeProviderLocked(p);
}
}
- if (mProvidersByName.get(name) != null) {
- throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
- }
- addProviderLocked(provider);
- mMockProviders.put(name, provider);
- mLastLocation.put(name, null);
- mLastLocationCoarseInterval.put(name, null);
+ addTestProviderLocked(name, properties);
updateProvidersLocked();
}
Binder.restoreCallingIdentity(identity);
}
+ private void addTestProviderLocked(String name, ProviderProperties properties) {
+ if (mProvidersByName.get(name) != null) {
+ throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
+ }
+ MockProvider provider = new MockProvider(name, this, properties);
+ addProviderLocked(provider);
+ mMockProviders.put(name, provider);
+ mLastLocation.put(name, null);
+ mLastLocationCoarseInterval.put(name, null);
+ }
+
@Override
public void removeTestProvider(String provider) {
checkMockPermissionsSafe();
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 62eb663..0d1e122 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -20,6 +20,7 @@
import android.net.LocalSocketAddress;
import android.os.Build;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -59,6 +60,8 @@
private final PowerManager.WakeLock mWakeLock;
+ private final Looper mLooper;
+
private INativeDaemonConnectorCallbacks mCallbacks;
private Handler mCallbackHandler;
@@ -74,6 +77,13 @@
NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) {
+ this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl,
+ FgThread.get().getLooper());
+ }
+
+ NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket,
+ int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl,
+ Looper looper) {
mCallbacks = callbacks;
mSocket = socket;
mResponseQueue = new ResponseQueue(responseQueueSize);
@@ -81,6 +91,7 @@
if (mWakeLock != null) {
mWakeLock.setReferenceCounted(true);
}
+ mLooper = looper;
mSequenceNumber = new AtomicInteger(0);
TAG = logTag != null ? logTag : "NativeDaemonConnector";
mLocalLog = new LocalLog(maxLogSize);
@@ -88,7 +99,7 @@
@Override
public void run() {
- mCallbackHandler = new Handler(FgThread.get().getLooper(), this);
+ mCallbackHandler = new Handler(mLooper, this);
while (true) {
try {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 9629bd1..7ce45f7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -58,6 +58,8 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.PhoneStateListener;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -143,21 +145,25 @@
public static final int InterfaceDnsServerInfo = 615;
}
+ static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
+
/**
* Binder context for this service
*/
- private Context mContext;
+ private final Context mContext;
/**
* connector object for communicating with netd
*/
- private NativeDaemonConnector mConnector;
+ private final NativeDaemonConnector mConnector;
- private final Handler mMainHandler = new Handler();
+ private final Handler mFgHandler;
+ private final Handler mDaemonHandler;
+ private final PhoneStateListener mPhoneStateListener;
private IBatteryStats mBatteryStats;
- private Thread mThread;
+ private final Thread mThread;
private CountDownLatch mConnectedSignal = new CountDownLatch(1);
private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
@@ -191,6 +197,9 @@
private volatile boolean mBandwidthControlEnabled;
private volatile boolean mFirewallEnabled;
+ private boolean mMobileActivityFromRadio = false;
+ private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+
private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
new RemoteCallbackList<INetworkActivityListener>();
private boolean mNetworkActive;
@@ -203,21 +212,39 @@
private NetworkManagementService(Context context, String socket) {
mContext = context;
+ // make sure this is on the same looper as our NativeDaemonConnector for sync purposes
+ mFgHandler = new Handler(FgThread.get().getLooper());
+
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
+ mConnector = null;
+ mThread = null;
+ mDaemonHandler = null;
+ mPhoneStateListener = null;
return;
}
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
// Don't need this wake lock, since we now have a time stamp for when
// the network actually went inactive. (It might be nice to still do this,
// but I don't want to do it through the power manager because that pollutes the
// battery stats history with pointless noise.)
+ //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
mConnector = new NativeDaemonConnector(
- new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl);
+ new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
+ FgThread.get().getLooper());
mThread = new Thread(mConnector, NETD_TAG);
+ mDaemonHandler = new Handler(FgThread.get().getLooper());
+ mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) {
+ public void onDataConnectionRealTimeInfoChanged(
+ DataConnectionRealTimeInfo dcRtInfo) {
+ // Disabled for now, until we are getting good data.
+ //notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
+ // dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
+ }
+ };
+
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
@@ -271,14 +298,17 @@
*/
private void notifyInterfaceStatusChanged(String iface, boolean up) {
final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mObservers.finishBroadcast();
}
- mObservers.finishBroadcast();
}
/**
@@ -287,14 +317,17 @@
*/
private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mObservers.finishBroadcast();
}
- mObservers.finishBroadcast();
}
/**
@@ -302,14 +335,17 @@
*/
private void notifyInterfaceAdded(String iface) {
final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).interfaceAdded(iface);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).interfaceAdded(iface);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mObservers.finishBroadcast();
}
- mObservers.finishBroadcast();
}
/**
@@ -322,14 +358,17 @@
mActiveQuotas.remove(iface);
final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).interfaceRemoved(iface);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).interfaceRemoved(iface);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mObservers.finishBroadcast();
}
- mObservers.finishBroadcast();
}
/**
@@ -337,46 +376,78 @@
*/
private void notifyLimitReached(String limitName, String iface) {
final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).limitReached(limitName, iface);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).limitReached(limitName, iface);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mObservers.finishBroadcast();
}
- mObservers.finishBroadcast();
}
/**
* Notify our observers of a change in the data activity state of the interface
*/
- private void notifyInterfaceClassActivity(int type, boolean active, long tsNanos) {
- try {
- getBatteryStats().noteDataConnectionActive(type, active, tsNanos);
- } catch (RemoteException e) {
- }
-
- final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
- Integer.toString(type), active, tsNanos);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
+ boolean fromRadio) {
+ final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
+ if (isMobile) {
+ if (!fromRadio) {
+ if (mMobileActivityFromRadio) {
+ // If this call is not coming from a report from the radio itself, but we
+ // have previously received reports from the radio, then we will take the
+ // power state to just be whatever the radio last reported.
+ powerState = mLastPowerStateFromRadio;
+ }
+ } else {
+ mMobileActivityFromRadio = true;
+ }
+ if (mLastPowerStateFromRadio != powerState) {
+ mLastPowerStateFromRadio = powerState;
+ try {
+ getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos);
+ } catch (RemoteException e) {
+ }
}
}
- mObservers.finishBroadcast();
+
+ boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
+ || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+
+ if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
+ // Report the change in data activity. We don't do this if this is a change
+ // on the mobile network, that is not coming from the radio itself, and we
+ // have previously seen change reports from the radio. In that case only
+ // the radio is the authority for the current state.
+ final int length = mObservers.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
+ Integer.toString(type), isActive, tsNanos);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
+ }
+ } finally {
+ mObservers.finishBroadcast();
+ }
+ }
boolean report = false;
synchronized (mIdleTimerLock) {
if (mActiveIdleTimers.isEmpty()) {
- // If there are no idle times, we are not monitoring activity, so we
+ // If there are no idle timers, we are not monitoring activity, so we
// are always considered active.
- active = true;
+ isActive = true;
}
- if (mNetworkActive != active) {
- mNetworkActive = active;
- report = active;
+ if (mNetworkActive != isActive) {
+ mNetworkActive = isActive;
+ report = isActive;
}
}
if (report) {
@@ -456,14 +527,17 @@
*/
private void notifyAddressUpdated(String iface, LinkAddress address) {
final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).addressUpdated(iface, address);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).addressUpdated(iface, address);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mObservers.finishBroadcast();
}
- mObservers.finishBroadcast();
}
/**
@@ -471,14 +545,17 @@
*/
private void notifyAddressRemoved(String iface, LinkAddress address) {
final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).addressRemoved(iface, address);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).addressRemoved(iface, address);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mObservers.finishBroadcast();
}
- mObservers.finishBroadcast();
}
/**
@@ -486,14 +563,18 @@
*/
private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
final int length = mObservers.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime, addresses);
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
+ addresses);
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mObservers.finishBroadcast();
}
- mObservers.finishBroadcast();
}
//
@@ -509,7 +590,7 @@
mConnectedSignal.countDown();
mConnectedSignal = null;
} else {
- mMainHandler.post(new Runnable() {
+ mFgHandler.post(new Runnable() {
@Override
public void run() {
prepareNativeDaemon();
@@ -580,10 +661,13 @@
try {
timestampNanos = Long.parseLong(cooked[4]);
} catch(NumberFormatException ne) {}
+ } else {
+ timestampNanos = SystemClock.elapsedRealtimeNanos();
}
boolean isActive = cooked[2].equals("active");
notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
- isActive, timestampNanos);
+ isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+ : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, timestampNanos, false);
return true;
// break;
case NetdResponseCode.InterfaceAddressChange:
@@ -1270,9 +1354,11 @@
if (ConnectivityManager.isNetworkTypeMobile(type)) {
mNetworkActive = false;
}
- mMainHandler.post(new Runnable() {
+ mDaemonHandler.post(new Runnable() {
@Override public void run() {
- notifyInterfaceClassActivity(type, true, SystemClock.elapsedRealtimeNanos());
+ notifyInterfaceClassActivity(type,
+ DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
+ SystemClock.elapsedRealtimeNanos(), false);
}
});
}
@@ -1297,10 +1383,11 @@
throw e.rethrowAsParcelableException();
}
mActiveIdleTimers.remove(iface);
- mMainHandler.post(new Runnable() {
+ mDaemonHandler.post(new Runnable() {
@Override public void run() {
- notifyInterfaceClassActivity(params.type, false,
- SystemClock.elapsedRealtimeNanos());
+ notifyInterfaceClassActivity(params.type,
+ DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
+ SystemClock.elapsedRealtimeNanos(), false);
}
});
}
@@ -1880,14 +1967,17 @@
private void reportNetworkActive() {
final int length = mNetworkActivityListeners.beginBroadcast();
- for (int i = 0; i < length; i++) {
- try {
- mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
- } catch (RemoteException e) {
- } catch (RuntimeException e) {
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
+ } catch (RemoteException e) {
+ } catch (RuntimeException e) {
+ }
}
+ } finally {
+ mNetworkActivityListeners.finishBroadcast();
}
- mNetworkActivityListeners.finishBroadcast();
}
/** {@inheritDoc} */
@@ -1907,6 +1997,9 @@
pw.println();
pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
+ pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
+ pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
+ pw.print("mNetworkActive="); pw.println(mNetworkActive);
synchronized (mQuotaLock) {
pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
new file mode 100644
index 0000000..8a30e50
--- /dev/null
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -0,0 +1,136 @@
+/*
+ * 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.server;
+
+import android.Manifest.permission;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.net.INetworkScoreService;
+import android.net.NetworkKey;
+import android.net.NetworkScorerAppManager;
+import android.net.RssiCurve;
+import android.net.ScoredNetwork;
+import android.text.TextUtils;
+
+import com.android.internal.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Backing service for {@link android.net.NetworkScoreManager}.
+ * @hide
+ */
+public class NetworkScoreService extends INetworkScoreService.Stub {
+ private static final String TAG = "NetworkScoreService";
+
+ /** SharedPreference bit set to true after the service is first initialized. */
+ private static final String PREF_SCORING_PROVISIONED = "is_provisioned";
+
+ private final Context mContext;
+
+ // TODO: Delete this temporary class once we have a real place for scores.
+ private final Map<NetworkKey, RssiCurve> mScoredNetworks;
+
+ public NetworkScoreService(Context context) {
+ mContext = context;
+ mScoredNetworks = new HashMap<>();
+ }
+
+ /** Called when the system is ready to run third-party code but before it actually does so. */
+ void systemReady() {
+ SharedPreferences prefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE);
+ if (!prefs.getBoolean(PREF_SCORING_PROVISIONED, false)) {
+ // On first run, we try to initialize the scorer to the one configured at build time.
+ // This will be a no-op if the scorer isn't actually valid.
+ String defaultPackage = mContext.getResources().getString(
+ R.string.config_defaultNetworkScorerPackageName);
+ if (!TextUtils.isEmpty(defaultPackage)) {
+ NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage);
+ }
+ prefs.edit().putBoolean(PREF_SCORING_PROVISIONED, true).apply();
+ }
+ }
+
+ @Override
+ public boolean updateScores(ScoredNetwork[] networks) {
+ if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) {
+ throw new SecurityException("Caller with UID " + getCallingUid() +
+ " is not the active scorer.");
+ }
+
+ // TODO: Propagate these scores down to the network subsystem layer instead of just holding
+ // them in memory.
+ for (ScoredNetwork network : networks) {
+ mScoredNetworks.put(network.networkKey, network.rssiCurve);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean clearScores() {
+ // Only the active scorer or the system (who can broadcast BROADCAST_SCORE_NETWORKS) should
+ // be allowed to flush all scores.
+ if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
+ mContext.checkCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS) ==
+ PackageManager.PERMISSION_GRANTED) {
+ clearInternal();
+ return true;
+ } else {
+ throw new SecurityException(
+ "Caller is neither the active scorer nor the scorer manager.");
+ }
+ }
+
+ @Override
+ public boolean setActiveScorer(String packageName) {
+ mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG);
+ // Preemptively clear scores even though the set operation could fail. We do this for safety
+ // as scores should never be compared across apps; in practice, Settings should only be
+ // allowing valid apps to be set as scorers, so failure here should be rare.
+ clearInternal();
+ return NetworkScorerAppManager.setActiveScorer(mContext, packageName);
+ }
+
+ /** Clear scores. Callers are responsible for checking permissions as appropriate. */
+ private void clearInternal() {
+ // TODO: Propagate the flush down to the network subsystem layer.
+ mScoredNetworks.clear();
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
+ String currentScorer = NetworkScorerAppManager.getActiveScorer(mContext);
+ if (currentScorer == null) {
+ writer.println("Scoring is disabled.");
+ return;
+ }
+ writer.println("Current scorer: " + currentScorer);
+ if (mScoredNetworks.isEmpty()) {
+ writer.println("No networks scored.");
+ } else {
+ for (Map.Entry<NetworkKey, RssiCurve> entry : mScoredNetworks.entrySet()) {
+ writer.println(entry.getKey() + ": " + entry.getValue());
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 037a744..d4565b6 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -393,6 +393,14 @@
if (!checkNotifyPermission("notifyServiceState()")){
return;
}
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.notePhoneState(state.getState());
+ } catch (RemoteException re) {
+ // Can't do much
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
synchronized (mRecords) {
mServiceState = state;
for (Record r : mRecords) {
@@ -802,15 +810,6 @@
//
private void broadcastServiceStateChanged(ServiceState state) {
- long ident = Binder.clearCallingIdentity();
- try {
- mBatteryStats.notePhoneState(state.getState());
- } catch (RemoteException re) {
- // Can't do much
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
Bundle data = new Bundle();
state.fillInNotifierBundle(data);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7607419..b6a41bf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17,8 +17,10 @@
package com.android.server.am;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
+import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
@@ -26,19 +28,23 @@
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import android.Manifest;
import android.app.AppOpsManager;
import android.app.IActivityContainer;
import android.app.IActivityContainerCallback;
import android.appwidget.AppWidgetManager;
import android.graphics.Rect;
import android.os.BatteryStats;
+import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.ProcessStats;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
@@ -54,6 +60,7 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
+import com.android.server.SystemServiceManager;
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.firewall.IntentFirewall;
@@ -331,6 +338,9 @@
// How many bytes to write into the dropbox log before truncating
static final int DROPBOX_MAX_SIZE = 256 * 1024;
+ /** All system services */
+ SystemServiceManager mSystemServiceManager;
+
/** Run all ActivityStacks through this */
ActivityStackSupervisor mStackSupervisor;
@@ -397,7 +407,7 @@
/**
* List of intents that were used to start the most recent tasks.
*/
- private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
+ final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
public class PendingAssistExtras extends Binder implements Runnable {
public final ActivityRecord activity;
@@ -724,6 +734,7 @@
private static final String ATTR_URI = "uri";
private static final String ATTR_MODE_FLAGS = "modeFlags";
private static final String ATTR_CREATED_TIME = "createdTime";
+ private static final String ATTR_PREFIX = "prefix";
/**
* Global set of specific {@link Uri} permissions that have been granted.
@@ -731,8 +742,41 @@
* to {@link UriPermission#uri} to {@link UriPermission}.
*/
@GuardedBy("this")
- private final SparseArray<ArrayMap<Uri, UriPermission>>
- mGrantedUriPermissions = new SparseArray<ArrayMap<Uri, UriPermission>>();
+ private final SparseArray<ArrayMap<GrantUri, UriPermission>>
+ mGrantedUriPermissions = new SparseArray<ArrayMap<GrantUri, UriPermission>>();
+
+ public static class GrantUri {
+ public final Uri uri;
+ public final boolean prefix;
+
+ public GrantUri(Uri uri, boolean prefix) {
+ this.uri = uri;
+ this.prefix = prefix;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof GrantUri) {
+ GrantUri other = (GrantUri) o;
+ return uri.equals(other.uri) && prefix == other.prefix;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ if (prefix) {
+ return uri.toString() + " [prefix]";
+ } else {
+ return uri.toString();
+ }
+ }
+ }
CoreSettingsObserver mCoreSettingsObserver;
@@ -843,17 +887,23 @@
* Set while we are wanting to sleep, to prevent any
* activities from being started/resumed.
*/
- boolean mSleeping = false;
+ private boolean mSleeping = false;
+
+ /**
+ * Set while we are running a voice interaction. This overrides
+ * sleeping while it is active.
+ */
+ private boolean mRunningVoice = false;
/**
* State of external calls telling us if the device is asleep.
*/
- boolean mWentToSleep = false;
+ private boolean mWentToSleep = false;
/**
* State of external call telling us if the lock screen is shown.
*/
- boolean mLockScreenShown = false;
+ private boolean mLockScreenShown = false;
/**
* Set if we are shutting down the system, similar to sleeping.
@@ -1081,6 +1131,8 @@
static final int REQUEST_ALL_PSS_MSG = 39;
static final int START_PROFILES_MSG = 40;
static final int UPDATE_TIME = 41;
+ static final int SYSTEM_USER_START_MSG = 42;
+ static final int SYSTEM_USER_CURRENT_MSG = 43;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1660,15 +1712,15 @@
break;
}
case REPORT_USER_SWITCH_MSG: {
- dispatchUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ dispatchUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
break;
}
case CONTINUE_USER_SWITCH_MSG: {
- continueUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ continueUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
break;
}
case USER_SWITCH_TIMEOUT_MSG: {
- timeoutUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ timeoutUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
break;
}
case IMMERSIVE_MODE_LOCK_MSG: {
@@ -1715,6 +1767,14 @@
}
break;
}
+ case SYSTEM_USER_START_MSG: {
+ mSystemServiceManager.startUser(msg.arg1);
+ break;
+ }
+ case SYSTEM_USER_CURRENT_MSG: {
+ mSystemServiceManager.switchUser(msg.arg1);
+ break;
+ }
}
}
};
@@ -1777,6 +1837,78 @@
}
};
+ /**
+ * Monitor for package changes and update our internal state.
+ */
+ private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ // Remove all tasks with activities in the specified package from the list of recent tasks
+ synchronized (ActivityManagerService.this) {
+ for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+ TaskRecord tr = mRecentTasks.get(i);
+ ComponentName cn = tr.intent.getComponent();
+ if (cn != null && cn.getPackageName().equals(packageName)) {
+ // If the package name matches, remove the task and kill the process
+ removeTaskByIdLocked(tr.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ final PackageManager pm = mContext.getPackageManager();
+ final ArrayList<TaskRecord> recentTasks = new ArrayList<TaskRecord>();
+ final ArrayList<TaskRecord> tasksToRemove = new ArrayList<TaskRecord>();
+ // Copy the list of recent tasks so that we don't hold onto the lock on
+ // ActivityManagerService for long periods while checking if components exist.
+ synchronized (ActivityManagerService.this) {
+ recentTasks.addAll(mRecentTasks);
+ }
+ // Check the recent tasks and filter out all tasks with components that no longer exist.
+ Intent tmpI = new Intent();
+ for (int i = recentTasks.size() - 1; i >= 0; i--) {
+ TaskRecord tr = recentTasks.get(i);
+ ComponentName cn = tr.intent.getComponent();
+ if (cn != null && cn.getPackageName().equals(packageName)) {
+ try {
+ // Add the task to the list to remove if the component no longer exists
+ tmpI.setComponent(cn);
+ if (pm.queryIntentActivities(tmpI, PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
+ tasksToRemove.add(tr);
+ }
+ } catch (Exception e) {}
+ }
+ }
+ // Prune all the tasks with removed components from the list of recent tasks
+ synchronized (ActivityManagerService.this) {
+ for (int i = tasksToRemove.size() - 1; i >= 0; i--) {
+ TaskRecord tr = tasksToRemove.get(i);
+ // Remove the task but don't kill the process
+ removeTaskByIdLocked(tr.taskId, 0);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ // Force stop the specified packages
+ if (packages != null) {
+ for (String pkg : packages) {
+ synchronized (ActivityManagerService.this) {
+ if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0,
+ "finished booting")) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ };
+
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
@@ -2023,6 +2155,10 @@
Watchdog.getInstance().addThread(mHandler);
}
+ public void setSystemServiceManager(SystemServiceManager mgr) {
+ mSystemServiceManager = mgr;
+ }
+
private void start() {
mProcessCpuThread.start();
@@ -2218,6 +2354,11 @@
if (mFocusedActivity != r) {
if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedActivityLocked: r=" + r);
mFocusedActivity = r;
+ if (r.task != null && r.task.voiceInteractor != null) {
+ startRunningVoiceLocked();
+ } else {
+ finishRunningVoiceLocked();
+ }
mStackSupervisor.setFocusedStack(r);
if (r != null) {
mWindowManager.setFocusedApp(r.appToken, true);
@@ -2226,6 +2367,12 @@
}
}
+ final void clearFocusedActivity(ActivityRecord r) {
+ if (mFocusedActivity == r) {
+ mFocusedActivity = null;
+ }
+ }
+
@Override
public void setFocusedStack(int stackId) {
if (DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: stackId=" + stackId);
@@ -2954,7 +3101,7 @@
intent.setComponent(new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name));
mStackSupervisor.startActivityLocked(null, intent, null, ri.activityInfo,
- null, null, 0, 0, 0, null, 0, null, false, null, null);
+ null, null, null, null, 0, 0, 0, null, 0, null, false, null, null);
}
}
}
@@ -3085,7 +3232,7 @@
}
for (int i=0; i<N; i++) {
PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
- mStackSupervisor.startActivityUncheckedLocked(pal.r, pal.sourceRecord, pal.startFlags,
+ mStackSupervisor.startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
doResume && i == (N-1), null);
}
mPendingActivityLaunches.clear();
@@ -3111,7 +3258,7 @@
false, true, "startActivity", null);
// TODO: Switch to user app stacks here.
return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
+ null, null, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
null, null, options, userId, null);
}
@@ -3126,7 +3273,7 @@
WaitResult res = new WaitResult();
// TODO: Switch to user app stacks here.
mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
+ null, null, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
res, null, options, UserHandle.getCallingUserId(), null);
return res;
}
@@ -3141,7 +3288,7 @@
false, true, "startActivityWithConfig", null);
// TODO: Switch to user app stacks here.
int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, resultTo, resultWho, requestCode, startFlags,
+ resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
null, null, null, config, options, userId, null);
return ret;
}
@@ -3179,6 +3326,31 @@
}
@Override
+ public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
+ Intent intent, String resolvedType, IVoiceInteractionSession session,
+ IVoiceInteractor interactor, int startFlags, String profileFile,
+ ParcelFileDescriptor profileFd, Bundle options, int userId) {
+ if (checkCallingPermission(Manifest.permission.BIND_VOICE_INTERACTION)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: startVoiceActivity() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.BIND_VOICE_INTERACTION;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ if (session == null || interactor == null) {
+ throw new NullPointerException("null session or interactor");
+ }
+ userId = handleIncomingUser(callingPid, callingUid, userId,
+ false, true, "startVoiceActivity", null);
+ // TODO: Switch to user app stacks here.
+ return mStackSupervisor.startActivityMayWait(null, callingUid, callingPackage, intent,
+ resolvedType, session, interactor, null, null, 0, startFlags,
+ profileFile, profileFd, null, null, options, userId, null);
+ }
+
+ @Override
public boolean startNextMatchingActivity(IBinder callingActivity,
Intent intent, Bundle options) {
// Refuse possible leaked file descriptors
@@ -3271,7 +3443,7 @@
final long origId = Binder.clearCallingIdentity();
int res = mStackSupervisor.startActivityLocked(r.app.thread, intent,
- r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null,
+ r.resolvedType, aInfo, null, null, resultTo != null ? resultTo.appToken : null,
resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage, 0,
options, false, null, null);
Binder.restoreCallingIdentity(origId);
@@ -3294,7 +3466,7 @@
// TODO: Switch to user app stacks here.
int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags,
+ null, null, resultTo, resultWho, requestCode, startFlags,
null, null, null, null, options, userId, container);
return ret;
}
@@ -3330,6 +3502,10 @@
if (N > 0 && mRecentTasks.get(0) == task) {
return;
}
+ // Another quick case: never add voice sessions.
+ if (task.voiceSession != null) {
+ return;
+ }
// Remove any existing entries that are the same kind of task.
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
@@ -3417,11 +3593,14 @@
* @param token The Binder token referencing the Activity we want to finish.
* @param resultCode Result code, if any, from this Activity.
* @param resultData Result data (Intent), if any, from this Activity.
+ * @param finishTask Whether to finish the task associated with this Activity. Only applies to
+ * the root Activity in the task.
*
* @return Returns true if the activity successfully finished, or false if it is still running.
*/
@Override
- public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
+ public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
+ boolean finishTask) {
// Refuse possible leaked file descriptors
if (resultData != null && resultData.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -3432,6 +3611,9 @@
if (r == null) {
return true;
}
+ // Keep track of the root activity of the task before we finish it
+ TaskRecord tr = r.task;
+ ActivityRecord rootR = tr.getRootActivity();
if (mController != null) {
// Find the first activity that is not finishing.
ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
@@ -3451,10 +3633,21 @@
}
}
final long origId = Binder.clearCallingIdentity();
- boolean res = r.task.stack.requestFinishActivityLocked(token, resultCode,
- resultData, "app-request", true);
- Binder.restoreCallingIdentity(origId);
- return res;
+ try {
+ boolean res;
+ if (finishTask && r == rootR) {
+ // If requested, remove the task that is associated to this activity only if it
+ // was the root activity in the task. The result code and data is ignored because
+ // we don't support returning them across task boundaries.
+ res = removeTaskByIdLocked(tr.taskId, 0);
+ } else {
+ res = tr.stack.requestFinishActivityLocked(token, resultCode,
+ resultData, "app-request", true);
+ }
+ return res;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
}
@@ -5147,26 +5340,8 @@
}
final void finishBooting() {
- IntentFilter pkgFilter = new IntentFilter();
- pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
- pkgFilter.addDataScheme("package");
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
- if (pkgs != null) {
- for (String pkg : pkgs) {
- synchronized (ActivityManagerService.this) {
- if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0,
- "finished booting")) {
- setResultCode(Activity.RESULT_OK);
- return;
- }
- }
- }
- }
- }
- }, pkgFilter);
+ // Register receivers to handle package update events
+ mPackageMonitor.register(mContext, Looper.getMainLooper(), false);
synchronized (this) {
// Ensure that any processes we had put on hold are now started
@@ -5822,7 +5997,7 @@
* in {@link ContentProvider}.
*/
private final boolean checkHoldingPermissionsLocked(
- IPackageManager pm, ProviderInfo pi, Uri uri, int uid, int modeFlags) {
+ IPackageManager pm, ProviderInfo pi, Uri uri, int uid, final int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid);
@@ -5918,18 +6093,17 @@
return pi;
}
- private UriPermission findUriPermissionLocked(int targetUid, Uri uri) {
- ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+ private UriPermission findUriPermissionLocked(int targetUid, GrantUri uri) {
+ final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris != null) {
return targetUris.get(uri);
- } else {
- return null;
}
+ return null;
}
- private UriPermission findOrCreateUriPermissionLocked(
- String sourcePkg, String targetPkg, int targetUid, Uri uri) {
- ArrayMap<Uri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
+ private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
+ String targetPkg, int targetUid, GrantUri uri) {
+ ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris == null) {
targetUris = Maps.newArrayMap();
mGrantedUriPermissions.put(targetUid, targetUris);
@@ -5944,21 +6118,40 @@
return perm;
}
- private final boolean checkUriPermissionLocked(
- Uri uri, int uid, int modeFlags, int minStrength) {
+ private final boolean checkUriPermissionLocked(Uri uri, int uid, final int modeFlags) {
+ final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
+ final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
+ : UriPermission.STRENGTH_OWNED;
+
// Root gets to do everything.
if (uid == 0) {
return true;
}
- ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
if (perms == null) return false;
- UriPermission perm = perms.get(uri);
- if (perm == null) return false;
- return perm.getStrength(modeFlags) >= minStrength;
+
+ // First look for exact match
+ final UriPermission exactPerm = perms.get(new GrantUri(uri, false));
+ if (exactPerm != null && exactPerm.getStrength(modeFlags) >= minStrength) {
+ return true;
+ }
+
+ // No exact match, look for prefixes
+ final int N = perms.size();
+ for (int i = 0; i < N; i++) {
+ final UriPermission perm = perms.valueAt(i);
+ if (perm.uri.prefix && uri.isPathPrefixMatch(perm.uri.uri)
+ && perm.getStrength(modeFlags) >= minStrength) {
+ return true;
+ }
+ }
+
+ return false;
}
@Override
- public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+ public int checkUriPermission(Uri uri, int pid, int uid, final int modeFlags) {
enforceNotIsolatedCaller("checkUriPermission");
// Another redirected-binder-call permissions check as in
@@ -5973,8 +6166,8 @@
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
- synchronized(this) {
- return checkUriPermissionLocked(uri, uid, modeFlags, UriPermission.STRENGTH_OWNED)
+ synchronized (this) {
+ return checkUriPermissionLocked(uri, uid, modeFlags)
? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED;
}
@@ -5990,11 +6183,8 @@
* lastTargetUid else set that to -1.
*/
int checkGrantUriPermissionLocked(int callingUid, String targetPkg,
- Uri uri, int modeFlags, int lastTargetUid) {
- final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
- modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- if (modeFlags == 0) {
+ Uri uri, final int modeFlags, int lastTargetUid) {
+ if (!Intent.isAccessUriMode(modeFlags)) {
return -1;
}
@@ -6089,9 +6279,7 @@
if (callingUid != Process.myUid()) {
if (!checkHoldingPermissionsLocked(pm, pi, uri, callingUid, modeFlags)) {
// Require they hold a strong enough Uri permission
- final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
- : UriPermission.STRENGTH_OWNED;
- if (!checkUriPermissionLocked(uri, callingUid, modeFlags, minStrength)) {
+ if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
throw new SecurityException("Uid " + callingUid
+ " does not have permission to uri " + uri);
}
@@ -6103,19 +6291,16 @@
@Override
public int checkGrantUriPermission(int callingUid, String targetPkg,
- Uri uri, int modeFlags) {
+ Uri uri, final int modeFlags) {
enforceNotIsolatedCaller("checkGrantUriPermission");
synchronized(this) {
return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags, -1);
}
}
- void grantUriPermissionUncheckedLocked(
- int targetUid, String targetPkg, Uri uri, int modeFlags, UriPermissionOwner owner) {
- final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
- modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- if (modeFlags == 0) {
+ void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, Uri uri,
+ final int modeFlags, UriPermissionOwner owner) {
+ if (!Intent.isAccessUriMode(modeFlags)) {
return;
}
@@ -6133,13 +6318,14 @@
return;
}
+ final boolean prefix = (modeFlags & Intent.FLAG_GRANT_PREFIX_URI_PERMISSION) != 0;
final UriPermission perm = findOrCreateUriPermissionLocked(
- pi.packageName, targetPkg, targetUid, uri);
- perm.grantModes(modeFlags, persistable, owner);
+ pi.packageName, targetPkg, targetUid, new GrantUri(uri, prefix));
+ perm.grantModes(modeFlags, owner);
}
void grantUriPermissionLocked(int callingUid, String targetPkg, Uri uri,
- int modeFlags, UriPermissionOwner owner) {
+ final int modeFlags, UriPermissionOwner owner) {
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
}
@@ -6253,7 +6439,7 @@
@Override
public void grantUriPermission(IApplicationThread caller, String targetPkg,
- Uri uri, int modeFlags) {
+ Uri uri, final int modeFlags) {
enforceNotIsolatedCaller("grantUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
@@ -6269,32 +6455,32 @@
throw new IllegalArgumentException("null uri");
}
- // Persistable only supported through Intents
- Preconditions.checkFlagsArgument(modeFlags,
- Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ Preconditions.checkFlagsArgument(modeFlags, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
- grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags,
- null);
+ grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags, null);
}
}
void removeUriPermissionIfNeededLocked(UriPermission perm) {
- if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
- |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
- ArrayMap<Uri, UriPermission> perms
- = mGrantedUriPermissions.get(perm.targetUid);
+ if (perm.modeFlags == 0) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
+ perm.targetUid);
if (perms != null) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Removing " + perm.targetUid + " permission to " + perm.uri);
+
perms.remove(perm.uri);
- if (perms.size() == 0) {
+ if (perms.isEmpty()) {
mGrantedUriPermissions.remove(perm.targetUid);
}
}
}
}
- private void revokeUriPermissionLocked(int callingUid, Uri uri, int modeFlags) {
+ private void revokeUriPermissionLocked(int callingUid, Uri uri, final int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + uri);
final IPackageManager pm = AppGlobals.getPackageManager();
@@ -6318,46 +6504,29 @@
boolean persistChanged = false;
// Go through all of the permissions and remove any that match.
- final List<String> SEGMENTS = uri.getPathSegments();
- if (SEGMENTS != null) {
- final int NS = SEGMENTS.size();
- int N = mGrantedUriPermissions.size();
- for (int i=0; i<N; i++) {
- ArrayMap<Uri, UriPermission> perms
- = mGrantedUriPermissions.valueAt(i);
- Iterator<UriPermission> it = perms.values().iterator();
- toploop:
- while (it.hasNext()) {
- UriPermission perm = it.next();
- Uri targetUri = perm.uri;
- if (!authority.equals(targetUri.getAuthority())) {
- continue;
- }
- List<String> targetSegments = targetUri.getPathSegments();
- if (targetSegments == null) {
- continue;
- }
- if (targetSegments.size() < NS) {
- continue;
- }
- for (int j=0; j<NS; j++) {
- if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
- continue toploop;
- }
- }
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
- "Revoking " + perm.targetUid + " permission to " + perm.uri);
- persistChanged |= perm.clearModes(modeFlags, true);
+ int N = mGrantedUriPermissions.size();
+ for (int i = 0; i < N; i++) {
+ final int targetUid = mGrantedUriPermissions.keyAt(i);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+
+ for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
+ final UriPermission perm = it.next();
+ if (perm.uri.uri.isPathPrefixMatch(uri)) {
+ if (DEBUG_URI_PERMISSION)
+ Slog.v(TAG,
+ "Revoking " + perm.targetUid + " permission to " + perm.uri);
+ persistChanged |= perm.revokeModes(
+ modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
if (perm.modeFlags == 0) {
it.remove();
}
}
- if (perms.size() == 0) {
- mGrantedUriPermissions.remove(
- mGrantedUriPermissions.keyAt(i));
- N--;
- i--;
- }
+ }
+
+ if (perms.isEmpty()) {
+ mGrantedUriPermissions.remove(targetUid);
+ N--;
+ i--;
}
}
@@ -6368,7 +6537,7 @@
@Override
public void revokeUriPermission(IApplicationThread caller, Uri uri,
- int modeFlags) {
+ final int modeFlags) {
enforceNotIsolatedCaller("revokeUriPermission");
synchronized(this) {
final ProcessRecord r = getRecordForAppLocked(caller);
@@ -6382,9 +6551,7 @@
return;
}
- modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
- | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- if (modeFlags == 0) {
+ if (!Intent.isAccessUriMode(modeFlags)) {
return;
}
@@ -6419,20 +6586,22 @@
boolean persistChanged = false;
- final int size = mGrantedUriPermissions.size();
- for (int i = 0; i < size; i++) {
+ int N = mGrantedUriPermissions.size();
+ for (int i = 0; i < N; i++) {
+ final int targetUid = mGrantedUriPermissions.keyAt(i);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+
// Only inspect grants matching user
if (userHandle == UserHandle.USER_ALL
- || userHandle == UserHandle.getUserId(mGrantedUriPermissions.keyAt(i))) {
- final Iterator<UriPermission> it = mGrantedUriPermissions.valueAt(i)
- .values().iterator();
- while (it.hasNext()) {
+ || userHandle == UserHandle.getUserId(targetUid)) {
+ for (Iterator<UriPermission> it = perms.values().iterator(); it.hasNext();) {
final UriPermission perm = it.next();
// Only inspect grants matching package
if (packageName == null || perm.sourcePkg.equals(packageName)
|| perm.targetPkg.equals(packageName)) {
- persistChanged |= perm.clearModes(~0, persistable);
+ persistChanged |= perm.revokeModes(
+ persistable ? ~0 : ~Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
// Only remove when no modes remain; any persisted grants
// will keep this alive.
@@ -6441,6 +6610,12 @@
}
}
}
+
+ if (perms.isEmpty()) {
+ mGrantedUriPermissions.remove(targetUid);
+ N--;
+ i--;
+ }
}
}
@@ -6460,7 +6635,7 @@
@Override
public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
- Uri uri, int modeFlags) {
+ Uri uri, final int modeFlags) {
synchronized(this) {
UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
if (owner == null) {
@@ -6514,8 +6689,9 @@
ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
synchronized (this) {
final int size = mGrantedUriPermissions.size();
- for (int i = 0 ; i < size; i++) {
- for (UriPermission perm : mGrantedUriPermissions.valueAt(i).values()) {
+ for (int i = 0; i < size; i++) {
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
+ for (UriPermission perm : perms.values()) {
if (perm.persistedModeFlags != 0) {
persist.add(perm.snapshot());
}
@@ -6536,7 +6712,8 @@
writeIntAttribute(out, ATTR_USER_HANDLE, perm.userHandle);
out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
- out.attribute(null, ATTR_URI, String.valueOf(perm.uri));
+ out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri));
+ writeBooleanAttribute(out, ATTR_PREFIX, perm.uri.prefix);
writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
out.endTag(null, TAG_URI_GRANT);
@@ -6572,6 +6749,7 @@
final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
+ final boolean prefix = readBooleanAttribute(in, ATTR_PREFIX);
final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
@@ -6587,7 +6765,7 @@
}
if (targetUid != -1) {
final UriPermission perm = findOrCreateUriPermissionLocked(
- sourcePkg, targetPkg, targetUid, uri);
+ sourcePkg, targetPkg, targetUid, new GrantUri(uri, prefix));
perm.initPersistedModes(modeFlags, createdTime);
}
} else {
@@ -6609,7 +6787,7 @@
}
@Override
- public void takePersistableUriPermission(Uri uri, int modeFlags) {
+ public void takePersistableUriPermission(Uri uri, final int modeFlags) {
enforceNotIsolatedCaller("takePersistableUriPermission");
Preconditions.checkFlagsArgument(modeFlags,
@@ -6617,13 +6795,28 @@
synchronized (this) {
final int callingUid = Binder.getCallingUid();
- final UriPermission perm = findUriPermissionLocked(callingUid, uri);
- if (perm == null) {
- throw new SecurityException("No permission grant found for UID " + callingUid
- + " and Uri " + uri.toSafeString());
+ boolean persistChanged = false;
+
+ UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false));
+ UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true));
+
+ final boolean exactValid = (exactPerm != null)
+ && ((modeFlags & exactPerm.persistableModeFlags) == modeFlags);
+ final boolean prefixValid = (prefixPerm != null)
+ && ((modeFlags & prefixPerm.persistableModeFlags) == modeFlags);
+
+ if (!(exactValid || prefixValid)) {
+ throw new SecurityException("No persistable permission grants found for UID "
+ + callingUid + " and Uri " + uri.toSafeString());
}
- boolean persistChanged = perm.takePersistableModes(modeFlags);
+ if (exactValid) {
+ persistChanged |= exactPerm.takePersistableModes(modeFlags);
+ }
+ if (prefixValid) {
+ persistChanged |= prefixPerm.takePersistableModes(modeFlags);
+ }
+
persistChanged |= maybePrunePersistedUriGrantsLocked(callingUid);
if (persistChanged) {
@@ -6633,7 +6826,7 @@
}
@Override
- public void releasePersistableUriPermission(Uri uri, int modeFlags) {
+ public void releasePersistableUriPermission(Uri uri, final int modeFlags) {
enforceNotIsolatedCaller("releasePersistableUriPermission");
Preconditions.checkFlagsArgument(modeFlags,
@@ -6641,16 +6834,24 @@
synchronized (this) {
final int callingUid = Binder.getCallingUid();
+ boolean persistChanged = false;
- final UriPermission perm = findUriPermissionLocked(callingUid, uri);
- if (perm == null) {
- Slog.w(TAG, "No permission grant found for UID " + callingUid + " and Uri "
- + uri.toSafeString());
- return;
+ UriPermission exactPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, false));
+ UriPermission prefixPerm = findUriPermissionLocked(callingUid, new GrantUri(uri, true));
+ if (exactPerm == null && prefixPerm == null) {
+ throw new SecurityException("No permission grants found for UID " + callingUid
+ + " and Uri " + uri.toSafeString());
}
- final boolean persistChanged = perm.releasePersistableModes(modeFlags);
- removeUriPermissionIfNeededLocked(perm);
+ if (exactPerm != null) {
+ persistChanged |= exactPerm.releasePersistableModes(modeFlags);
+ removeUriPermissionIfNeededLocked(exactPerm);
+ }
+ if (prefixPerm != null) {
+ persistChanged |= prefixPerm.releasePersistableModes(modeFlags);
+ removeUriPermissionIfNeededLocked(prefixPerm);
+ }
+
if (persistChanged) {
schedulePersistUriGrants();
}
@@ -6664,7 +6865,7 @@
* @return if any mutations occured that require persisting.
*/
private boolean maybePrunePersistedUriGrantsLocked(int uid) {
- final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
if (perms == null) return false;
if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
@@ -6714,13 +6915,12 @@
final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
synchronized (this) {
if (incoming) {
- final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
+ callingUid);
if (perms == null) {
Slog.w(TAG, "No permission grants found for " + packageName);
} else {
- final int size = perms.size();
- for (int i = 0; i < size; i++) {
- final UriPermission perm = perms.valueAt(i);
+ for (UriPermission perm : perms.values()) {
if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
result.add(perm.buildPersistedPublicApiObject());
}
@@ -6729,10 +6929,9 @@
} else {
final int size = mGrantedUriPermissions.size();
for (int i = 0; i < size; i++) {
- final ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
- final int permsSize = perms.size();
- for (int j = 0; j < permsSize; j++) {
- final UriPermission perm = perms.valueAt(j);
+ final ArrayMap<GrantUri, UriPermission> perms =
+ mGrantedUriPermissions.valueAt(i);
+ for (UriPermission perm : perms.values()) {
if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
result.add(perm.buildPersistedPublicApiObject());
}
@@ -7084,6 +7283,24 @@
}
}
+ /**
+ * Removes the task with the specified task id.
+ *
+ * @param taskId Identifier of the task to be removed.
+ * @param flags Additional operational flags. May be 0 or
+ * {@link ActivityManager#REMOVE_TASK_KILL_PROCESS}.
+ * @return Returns true if the given task was found and removed.
+ */
+ private boolean removeTaskByIdLocked(int taskId, int flags) {
+ TaskRecord tr = recentTaskForIdLocked(taskId);
+ if (tr != null) {
+ tr.removeTaskActivitiesLocked(-1, false);
+ cleanUpRemovedTaskLocked(tr, flags);
+ return true;
+ }
+ return false;
+ }
+
@Override
public boolean removeTask(int taskId, int flags) {
synchronized (this) {
@@ -7091,29 +7308,11 @@
"removeTask()");
long ident = Binder.clearCallingIdentity();
try {
- TaskRecord tr = recentTaskForIdLocked(taskId);
- if (tr != null) {
- ActivityRecord r = tr.removeTaskActivitiesLocked(-1, false);
- if (r != null) {
- cleanUpRemovedTaskLocked(tr, flags);
- return true;
- }
- if (tr.mActivities.size() == 0) {
- // Caller is just removing a recent task that is
- // not actively running. That is easy!
- cleanUpRemovedTaskLocked(tr, flags);
- return true;
- }
- Slog.w(TAG, "removeTask: task " + taskId
- + " does not have activities to remove, "
- + " but numActivities=" + tr.numActivities
- + ": " + tr);
- }
+ return removeTaskByIdLocked(taskId, flags);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- return false;
}
/**
@@ -7240,6 +7439,9 @@
if (r == null) {
return null;
}
+ if (callback == null) {
+ throw new IllegalArgumentException("callback must not be null");
+ }
return mStackSupervisor.createActivityContainer(r, callback);
}
}
@@ -7599,11 +7801,11 @@
}
}
}
-
- ArrayMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
+
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
if (perms != null) {
- for (Map.Entry<Uri, UriPermission> uri : perms.entrySet()) {
- if (uri.getKey().getAuthority().equals(cpi.authority)) {
+ for (GrantUri uri : perms.keySet()) {
+ if (uri.uri.getAuthority().equals(cpi.authority)) {
return null;
}
}
@@ -8429,11 +8631,27 @@
return mSleeping || mShuttingDown;
}
+ public boolean isSleeping() {
+ return mSleeping;
+ }
+
void goingToSleep() {
synchronized(this) {
mWentToSleep = true;
updateEventDispatchingLocked();
+ goToSleepIfNeededLocked();
+ }
+ }
+ void finishRunningVoiceLocked() {
+ if (mRunningVoice) {
+ mRunningVoice = false;
+ goToSleepIfNeededLocked();
+ }
+ }
+
+ void goToSleepIfNeededLocked() {
+ if (mWentToSleep && !mRunningVoice) {
if (!mSleeping) {
mSleeping = true;
mStackSupervisor.goingToSleepLocked();
@@ -8496,7 +8714,7 @@
}
private void comeOutOfSleepIfNeededLocked() {
- if (!mWentToSleep && !mLockScreenShown) {
+ if ((!mWentToSleep && !mLockScreenShown) || mRunningVoice) {
if (mSleeping) {
mSleeping = false;
mStackSupervisor.comeOutOfSleepIfNeededLocked();
@@ -8512,6 +8730,13 @@
}
}
+ void startRunningVoiceLocked() {
+ if (!mRunningVoice) {
+ mRunningVoice = true;
+ comeOutOfSleepIfNeededLocked();
+ }
+ }
+
private void updateEventDispatchingLocked() {
mWindowManager.setEventDispatching(mBooted && !mWentToSleep && !mShuttingDown);
}
@@ -9218,7 +9443,7 @@
proc.notCachedSinceIdle = true;
proc.initialIdlePss = 0;
proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true,
- mSleeping, now);
+ isSleeping(), now);
}
}
@@ -9517,6 +9742,8 @@
if (goingCallback != null) goingCallback.run();
+ mSystemServiceManager.startUser(mCurrentUserId);
+
synchronized (this) {
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
try {
@@ -9573,6 +9800,8 @@
}, 0, null, null,
android.Manifest.permission.INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ } catch (Throwable t) {
+ Slog.wtf(TAG, "Failed sending first user broadcasts", t);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -11072,8 +11301,8 @@
pw.println(" mSleeping=" + mSleeping + " mWentToSleep=" + mWentToSleep
+ " mLockScreenShown " + mLockScreenShown);
}
- if (mShuttingDown) {
- pw.println(" mShuttingDown=" + mShuttingDown);
+ if (mShuttingDown || mRunningVoice) {
+ pw.print(" mShuttingDown=" + mShuttingDown + " mRunningVoice=" + mRunningVoice);
}
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
@@ -11570,8 +11799,7 @@
if (dumpUid >= -1 && UserHandle.getAppId(uid) != dumpUid) {
continue;
}
- ArrayMap<Uri, UriPermission> perms
- = mGrantedUriPermissions.valueAt(i);
+ final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
if (!printed) {
if (needSep) pw.println();
needSep = true;
@@ -11579,8 +11807,7 @@
printed = true;
printedAnything = true;
}
- pw.print(" * UID "); pw.print(uid);
- pw.println(" holds:");
+ pw.print(" * UID "); pw.print(uid); pw.println(" holds:");
for (UriPermission perm : perms.values()) {
pw.print(" "); pw.println(perm);
if (dumpAll) {
@@ -15195,7 +15422,7 @@
if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
app.pssProcState = app.setProcState;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
- mSleeping, now);
+ isSleeping(), now);
mPendingPssProcesses.add(app);
}
}
@@ -15232,7 +15459,7 @@
}
}
return !processingBroadcasts
- && (mSleeping || mStackSupervisor.allResumedActivitiesIdle());
+ && (isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
}
/**
@@ -15507,7 +15734,7 @@
app.setProcState)) {
app.lastStateTime = now;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
- mSleeping, now);
+ isSleeping(), now);
if (DEBUG_PSS) Slog.d(TAG, "Process state change from "
+ ProcessList.makeProcStateString(app.setProcState) + " to "
+ ProcessList.makeProcStateString(app.curProcState) + " next pss in "
@@ -15517,7 +15744,7 @@
&& now > (app.lastStateTime+ProcessList.PSS_MIN_TIME_FROM_STATE_CHANGE))) {
requestPssLocked(app, app.setProcState);
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
- mSleeping, now);
+ isSleeping(), now);
} else if (false && DEBUG_PSS) {
Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
}
@@ -15854,7 +16081,7 @@
}
mLastMemoryLevel = memFactor;
mLastNumProcesses = mLruProcesses.size();
- boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !mSleeping, now);
+ boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleeping(), now);
final int trackerMemFactor = mProcessStats.getMemFactorLocked();
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
@@ -16291,7 +16518,8 @@
* background.
*/
private void updateCurrentProfileIdsLocked() {
- final List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+ final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+ mCurrentUserId, false /* enabledOnly */);
int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
for (int i = 0; i < currentProfileIds.length; i++) {
currentProfileIds[i] = profiles.get(i).id;
@@ -16301,7 +16529,8 @@
private Set getProfileIdsLocked(int userId) {
Set userIds = new HashSet<Integer>();
- final List<UserInfo> profiles = getUserManagerLocked().getProfiles(userId);
+ final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+ userId, false /* enabledOnly */);
for (UserInfo user : profiles) {
userIds.add(Integer.valueOf(user.id));
}
@@ -16395,7 +16624,15 @@
needStart = true;
}
+ if (uss.mState == UserStartedState.STATE_BOOTING) {
+ // Booting up a new user, need to tell system services about it.
+ // Note that this is on the same handler as scheduling of broadcasts,
+ // which is important because it needs to go first.
+ mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId));
+ }
+
if (foreground) {
+ mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId));
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
@@ -16600,7 +16837,8 @@
void startProfilesLocked() {
if (DEBUG_MU) Slog.i(TAG_MU, "startProfilesLocked");
- List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+ List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+ mCurrentUserId, false /* enabledOnly */);
List<UserInfo> toStart = new ArrayList<UserInfo>(profiles.size());
for (UserInfo user : profiles) {
if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
@@ -16749,6 +16987,7 @@
}
uss.mState = UserStartedState.STATE_SHUTDOWN;
}
+ mSystemServiceManager.stopUser(userId);
broadcastIntentLocked(null, null, shutdownIntent,
null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
true, false, MY_PID, Process.SYSTEM_UID, userId);
@@ -16798,7 +17037,12 @@
}
}
- mStackSupervisor.removeUserLocked(userId);
+ if (stopped) {
+ mSystemServiceManager.cleanupUser(userId);
+ synchronized (this) {
+ mStackSupervisor.removeUserLocked(userId);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d596472..7a44473 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -139,7 +139,7 @@
boolean forceNewConfig; // force re-create with new config next time
int launchCount; // count of launches since last state
long lastLaunchTime; // time of last lauch of this activity
- ArrayList<ActivityStack> mChildContainers = new ArrayList<ActivityStack>();
+ ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>();
String stringName; // for caching of toString().
@@ -215,14 +215,7 @@
pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions);
}
if (uriPermissions != null) {
- if (uriPermissions.readUriPermissions != null) {
- pw.print(prefix); pw.print("readUriPermissions=");
- pw.println(uriPermissions.readUriPermissions);
- }
- if (uriPermissions.writeUriPermissions != null) {
- pw.print(prefix); pw.print("writeUriPermissions=");
- pw.println(uriPermissions.writeUriPermissions);
- }
+ uriPermissions.dump(pw, prefix);
}
pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed);
pw.print(" launchCount="); pw.print(launchCount);
@@ -640,7 +633,7 @@
// case we will deliver it if this is the current top activity on its
// stack.
boolean unsent = true;
- if ((state == ActivityState.RESUMED || (service.mSleeping
+ if ((state == ActivityState.RESUMED || (service.isSleeping()
&& task.stack.topRunningActivityLocked(null) == this))
&& app != null && app.thread != null) {
try {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8dd4317..bea926f 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -36,6 +36,10 @@
import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE;
+
+import android.service.voice.IVoiceInteractionSession;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
@@ -499,6 +503,11 @@
if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
+ if (task.voiceSession != null) {
+ // We never match voice sessions; those always run independently.
+ if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": voice session");
+ continue;
+ }
if (task.userId != userId) {
// Looking for a different task.
if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": different user");
@@ -733,7 +742,9 @@
int w = mThumbnailWidth;
int h = mThumbnailHeight;
if (w < 0) {
- if (SystemProperties.getBoolean("persist.recents.use_alternate", false)) {
+ Configuration config = res.getConfiguration();
+ boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
+ if (useAlternateRecents) {
mThumbnailWidth = w =
res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
mThumbnailHeight = h =
@@ -791,7 +802,7 @@
prev.task.touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
- if (next == null || next.task != prev.task) {
+ if (next == null || next.noDisplay || next.task != prev.task) {
prev.updateThumbnail(screenshotActivities(prev), null);
}
stopFullyDrawnTraceIfNeeded();
@@ -1066,9 +1077,9 @@
private void setVisibile(ActivityRecord r, boolean visible) {
r.visible = visible;
mWindowManager.setAppVisibility(r.appToken, visible);
- final ArrayList<ActivityStack> containers = r.mChildContainers;
+ final ArrayList<ActivityContainer> containers = r.mChildContainers;
for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
- ActivityContainer container = containers.get(containerNdx).mActivityContainer;
+ ActivityContainer container = containers.get(containerNdx);
container.setVisible(visible);
}
}
@@ -1270,6 +1281,7 @@
* occurred and the activity will be notified immediately.
*/
void notifyActivityDrawnLocked(ActivityRecord r) {
+ mActivityContainer.setDrawn();
if ((r == null)
|| (mUndrawnActivitiesBelowTopTranslucent.remove(r) &&
mUndrawnActivitiesBelowTopTranslucent.isEmpty())) {
@@ -1336,7 +1348,8 @@
if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
ActivityRecord parent = mActivityContainer.mParentActivity;
- if (parent != null && parent.state != ActivityState.RESUMED) {
+ if ((parent != null && parent.state != ActivityState.RESUMED) ||
+ !mActivityContainer.isAttached()) {
// Do not resume this stack if its parent is not resumed.
// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false;
@@ -1497,7 +1510,7 @@
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
- if (mService.mSleeping && mLastNoHistoryActivity != null &&
+ if (mService.isSleeping() && mLastNoHistoryActivity != null &&
!mLastNoHistoryActivity.finishing) {
if (DEBUG_STATES) Slog.d(TAG, "no-history finish of " + mLastNoHistoryActivity +
" on new resume");
@@ -2028,7 +2041,7 @@
+ " out to bottom task " + bottom.task);
} else {
targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
- null, false);
+ null, null, null, false);
newThumbHolder = targetTask;
targetTask.affinityIntent = target.intent;
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
@@ -2325,7 +2338,7 @@
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
- if (!mService.mSleeping) {
+ if (!mService.isSleeping()) {
if (DEBUG_STATES) {
Slog.d(TAG, "no-history finish of " + r);
}
@@ -2624,6 +2637,20 @@
return r;
}
+ void finishAllActivitiesLocked() {
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+ for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ActivityRecord r = activities.get(activityNdx);
+ if (r.finishing) {
+ continue;
+ }
+ Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r);
+ finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
+ }
+ }
+ }
+
final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode,
Intent resultData) {
final ActivityRecord srec = ActivityRecord.forToken(token);
@@ -2690,7 +2717,7 @@
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
destIntent.getComponent(), 0, srec.userId);
int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent,
- null, aInfo, parent.appToken, null,
+ null, aInfo, null, null, parent.appToken, null,
0, -1, parent.launchedFromUid, parent.launchedFromPackage,
0, null, true, null, null);
foundParentInTask = res == ActivityManager.START_SUCCESS;
@@ -2719,9 +2746,7 @@
if (mPausingActivity == r) {
mPausingActivity = null;
}
- if (mService.mFocusedActivity == r) {
- mService.mFocusedActivity = null;
- }
+ mService.clearFocusedActivity(r);
r.configDestroy = false;
r.frozenBeforeDestroy = false;
@@ -2862,7 +2887,6 @@
}
if (activityRemoved) {
mStackSupervisor.resumeTopActivitiesLocked();
-
}
}
@@ -3704,6 +3728,11 @@
mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
}
mTaskHistory.remove(task);
+ if (task.voiceInteractor != null) {
+ // This task was a voice interaction, so it should not remain on the
+ // recent tasks list.
+ mService.mRecentTasks.remove(task);
+ }
if (mTaskHistory.isEmpty()) {
if (DEBUG_STACK) Slog.i(TAG, "removeTask: moving to back stack=" + this);
@@ -3717,8 +3746,10 @@
}
}
- TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, boolean toTop) {
- TaskRecord task = new TaskRecord(taskId, info, intent);
+ TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ boolean toTop) {
+ TaskRecord task = new TaskRecord(taskId, info, intent, voiceSession, voiceInteractor);
addTask(task, toTop);
return task;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 63f9d09..3770a07 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import static android.Manifest.permission.START_ANY_ACTIVITY;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -77,6 +76,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -87,6 +87,7 @@
import android.view.InputEvent;
import android.view.Surface;
import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.TransferPipe;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
@@ -96,7 +97,6 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -225,11 +225,11 @@
// TODO: Add listener for removal of references.
/** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
- SparseArray<WeakReference<ActivityContainer>> mActivityContainers =
- new SparseArray<WeakReference<ActivityContainer>>();
+ SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
/** Mapping from displayId to display current state */
- private SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<ActivityDisplay>();
+ private final SparseArray<ActivityDisplay> mActivityDisplays =
+ new SparseArray<ActivityDisplay>();
InputManagerInternal mInputManagerInternal;
@@ -265,7 +265,7 @@
mActivityDisplays.put(displayId, activityDisplay);
}
- createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY);
+ createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY);
mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
@@ -688,13 +688,14 @@
void startHomeActivity(Intent intent, ActivityInfo aInfo) {
moveHomeToTop();
- startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0,
+ startActivityLocked(null, intent, null, aInfo, null, null, null, null, 0, 0, 0, null, 0,
null, false, null, null);
}
final int startActivityMayWait(IApplicationThread caller, int callingUid,
- String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
- String resultWho, int requestCode, int startFlags, String profileFile,
+ String callingPackage, Intent intent, String resolvedType,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile,
ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
Bundle options, int userId, IActivityContainer iContainer) {
// Refuse possible leaked file descriptors
@@ -803,7 +804,8 @@
}
}
- int res = startActivityLocked(caller, intent, resolvedType, aInfo, resultTo, resultWho,
+ int res = startActivityLocked(caller, intent, resolvedType, aInfo,
+ voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage, startFlags, options,
componentSpecified, null, container);
@@ -919,7 +921,7 @@
theseOptions = null;
}
int res = startActivityLocked(caller, intent, resolvedTypes[i],
- aInfo, resultTo, null, -1, callingPid, callingUid, callingPackage,
+ aInfo, null, null, resultTo, null, -1, callingPid, callingUid, callingPackage,
0, theseOptions, componentSpecified, outActivity, null);
if (res < 0) {
return res;
@@ -1035,8 +1037,8 @@
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
new Configuration(mService.mConfiguration), r.compat,
- app.repProcState, r.icicle, results, newIntents, !andResume,
- mService.isNextTransitionForward(), profileFile, profileFd,
+ r.task.voiceInteractor, app.repProcState, r.icicle, results, newIntents,
+ !andResume, mService.isNextTransitionForward(), profileFile, profileFd,
profileAutoStop, options);
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
@@ -1144,8 +1146,9 @@
}
final int startActivityLocked(IApplicationThread caller,
- Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
- String resultWho, int requestCode,
+ Intent intent, String resolvedType, ActivityInfo aInfo,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ IBinder resultTo, String resultWho, int requestCode,
int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container) {
int err = ActivityManager.START_SUCCESS;
@@ -1188,7 +1191,7 @@
}
ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
- int launchFlags = intent.getFlags();
+ final int launchFlags = intent.getFlags();
if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
&& sourceRecord != null) {
@@ -1233,6 +1236,38 @@
err = ActivityManager.START_CLASS_NOT_FOUND;
}
+ if (err == ActivityManager.START_SUCCESS && sourceRecord != null
+ && sourceRecord.task.voiceSession != null) {
+ // If this activity is being launched as part of a voice session, we need
+ // to ensure that it is safe to do so. If the upcoming activity will also
+ // be part of the voice session, we can only launch it if it has explicitly
+ // said it supports the VOICE category, or it is a part of the calling app.
+ if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
+ && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
+ try {
+ if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
+ intent, resolvedType)) {
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ } catch (RemoteException e) {
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ }
+ }
+
+ if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
+ // If the caller is starting a new voice session, just make sure the target
+ // is actually allowing it to run this way.
+ try {
+ if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
+ intent, resolvedType)) {
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ } catch (RemoteException e) {
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ }
+
if (err != ActivityManager.START_SUCCESS) {
if (resultRecord != null) {
resultStack.sendActivityResultLocked(-1,
@@ -1306,8 +1341,8 @@
}
final ActivityStack stack = getFocusedStack();
- if (stack.mResumedActivity == null
- || stack.mResumedActivity.info.applicationInfo.uid != callingUid) {
+ if (voiceSession == null && (stack.mResumedActivity == null
+ || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
PendingActivityLaunch pal =
new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
@@ -1331,7 +1366,8 @@
mService.doPendingActivityLaunchesLocked(false);
- err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);
+ err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
+ startFlags, true, options);
if (allPausedActivitiesComplete()) {
// If someone asked to have the keyguard dismissed on the next
@@ -1386,7 +1422,7 @@
}
// Need to create an app stack for this user.
- int stackId = createStackOnDisplay(null, getNextStackId(), Display.DEFAULT_DISPLAY);
+ int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
" stackId=" + stackId);
mFocusedStack = getStack(stackId);
@@ -1411,8 +1447,9 @@
}
final int startActivityUncheckedLocked(ActivityRecord r,
- ActivityRecord sourceRecord, int startFlags, boolean doResume,
- Bundle options) {
+ ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
+ boolean doResume, Bundle options) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
@@ -1756,7 +1793,7 @@
r.setTask(targetStack.createTaskRecord(getNextTaskId(),
newTaskInfo != null ? newTaskInfo : r.info,
newTaskIntent != null ? newTaskIntent : intent,
- true), null, true);
+ voiceSession, voiceInteractor, true), null, true);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
r.task);
} else {
@@ -1834,7 +1871,7 @@
targetStack.moveToFront();
ActivityRecord prev = targetStack.topActivity();
r.setTask(prev != null ? prev.task
- : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
+ : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, null, null, true),
null, true);
mWindowManager.moveTaskToTop(r.task.taskId);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
@@ -2154,14 +2191,9 @@
}
ActivityStack getStack(int stackId) {
- WeakReference<ActivityContainer> weakReference = mActivityContainers.get(stackId);
- if (weakReference != null) {
- ActivityContainer activityContainer = weakReference.get();
- if (activityContainer != null) {
- return activityContainer.mStack;
- } else {
- mActivityContainers.remove(stackId);
- }
+ ActivityContainer activityContainer = mActivityContainers.get(stackId);
+ if (activityContainer != null) {
+ return activityContainer.mStack;
}
return null;
}
@@ -2191,49 +2223,26 @@
return null;
}
- ActivityContainer createActivityContainer(ActivityRecord parentActivity, int stackId,
+ ActivityContainer createActivityContainer(ActivityRecord parentActivity,
IActivityContainerCallback callback) {
- ActivityContainer activityContainer = new ActivityContainer(parentActivity, stackId,
- callback);
- mActivityContainers.put(stackId, new WeakReference<ActivityContainer>(activityContainer));
- if (parentActivity != null) {
- parentActivity.mChildContainers.add(activityContainer.mStack);
- }
+ ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback);
+ mActivityContainers.put(activityContainer.mStackId, activityContainer);
+ parentActivity.mChildContainers.add(activityContainer);
return activityContainer;
}
- ActivityContainer createActivityContainer(ActivityRecord parentActivity,
- IActivityContainerCallback callback) {
- return createActivityContainer(parentActivity, getNextStackId(), callback);
- }
-
void removeChildActivityContainers(ActivityRecord parentActivity) {
- for (int ndx = mActivityContainers.size() - 1; ndx >= 0; --ndx) {
- final ActivityContainer container = mActivityContainers.valueAt(ndx).get();
- if (container == null) {
- mActivityContainers.removeAt(ndx);
- continue;
- }
- if (container.mParentActivity != parentActivity) {
- continue;
- }
-
- ActivityStack stack = container.mStack;
- ActivityRecord top = stack.topRunningNonDelayedActivityLocked(null);
- if (top != null) {
- // TODO: Make sure the next activity doesn't start up when top is destroyed.
- stack.destroyActivityLocked(top, true, true, "stack parent destroyed");
- }
- mActivityContainers.removeAt(ndx);
- container.detachLocked();
+ final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers;
+ for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) {
+ ActivityContainer container = childStacks.remove(containerNdx);
+ container.release();
}
}
void deleteActivityContainer(IActivityContainer container) {
ActivityContainer activityContainer = (ActivityContainer)container;
if (activityContainer != null) {
- activityContainer.mStack.destroyActivitiesLocked(null, true,
- "deleteActivityContainer");
+ activityContainer.mStack.finishAllActivitiesLocked();
final ActivityRecord parent = activityContainer.mParentActivity;
if (parent != null) {
parent.mChildContainers.remove(activityContainer);
@@ -2244,14 +2253,14 @@
}
}
- private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) {
+ private int createStackOnDisplay(int stackId, int displayId) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay == null) {
return -1;
}
- ActivityContainer activityContainer =
- createActivityContainer(parentActivity, stackId, null);
+ ActivityContainer activityContainer = new ActivityContainer(stackId);
+ mActivityContainers.put(stackId, activityContainer);
activityContainer.attachToDisplayLocked(activityDisplay);
return stackId;
}
@@ -2334,9 +2343,9 @@
}
boolean shutdownLocked(int timeout) {
- boolean timedout = false;
goingToSleepLocked();
+ boolean timedout = false;
final long endTime = System.currentTimeMillis() + timeout;
while (true) {
boolean cantShutdown = false;
@@ -3028,26 +3037,30 @@
}
}
- class ActivityContainer extends IActivityContainer.Stub {
+ class ActivityContainer extends android.app.IActivityContainer.Stub {
+ final static int FORCE_NEW_TASK_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
final int mStackId;
- final IActivityContainerCallback mCallback;
+ IActivityContainerCallback mCallback = null;
final ActivityStack mStack;
- final ActivityRecord mParentActivity;
- final String mIdString;
+ ActivityRecord mParentActivity = null;
+ String mIdString;
boolean mVisible = true;
/** Display this ActivityStack is currently on. Null if not attached to a Display. */
ActivityDisplay mActivityDisplay;
- ActivityContainer(ActivityRecord parentActivity, int stackId,
- IActivityContainerCallback callback) {
+ final static int CONTAINER_STATE_HAS_SURFACE = 0;
+ final static int CONTAINER_STATE_NO_SURFACE = 1;
+ final static int CONTAINER_STATE_FINISHING = 2;
+ int mContainerState = CONTAINER_STATE_HAS_SURFACE;
+
+ ActivityContainer(int stackId) {
synchronized (mService) {
mStackId = stackId;
mStack = new ActivityStack(this);
- mParentActivity = parentActivity;
- mCallback = callback;
- mIdString = "ActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+ mIdString = "ActivtyContainer{" + mStackId + "}";
if (DEBUG_STACK) Slog.d(TAG, "Creating " + this);
}
}
@@ -3097,6 +3110,14 @@
}
}
+ @Override
+ public void release() {
+ mContainerState = CONTAINER_STATE_FINISHING;
+ mStack.finishAllActivitiesLocked();
+ detachLocked();
+ mWindowManager.removeStack(mStackId);
+ }
+
private void detachLocked() {
if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display="
+ mActivityDisplay + " Callers=" + Debug.getCallers(2));
@@ -3110,24 +3131,18 @@
}
@Override
- public void detachFromDisplay() {
- synchronized (mService) {
- detachLocked();
- }
- }
-
- @Override
public final int startActivity(Intent intent) {
mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
int userId = mService.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
// TODO: Switch to user app stacks here.
+ intent.addFlags(FORCE_NEW_TASK_FLAGS);
String mimeType = intent.getType();
if (mimeType == null && intent.getData() != null
&& "content".equals(intent.getData().getScheme())) {
mimeType = mService.getProviderMimeType(intent.getData(), userId);
}
- return startActivityMayWait(null, -1, null, intent, mimeType, null, null, 0, 0, null,
+ return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null, 0, 0, null,
null, null, null, null, userId, this);
}
@@ -3140,7 +3155,41 @@
}
return ((PendingIntentRecord)intentSender).sendInner(0, null, null, null, null, null,
- null, 0, 0, 0, null, this);
+ null, 0, FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
+ }
+
+ private void checkEmbeddedAllowedInner(Intent intent, String resolvedType) {
+ int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
+ if (resolvedType == null) {
+ resolvedType = intent.getType();
+ if (resolvedType == null && intent.getData() != null
+ && "content".equals(intent.getData().getScheme())) {
+ resolvedType = mService.getProviderMimeType(intent.getData(), userId);
+ }
+ }
+ ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, null, userId);
+ if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+ throw new SecurityException(
+ "Attempt to embed activity that has not set allowEmbedded=\"true\"");
+ }
+ }
+
+ /** Throw a SecurityException if allowEmbedded is not true */
+ @Override
+ public final void checkEmbeddedAllowed(Intent intent) {
+ checkEmbeddedAllowedInner(intent, null);
+ }
+
+ /** Throw a SecurityException if allowEmbedded is not true */
+ @Override
+ public final void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
+ if (!(intentSender instanceof PendingIntentRecord)) {
+ throw new IllegalArgumentException("Bad PendingIntent object");
+ }
+ PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender;
+ checkEmbeddedAllowedInner(pendingIntent.key.requestIntent,
+ pendingIntent.key.requestResolvedType);
}
@Override
@@ -3149,23 +3198,8 @@
}
@Override
- public void attachToSurface(Surface surface, int width, int height, int density) {
+ public void setSurface(Surface surface, int width, int height, int density) {
mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface");
-
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mService) {
- ActivityDisplay activityDisplay =
- new ActivityDisplay(surface, width, height, density);
- mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
- attachToDisplayLocked(activityDisplay);
- mStack.resumeTopActivityLocked(null);
- }
- if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
- + mActivityDisplay);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
}
ActivityStackSupervisor getOuter() {
@@ -3184,6 +3218,7 @@
}
}
+ // TODO: Make sure every change to ActivityRecord.visible results in a call to this.
void setVisible(boolean visible) {
if (mVisible != visible) {
mVisible = visible;
@@ -3194,52 +3229,114 @@
}
}
+ void setDrawn() {
+ }
+
@Override
public String toString() {
return mIdString + (mActivityDisplay == null ? "N" : "A");
}
}
+ private class VirtualActivityContainer extends ActivityContainer {
+ Surface mSurface;
+ boolean mDrawn = false;
+
+ VirtualActivityContainer(ActivityRecord parent, IActivityContainerCallback callback) {
+ super(getNextStackId());
+ mParentActivity = parent;
+ mCallback = callback;
+ mContainerState = CONTAINER_STATE_NO_SURFACE;
+ mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+ }
+
+ @Override
+ public void setSurface(Surface surface, int width, int height, int density) {
+ super.setSurface(surface, width, height, density);
+
+ synchronized (mService) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ setSurfaceLocked(surface, width, height, density);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
+
+ private void setSurfaceLocked(Surface surface, int width, int height, int density) {
+ if (mContainerState == CONTAINER_STATE_FINISHING) {
+ return;
+ }
+ VirtualActivityDisplay virtualActivityDisplay =
+ (VirtualActivityDisplay) mActivityDisplay;
+ if (virtualActivityDisplay == null) {
+ virtualActivityDisplay =
+ new VirtualActivityDisplay(width, height, density);
+ mActivityDisplay = virtualActivityDisplay;
+ mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay);
+ attachToDisplayLocked(virtualActivityDisplay);
+ }
+
+ if (mSurface != null) {
+ mSurface.release();
+ }
+
+ mSurface = surface;
+ if (surface != null) {
+ mStack.resumeTopActivityLocked(null);
+ } else {
+ mContainerState = CONTAINER_STATE_NO_SURFACE;
+ ((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
+// if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
+// mStack.startPausingLocked(false, true);
+// }
+ }
+
+ setSurfaceIfReady();
+
+ if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
+ + virtualActivityDisplay);
+ }
+
+ @Override
+ void setDrawn() {
+ synchronized (mService) {
+ mDrawn = true;
+ setSurfaceIfReady();
+ }
+ }
+
+ private void setSurfaceIfReady() {
+ if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
+ " mContainerState=" + mContainerState + " mSurface=" + mSurface);
+ if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
+ ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
+ mContainerState = CONTAINER_STATE_HAS_SURFACE;
+ }
+ }
+ }
+
/** Exactly one of these classes per Display in the system. Capable of holding zero or more
* attached {@link ActivityStack}s */
- final class ActivityDisplay {
+ class ActivityDisplay {
/** Actual Display this object tracks. */
int mDisplayId;
Display mDisplay;
DisplayInfo mDisplayInfo = new DisplayInfo();
- Surface mSurface;
/** All of the stacks on this display. Order matters, topmost stack is in front of all other
* stacks, bottommost behind. Accessed directly by ActivityManager package classes */
final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
- /** If this display is for an ActivityView then the VirtualDisplay created for it is stored
- * here. */
- VirtualDisplay mVirtualDisplay;
+ ActivityDisplay() {
+ }
ActivityDisplay(int displayId) {
init(mDisplayManager.getDisplay(displayId));
}
- ActivityDisplay(Surface surface, int width, int height, int density) {
- DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
- long ident = Binder.clearCallingIdentity();
- try {
- mVirtualDisplay = dm.createVirtualDisplay(mService.mContext,
- VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface,
- DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
- DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- init(mVirtualDisplay.getDisplay());
- mSurface = surface;
-
- mWindowManager.handleDisplayAdded(mDisplayId);
- }
-
- private void init(Display display) {
+ void init(Display display) {
mDisplay = display;
mDisplayId = display.getDisplayId();
mDisplay.getDisplayInfo(mDisplayInfo);
@@ -3255,11 +3352,6 @@
if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack
+ " from displayId=" + mDisplayId);
mStacks.remove(stack);
- if (mStacks.isEmpty() && mVirtualDisplay != null) {
- mVirtualDisplay.release();
- mVirtualDisplay = null;
- }
- mSurface.release();
}
void getBounds(Point bounds) {
@@ -3270,8 +3362,42 @@
@Override
public String toString() {
- return "ActivityDisplay={" + mDisplayId + (mVirtualDisplay == null ? "" : "V")
- + " numStacks=" + mStacks.size() + "}";
+ return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
+ }
+ }
+
+ class VirtualActivityDisplay extends ActivityDisplay {
+ VirtualDisplay mVirtualDisplay;
+
+ VirtualActivityDisplay(int width, int height, int density) {
+ DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+ mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, VIRTUAL_DISPLAY_BASE_NAME,
+ width, height, density, null, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
+
+ init(mVirtualDisplay.getDisplay());
+
+ mWindowManager.handleDisplayAdded(mDisplayId);
+ }
+
+ void setSurface(Surface surface) {
+ if (mVirtualDisplay != null) {
+ mVirtualDisplay.setSurface(surface);
+ }
+ }
+
+ @Override
+ void detachActivitiesLocked(ActivityStack stack) {
+ super.detachActivitiesLocked(stack);
+ if (mVirtualDisplay != null) {
+ mVirtualDisplay.release();
+ mVirtualDisplay = null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "VirtualActivityDisplay={" + mDisplayId + "}";
}
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 0ddb827..dbe773c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -32,6 +32,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Slog;
@@ -248,10 +249,10 @@
}
}
- public void noteDataConnectionActive(int type, boolean active, long timestampNs) {
+ public void noteMobileRadioPowerState(int powerState, long timestampNs) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteDataConnectionActive(type, active, timestampNs);
+ mStats.noteMobileRadioPowerState(powerState, timestampNs);
}
}
diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
index b12843b..d42d415 100644
--- a/services/core/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -17,18 +17,18 @@
package com.android.server.am;
import android.app.ApplicationErrorReport.CrashInfo;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructTimeval;
+import android.system.StructUcred;
import android.util.Slog;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.StructTimeval;
-import libcore.io.StructUcred;
-
-import static libcore.io.OsConstants.*;
+import static android.system.OsConstants.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
import java.net.InetSocketAddress;
import java.net.InetUnixAddress;
@@ -76,7 +76,7 @@
try {
CrashInfo ci = new CrashInfo();
ci.exceptionClassName = "Native crash";
- ci.exceptionMessage = Libcore.os.strsignal(mSignal);
+ ci.exceptionMessage = Os.strsignal(mSignal);
ci.throwFileName = "unknown";
ci.throwClassName = "unknown";
ci.throwMethodName = "unknown";
@@ -116,22 +116,22 @@
}
try {
- FileDescriptor serverFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0);
+ FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
final InetUnixAddress sockAddr = new InetUnixAddress(DEBUGGERD_SOCKET_PATH);
- Libcore.os.bind(serverFd, sockAddr, 0);
- Libcore.os.listen(serverFd, 1);
+ Os.bind(serverFd, sockAddr, 0);
+ Os.listen(serverFd, 1);
while (true) {
InetSocketAddress peer = new InetSocketAddress();
FileDescriptor peerFd = null;
try {
if (MORE_DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
- peerFd = Libcore.os.accept(serverFd, peer);
+ peerFd = Os.accept(serverFd, peer);
if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
if (peerFd != null) {
// Only the superuser is allowed to talk to us over this socket
StructUcred credentials =
- Libcore.os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
+ Os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
if (credentials.uid == 0) {
// the reporting thread may take responsibility for
// acking the debugger; make sure we play along.
@@ -145,7 +145,7 @@
// byte written is irrelevant.
if (peerFd != null) {
try {
- Libcore.os.write(peerFd, ackSignal, 0, 1);
+ Os.write(peerFd, ackSignal, 0, 1);
} catch (Exception e) {
/* we don't care about failures here */
if (MORE_DEBUG) {
@@ -153,7 +153,7 @@
}
}
try {
- Libcore.os.close(peerFd);
+ Os.close(peerFd);
} catch (ErrnoException e) {
if (MORE_DEBUG) {
Slog.d(TAG, "Exception closing socket: " + e.getMessage());
@@ -178,10 +178,10 @@
}
static int readExactly(FileDescriptor fd, byte[] buffer, int offset, int numBytes)
- throws ErrnoException {
+ throws ErrnoException, InterruptedIOException {
int totalRead = 0;
while (numBytes > 0) {
- int n = Libcore.os.read(fd, buffer, offset + totalRead, numBytes);
+ int n = Os.read(fd, buffer, offset + totalRead, numBytes);
if (n <= 0) {
if (DEBUG) {
Slog.w(TAG, "Needed " + numBytes + " but saw " + n);
@@ -202,8 +202,8 @@
try {
StructTimeval timeout = StructTimeval.fromMillis(SOCKET_TIMEOUT_MILLIS);
- Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
- Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);
// first, the pid and signal number
int headerBytes = readExactly(fd, buf, 0, 8);
@@ -237,7 +237,7 @@
int bytes;
do {
// get some data
- bytes = Libcore.os.read(fd, buf, 0, buf.length);
+ bytes = Os.read(fd, buf, 0, buf.length);
if (bytes > 0) {
if (MORE_DEBUG) {
String s = new String(buf, 0, bytes, "UTF-8");
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 363a9b7..e54c95e 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -193,14 +193,7 @@
pw.println(si.neededGrants);
}
if (si.uriPermissions != null) {
- if (si.uriPermissions.readUriPermissions != null) {
- pw.print(prefix); pw.print(" readUriPermissions=");
- pw.println(si.uriPermissions.readUriPermissions);
- }
- if (si.uriPermissions.writeUriPermissions != null) {
- pw.print(prefix); pw.print(" writeUriPermissions=");
- pw.println(si.uriPermissions.writeUriPermissions);
- }
+ si.uriPermissions.dump(pw, prefix);
}
}
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 3a43521..68da54d 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -28,7 +28,9 @@
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
import android.util.Slog;
+import com.android.internal.app.IVoiceInteractor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -36,6 +38,8 @@
final class TaskRecord extends ThumbnailHolder {
final int taskId; // Unique identifier for this task.
final String affinity; // The affinity name for this task, or null.
+ final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
+ final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
Intent intent; // The original intent that started the task.
Intent affinityIntent; // Intent of affinity-moved activity that started this task.
ComponentName origActivity; // The non-alias activity component of the intent.
@@ -64,9 +68,12 @@
* Display.DEFAULT_DISPLAY. */
boolean mOnTopOfHome = false;
- TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
+ TaskRecord(int _taskId, ActivityInfo info, Intent _intent,
+ IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
taskId = _taskId;
affinity = info.taskAffinity;
+ voiceSession = _voiceSession;
+ voiceInteractor = _voiceInteractor;
setIntent(_intent, info);
}
@@ -139,6 +146,18 @@
}
}
+ /** Returns the first non-finishing activity from the root. */
+ ActivityRecord getRootActivity() {
+ for (int i = 0; i < mActivities.size(); i++) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.finishing) {
+ continue;
+ }
+ return r;
+ }
+ return null;
+ }
+
ActivityRecord getTopActivity() {
for (int i = mActivities.size() - 1; i >= 0; --i) {
final ActivityRecord r = mActivities.get(i);
@@ -305,7 +324,7 @@
}
public ActivityManager.TaskThumbnails getTaskThumbnailsLocked() {
- TaskAccessInfo info = getTaskAccessInfoLocked(true);
+ TaskAccessInfo info = getTaskAccessInfoLocked();
final ActivityRecord resumedActivity = stack.mResumedActivity;
if (resumedActivity != null && resumedActivity.thumbHolder == this) {
info.mainThumbnail = stack.screenshotActivities(resumedActivity);
@@ -325,7 +344,7 @@
}
// Return the information about the task, to figure out the top
// thumbnail to return.
- TaskAccessInfo info = getTaskAccessInfoLocked(true);
+ TaskAccessInfo info = getTaskAccessInfoLocked();
if (info.numSubThumbbails <= 0) {
return info.mainThumbnail != null ? info.mainThumbnail : lastThumbnail;
}
@@ -334,7 +353,7 @@
public ActivityRecord removeTaskActivitiesLocked(int subTaskIndex,
boolean taskRequired) {
- TaskAccessInfo info = getTaskAccessInfoLocked(false);
+ TaskAccessInfo info = getTaskAccessInfoLocked();
if (info.root == null) {
if (taskRequired) {
Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
@@ -369,7 +388,7 @@
return mTaskType == ActivityRecord.APPLICATION_ACTIVITY_TYPE;
}
- public TaskAccessInfo getTaskAccessInfoLocked(boolean inclThumbs) {
+ public TaskAccessInfo getTaskAccessInfoLocked() {
final TaskAccessInfo thumbs = new TaskAccessInfo();
// How many different sub-thumbnails?
final int NA = mActivities.size();
@@ -461,6 +480,12 @@
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);
}
+ if (voiceSession != null || voiceInteractor != null) {
+ pw.print(prefix); pw.print("VOICE: session=0x");
+ pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
+ pw.print(" interactor=0x");
+ pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
+ }
if (intent != null) {
StringBuilder sb = new StringBuilder(128);
sb.append(prefix); sb.append("intent={");
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 1f12b74..4970b8d 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -17,15 +17,16 @@
package com.android.server.am;
import android.content.Intent;
-import android.net.Uri;
import android.os.UserHandle;
+import android.util.ArraySet;
import android.util.Log;
+import android.util.Slog;
+import com.android.server.am.ActivityManagerService.GrantUri;
import com.google.android.collect.Sets;
import java.io.PrintWriter;
import java.util.Comparator;
-import java.util.HashSet;
/**
* Description of a permission granted to an app to access a particular URI.
@@ -50,7 +51,7 @@
/** Cached UID of {@link #targetPkg}; should not be persisted */
final int targetUid;
- final Uri uri;
+ final GrantUri uri;
/**
* Allowed modes. All permission enforcement should use this field. Must
@@ -61,12 +62,13 @@
*/
int modeFlags = 0;
- /** Allowed modes with explicit owner. */
+ /** Allowed modes with active owner. */
int ownedModeFlags = 0;
/** Allowed modes without explicit owner. */
int globalModeFlags = 0;
/** Allowed modes that have been offered for possible persisting. */
int persistableModeFlags = 0;
+
/** Allowed modes that should be persisted across device boots. */
int persistedModeFlags = 0;
@@ -78,12 +80,12 @@
private static final long INVALID_TIME = Long.MIN_VALUE;
- private HashSet<UriPermissionOwner> mReadOwners;
- private HashSet<UriPermissionOwner> mWriteOwners;
+ private ArraySet<UriPermissionOwner> mReadOwners;
+ private ArraySet<UriPermissionOwner> mWriteOwners;
private String stringName;
- UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri) {
+ UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) {
this.userHandle = UserHandle.getUserId(targetUid);
this.sourcePkg = sourcePkg;
this.targetPkg = targetPkg;
@@ -100,6 +102,9 @@
* global or owner grants.
*/
void initPersistedModes(int modeFlags, long createdTime) {
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
persistableModeFlags = modeFlags;
persistedModeFlags = modeFlags;
persistedCreateTime = createdTime;
@@ -107,7 +112,11 @@
updateModeFlags();
}
- void grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner) {
+ void grantModes(int modeFlags, UriPermissionOwner owner) {
+ final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
if (persistable) {
persistableModeFlags |= modeFlags;
}
@@ -130,10 +139,14 @@
* @return if mode changes should trigger persisting.
*/
boolean takePersistableModes(int modeFlags) {
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
if ((modeFlags & persistableModeFlags) != modeFlags) {
- throw new SecurityException("Requested flags 0x"
+ Slog.w(TAG, "Requested flags 0x"
+ Integer.toHexString(modeFlags) + ", but only 0x"
+ Integer.toHexString(persistableModeFlags) + " are allowed");
+ return false;
}
final int before = persistedModeFlags;
@@ -148,6 +161,9 @@
}
boolean releasePersistableModes(int modeFlags) {
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
final int before = persistedModeFlags;
persistableModeFlags &= ~modeFlags;
@@ -164,7 +180,11 @@
/**
* @return if mode changes should trigger persisting.
*/
- boolean clearModes(int modeFlags, boolean persistable) {
+ boolean revokeModes(int modeFlags) {
+ final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
final int before = persistedModeFlags;
if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
@@ -208,6 +228,8 @@
* Return strength of this permission grant for the given flags.
*/
public int getStrength(int modeFlags) {
+ modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if ((persistableModeFlags & modeFlags) == modeFlags) {
return STRENGTH_PERSISTABLE;
} else if ((globalModeFlags & modeFlags) == modeFlags) {
@@ -221,7 +243,7 @@
private void addReadOwner(UriPermissionOwner owner) {
if (mReadOwners == null) {
- mReadOwners = Sets.newHashSet();
+ mReadOwners = Sets.newArraySet();
ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
updateModeFlags();
}
@@ -246,7 +268,7 @@
private void addWriteOwner(UriPermissionOwner owner) {
if (mWriteOwners == null) {
- mWriteOwners = Sets.newHashSet();
+ mWriteOwners = Sets.newArraySet();
ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
updateModeFlags();
}
@@ -333,7 +355,7 @@
final int userHandle;
final String sourcePkg;
final String targetPkg;
- final Uri uri;
+ final GrantUri uri;
final int persistedModeFlags;
final long persistedCreateTime;
@@ -352,6 +374,6 @@
}
public android.content.UriPermission buildPersistedPublicApiObject() {
- return new android.content.UriPermission(uri, persistedModeFlags, persistedCreateTime);
+ return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
}
}
diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
index 7bbd3bc..65d7047 100644
--- a/services/core/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/am/UriPermissionOwner.java
@@ -20,8 +20,11 @@
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
+import android.util.ArraySet;
-import java.util.HashSet;
+import com.google.android.collect.Sets;
+
+import java.io.PrintWriter;
import java.util.Iterator;
final class UriPermissionOwner {
@@ -30,8 +33,8 @@
Binder externalToken;
- HashSet<UriPermission> readUriPermissions; // special access to reading uris.
- HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
+ private ArraySet<UriPermission> mReadPerms;
+ private ArraySet<UriPermission> mWritePerms;
class ExternalToken extends Binder {
UriPermissionOwner getOwner() {
@@ -39,9 +42,9 @@
}
}
- UriPermissionOwner(ActivityManagerService _service, Object _owner) {
- service = _service;
- owner = _owner;
+ UriPermissionOwner(ActivityManagerService service, Object owner) {
+ this.service = service;
+ this.owner = owner;
}
Binder getExternalTokenLocked() {
@@ -64,82 +67,76 @@
}
void removeUriPermissionsLocked(int mode) {
- if ((mode&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
- && readUriPermissions != null) {
- for (UriPermission perm : readUriPermissions) {
- perm.removeReadOwner(this);
- service.removeUriPermissionIfNeededLocked(perm);
- }
- readUriPermissions = null;
- }
- if ((mode&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
- && writeUriPermissions != null) {
- for (UriPermission perm : writeUriPermissions) {
- perm.removeWriteOwner(this);
- service.removeUriPermissionIfNeededLocked(perm);
- }
- writeUriPermissions = null;
- }
+ removeUriPermissionLocked(null, mode);
}
void removeUriPermissionLocked(Uri uri, int mode) {
- if ((mode&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
- && readUriPermissions != null) {
- Iterator<UriPermission> it = readUriPermissions.iterator();
+ if ((mode & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0
+ && mReadPerms != null) {
+ Iterator<UriPermission> it = mReadPerms.iterator();
while (it.hasNext()) {
UriPermission perm = it.next();
- if (uri.equals(perm.uri)) {
+ if (uri == null || uri.equals(perm.uri)) {
perm.removeReadOwner(this);
service.removeUriPermissionIfNeededLocked(perm);
it.remove();
}
}
- if (readUriPermissions.size() == 0) {
- readUriPermissions = null;
+ if (mReadPerms.isEmpty()) {
+ mReadPerms = null;
}
}
- if ((mode&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
- && writeUriPermissions != null) {
- Iterator<UriPermission> it = writeUriPermissions.iterator();
+ if ((mode & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0
+ && mWritePerms != null) {
+ Iterator<UriPermission> it = mWritePerms.iterator();
while (it.hasNext()) {
UriPermission perm = it.next();
- if (uri.equals(perm.uri)) {
+ if (uri == null || uri.equals(perm.uri)) {
perm.removeWriteOwner(this);
service.removeUriPermissionIfNeededLocked(perm);
it.remove();
}
}
- if (writeUriPermissions.size() == 0) {
- writeUriPermissions = null;
+ if (mWritePerms.isEmpty()) {
+ mWritePerms = null;
}
}
}
public void addReadPermission(UriPermission perm) {
- if (readUriPermissions == null) {
- readUriPermissions = new HashSet<UriPermission>();
+ if (mReadPerms == null) {
+ mReadPerms = Sets.newArraySet();
}
- readUriPermissions.add(perm);
+ mReadPerms.add(perm);
}
public void addWritePermission(UriPermission perm) {
- if (writeUriPermissions == null) {
- writeUriPermissions = new HashSet<UriPermission>();
+ if (mWritePerms == null) {
+ mWritePerms = Sets.newArraySet();
}
- writeUriPermissions.add(perm);
+ mWritePerms.add(perm);
}
public void removeReadPermission(UriPermission perm) {
- readUriPermissions.remove(perm);
- if (readUriPermissions.size() == 0) {
- readUriPermissions = null;
+ mReadPerms.remove(perm);
+ if (mReadPerms.isEmpty()) {
+ mReadPerms = null;
}
}
public void removeWritePermission(UriPermission perm) {
- writeUriPermissions.remove(perm);
- if (writeUriPermissions.size() == 0) {
- writeUriPermissions = null;
+ mWritePerms.remove(perm);
+ if (mWritePerms.isEmpty()) {
+ mWritePerms = null;
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ if (mReadPerms != null) {
+ pw.print(prefix); pw.print("readUriPermissions="); pw.println(mReadPerms);
+ }
+ if (mWritePerms != null) {
+ pw.print(prefix); pw.print("writeUriPermissions="); pw.println(mWritePerms);
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 071417b..6697b60 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -517,6 +517,16 @@
return -1;
}
+ private void setVirtualDisplaySurfaceInternal(IBinder appToken, Surface surface) {
+ synchronized (mSyncRoot) {
+ if (mVirtualDisplayAdapter == null) {
+ return;
+ }
+
+ mVirtualDisplayAdapter.setVirtualDisplaySurfaceLocked(appToken, surface);
+ }
+ }
+
private void releaseVirtualDisplayInternal(IBinder appToken) {
synchronized (mSyncRoot) {
if (mVirtualDisplayAdapter == null) {
@@ -1221,9 +1231,6 @@
throw new IllegalArgumentException("width, height, and densityDpi must be "
+ "greater than 0");
}
- if (surface == null) {
- throw new IllegalArgumentException("surface must not be null");
- }
if (callingUid != Process.SYSTEM_UID &&
(flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
@@ -1255,6 +1262,16 @@
}
@Override // Binder call
+ public void setVirtualDisplaySurface(IBinder appToken, Surface surface) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ setVirtualDisplaySurfaceInternal(appToken, surface);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public void releaseVirtualDisplay(IBinder appToken) {
final long token = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 2c8f1b4..91afec7 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -95,6 +95,14 @@
}
}
+ static boolean shouldBlank(int state) {
+ return state == Display.STATE_OFF;
+ }
+
+ static boolean shouldUnblank(int state) {
+ return state == Display.STATE_ON || state == Display.STATE_DOZING;
+ }
+
private final class LocalDisplayDevice extends DisplayDevice {
private final int mBuiltInDisplayId;
private final SurfaceControl.PhysicalDisplayInfo mPhys;
@@ -180,9 +188,9 @@
@Override
public void requestDisplayStateLocked(int state) {
if (mState != state) {
- if (state == Display.STATE_OFF && mState != Display.STATE_OFF) {
+ if (shouldBlank(state) && !shouldBlank(mState)) {
SurfaceControl.blankDisplay(getDisplayTokenLocked());
- } else if (state != Display.STATE_OFF && mState == Display.STATE_OFF) {
+ } else if (shouldUnblank(state) && !shouldUnblank(mState)) {
SurfaceControl.unblankDisplay(getDisplayTokenLocked());
}
mState = state;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 95ca0d2..a165f26 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -69,6 +69,13 @@
return device;
}
+ public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) {
+ VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
+ if (device != null) {
+ device.setSurfaceLocked(surface);
+ }
+ }
+
public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
if (device != null) {
@@ -144,6 +151,17 @@
}
}
+ public void setSurfaceLocked(Surface surface) {
+ if (mSurface != surface) {
+ if ((mSurface != null) != (surface != null)) {
+ sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+ }
+ sendTraversalRequestLocked();
+ mSurface = surface;
+ mInfo = null;
+ }
+ }
+
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
@@ -171,6 +189,7 @@
}
mInfo.type = Display.TYPE_VIRTUAL;
mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+ mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
mInfo.ownerUid = mOwnerUid;
mInfo.ownerPackageName = mOwnerPackageName;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
new file mode 100644
index 0000000..5f07108
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -0,0 +1,94 @@
+/*
+ * 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.server.hdmi;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
+ * and pass it to CEC HAL so that it sends message to other device. For incoming
+ * message it translates the message and delegates it to proper module.
+ *
+ * <p>It can be created only by {@link HdmiCecController#create}
+ *
+ * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
+ */
+class HdmiCecController {
+ private static final String TAG = "HdmiCecController";
+
+ // Handler instance to process synchronous I/O (mainly send) message.
+ private Handler mIoHandler;
+
+ // Handler instance to process various messages coming from other CEC
+ // device or issued by internal state change.
+ private Handler mMessageHandler;
+
+ // Stores the pointer to the native implementation of the service that
+ // interacts with HAL.
+ private long mNativePtr;
+
+ // Private constructor. Use HdmiCecController.create().
+ private HdmiCecController() {
+ }
+
+ /**
+ * A factory method to get {@link HdmiCecController}. If it fails to initialize
+ * inner device or has no device it will return {@code null}.
+ *
+ * <p>Declared as package-private, accessed by {@link HdmiControlService} only.
+ *
+ * @param ioLooper a Looper instance to handle IO (mainly send message) operation.
+ * @param messageHandler a message handler that processes a message coming from other
+ * CEC compatible device or callback of internal state change.
+ * @return {@link HdmiCecController} if device is initialized successfully. Otherwise,
+ * returns {@code null}.
+ */
+ static HdmiCecController create(Looper ioLooper, Handler messageHandler) {
+ HdmiCecController handler = new HdmiCecController();
+ long nativePtr = nativeInit(handler);
+ if (nativePtr == 0L) {
+ handler = null;
+ return null;
+ }
+
+ handler.init(ioLooper, messageHandler, nativePtr);
+ return handler;
+ }
+
+ private void init(Looper ioLooper, Handler messageHandler, long nativePtr) {
+ mIoHandler = new Handler(ioLooper) {
+ @Override
+ public void handleMessage(Message msg) {
+ // TODO: Call native sendMessage.
+ }
+ };
+
+ mMessageHandler = messageHandler;
+ mNativePtr = nativePtr;
+ }
+
+ /**
+ * Called by native when an HDMI-CEC message arrived.
+ */
+ private void handleMessage(int srcAddress, int dstAddres, int opcode, byte[] params) {
+ // TODO: Translate message and delegate it to main message handler.
+ }
+
+ private static native long nativeInit(HdmiCecController handler);
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
new file mode 100644
index 0000000..56c5b49
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -0,0 +1,70 @@
+/*
+ * 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.server.hdmi;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+/**
+ * Provides a service for sending and processing HDMI control messages,
+ * HDMI-CEC and MHL control command, and providing the information on both standard.
+ */
+public final class HdmiControlService extends SystemService {
+ private static final String TAG = "HdmiControlService";
+
+ // A thread to handle synchronous IO of CEC and MHL control service.
+ // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms)
+ // and sparse call it shares a thread to handle IO operations.
+ private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread");
+
+ // Main handler class to handle incoming message from each controller.
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ // TODO: Add handler for each message type.
+ }
+ };
+
+ @Nullable
+ private HdmiCecController mCecController;
+
+ @Nullable
+ private HdmiMhlController mMhlController;
+
+ public HdmiControlService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mCecController = HdmiCecController.create(mIoThread.getLooper(), mHandler);
+ if (mCecController == null) {
+ Slog.i(TAG, "Device does not support HDMI-CEC.");
+ }
+
+ mMhlController = HdmiMhlController.create(mIoThread.getLooper(), mHandler);
+ if (mMhlController == null) {
+ Slog.i(TAG, "Device does not support MHL-control.");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
index fab84a8..79f192d 100644
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java
@@ -60,6 +60,10 @@
private static final int FLP_RESULT_ID_UNKNOWN = -5;
private static final int FLP_RESULT_INVALID_GEOFENCE_TRANSITION = -6;
+ // FlpHal monitor status codes, they must be equal to the ones in fused_location.h
+ private static final int FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE = 1<<0;
+ private static final int FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE = 1<<1;
+
public static FlpHardwareProvider getInstance(Context context) {
if (sSingletonInstance == null) {
sSingletonInstance = new FlpHardwareProvider(context);
@@ -141,6 +145,8 @@
int transition,
long timestamp,
int sourcesUsed) {
+ // the transition Id does not require translation because the values in fused_location.h
+ // and GeofenceHardware are in sync
getGeofenceHardwareSink().reportGeofenceTransition(
geofenceId,
updateLocationInformation(location),
@@ -157,9 +163,23 @@
updatedLocation = updateLocationInformation(location);
}
+ int monitorStatus;
+ switch (status) {
+ case FLP_GEOFENCE_MONITOR_STATUS_UNAVAILABLE:
+ monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
+ break;
+ case FLP_GEOFENCE_MONITOR_STATUS_AVAILABLE:
+ monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
+ break;
+ default:
+ Log.e(TAG, "Invalid FlpHal Geofence monitor status: " + status);
+ monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
+ break;
+ }
+
getGeofenceHardwareSink().reportGeofenceMonitorStatus(
GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE,
- status,
+ monitorStatus,
updatedLocation,
source);
}
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
new file mode 100644
index 0000000..d314ea7
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
@@ -0,0 +1,379 @@
+/*
+ * 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.server.media;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.routeprovider.IRouteConnection;
+import android.media.routeprovider.IRouteProvider;
+import android.media.routeprovider.IRouteProviderCallback;
+import android.media.routeprovider.RouteProviderService;
+import android.media.routeprovider.RouteRequest;
+import android.media.session.RouteEvent;
+import android.media.session.RouteInfo;
+import android.media.session.Session;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * System representation and interface to a MediaRouteProvider. This class is
+ * not thread safe so all calls should be made on the main thread.
+ */
+public class MediaRouteProviderProxy {
+ private static final String TAG = "MRPProxy";
+ private static final boolean DEBUG = true;
+
+ private static final int MAX_RETRIES = 3;
+
+ private final Object mLock = new Object();
+ private final Context mContext;
+ private final String mId;
+ private final ComponentName mComponentName;
+ private final int mUserId;
+
+ private Intent mBindIntent;
+ // Interfaces declared in the manifest
+ private ArrayList<String> mInterfaces;
+ private ArrayList<RouteConnectionRecord> mConnections = new ArrayList<RouteConnectionRecord>();
+ private Handler mHandler = new Handler();
+
+ private IRouteProvider mBinder;
+ private boolean mRunning;
+ private boolean mInterested;
+ private boolean mBound;
+ private int mRetryCount;
+
+ private RoutesListener mRouteListener;
+
+ public MediaRouteProviderProxy(Context context, String id, ComponentName component, int uid,
+ ArrayList<String> interfaces) {
+ mContext = context;
+ mId = id;
+ mComponentName = component;
+ mUserId = uid;
+ mInterfaces = interfaces;
+ mBindIntent = new Intent(RouteProviderService.SERVICE_INTERFACE);
+ mBindIntent.setComponent(mComponentName);
+ }
+
+ /**
+ * Send any cleanup messages and unbind from the media route provider
+ */
+ public void stop() {
+ if (mRunning) {
+ mRunning = false;
+ mRetryCount = 0;
+ updateBinding();
+ }
+ }
+
+ /**
+ * Bind to the media route provider and perform any setup needed
+ */
+ public void start() {
+ if (!mRunning) {
+ mRunning = true;
+ updateBinding();
+ }
+ }
+
+ /**
+ * Set whether or not this provider is currently interesting to the system.
+ * In the future this may take a list of interfaces instead.
+ *
+ * @param interested True if we want to connect to this provider
+ */
+ public void setInterested(boolean interested) {
+ mInterested = interested;
+ updateBinding();
+ }
+
+ /**
+ * Set a listener to get route updates on.
+ *
+ * @param listener The listener to receive updates on.
+ */
+ public void setRoutesListener(RoutesListener listener) {
+ mRouteListener = listener;
+ }
+
+ /**
+ * Send a request to the Provider to get all the routes that the session can
+ * use.
+ *
+ * @param record The session to get routes for.
+ * @param requestId An id to identify this request.
+ */
+ public void getRoutes(MediaSessionRecord record, final int requestId) {
+ // TODO change routes to have a system global id and maintain a mapping
+ // to the original route
+ if (mBinder == null) {
+ Log.wtf(TAG, "Attempted to call getRoutes without a binder connection");
+ return;
+ }
+ List<RouteRequest> requests = record.getRouteRequests();
+ final String sessionId = record.getSessionInfo().getId();
+ try {
+ mBinder.getAvailableRoutes(requests, new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode != RouteProviderService.RESULT_SUCCESS) {
+ // ignore failures, just means no routes were generated
+ return;
+ }
+ ArrayList<RouteInfo> routes
+ = resultData.getParcelableArrayList(RouteProviderService.KEY_ROUTES);
+ ArrayList<RouteInfo> sysRoutes = new ArrayList<RouteInfo>();
+ for (int i = 0; i < routes.size(); i++) {
+ RouteInfo route = routes.get(i);
+ RouteInfo.Builder bob = new RouteInfo.Builder(route);
+ bob.setProviderId(mId);
+ sysRoutes.add(bob.build());
+ }
+ if (mRouteListener != null) {
+ mRouteListener.onRoutesUpdated(sessionId, sysRoutes, requestId);
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error in getRoutes", e);
+ }
+ }
+
+ /**
+ * Try connecting again if we've been disconnected.
+ */
+ public void rebindIfDisconnected() {
+ if (mBinder == null && shouldBind()) {
+ unbind();
+ bind();
+ }
+ }
+
+ /**
+ * Send a request to connect to a route.
+ *
+ * @param session The session that is trying to connect.
+ * @param route The route it is connecting to.
+ * @param request The request with the connection parameters.
+ * @return true if the request was sent, false otherwise.
+ */
+ public boolean connectToRoute(MediaSessionRecord session, final RouteInfo route,
+ final RouteRequest request) {
+ final String sessionId = session.getSessionInfo().getId();
+ try {
+ mBinder.connect(route, request, new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode != RouteProviderService.RESULT_SUCCESS) {
+ // TODO handle connection failure
+ return;
+ }
+ IBinder binder = resultData.getBinder(RouteProviderService.KEY_CONNECTION);
+ IRouteConnection connection = null;
+ if (binder != null) {
+ connection = IRouteConnection.Stub.asInterface(binder);
+ }
+
+ if (connection != null) {
+ RouteConnectionRecord record = new RouteConnectionRecord(
+ connection);
+ mConnections.add(record);
+ if (mRouteListener != null) {
+ mRouteListener.onRouteConnected(sessionId, route, request, record);
+ }
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error connecting to route.", e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Check if this is the provider you're looking for.
+ */
+ public boolean hasComponentName(String packageName, String className) {
+ return mComponentName.getPackageName().equals(packageName)
+ && mComponentName.getClassName().equals(className);
+ }
+
+ /**
+ * Get the unique id for this provider.
+ *
+ * @return The provider's id.
+ */
+ public String getId() {
+ return mId;
+ }
+
+ private void updateBinding() {
+ if (shouldBind()) {
+ bind();
+ } else {
+ unbind();
+ }
+ }
+
+ private boolean shouldBind() {
+ return mRunning && mInterested;
+ }
+
+ private void bind() {
+ if (!mBound) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Binding");
+ }
+
+ try {
+ mBound = mContext.bindServiceAsUser(mBindIntent, mServiceConn,
+ Context.BIND_AUTO_CREATE, new UserHandle(mUserId));
+ if (!mBound && DEBUG) {
+ Slog.d(TAG, this + ": Bind failed");
+ }
+ } catch (SecurityException ex) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Bind failed", ex);
+ }
+ }
+ }
+ }
+
+ private void unbind() {
+ if (mBound) {
+ if (DEBUG) {
+ Slog.d(TAG, this + ": Unbinding");
+ }
+
+ mBound = false;
+ mContext.unbindService(mServiceConn);
+ }
+ }
+
+ private RouteConnectionRecord getConnectionLocked(IBinder binder) {
+ for (int i = mConnections.size() - 1; i >= 0; i--) {
+ RouteConnectionRecord record = mConnections.get(i);
+ if (record.isConnection(binder)) {
+ return record;
+ }
+ }
+ return null;
+ }
+
+ private ServiceConnection mServiceConn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mBinder = IRouteProvider.Stub.asInterface(service);
+ if (DEBUG) {
+ Slog.d(TAG, "Connected to route provider");
+ }
+ try {
+ mBinder.registerCallback(mCbStub);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error registering callback on route provider. Retry count: "
+ + mRetryCount, e);
+ if (mRetryCount < MAX_RETRIES) {
+ mRetryCount++;
+ rebindIfDisconnected();
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mBinder = null;
+ if (DEBUG) {
+ Slog.d(TAG, "Disconnected from route provider");
+ }
+ }
+
+ };
+
+ private IRouteProviderCallback.Stub mCbStub = new IRouteProviderCallback.Stub() {
+ @Override
+ public void onConnectionStateChanged(IRouteConnection connection, int state)
+ throws RemoteException {
+ // TODO
+ }
+
+ @Override
+ public void onRouteEvent(RouteEvent event) throws RemoteException {
+ synchronized (mLock) {
+ RouteConnectionRecord record = getConnectionLocked(event.getConnection());
+ Log.d(TAG, "Received route event for record " + record);
+ if (record != null) {
+ record.sendEvent(event);
+ }
+ }
+ }
+
+ @Override
+ public void onConnectionTerminated(IRouteConnection connection) throws RemoteException {
+ synchronized (mLock) {
+ RouteConnectionRecord record = getConnectionLocked(connection.asBinder());
+ if (record != null) {
+ record.disconnect();
+ mConnections.remove(record);
+ }
+ }
+ }
+
+ @Override
+ public void onRoutesChanged() throws RemoteException {
+ // TODO
+ }
+ };
+
+ /**
+ * Listener for receiving responses to route requests on the provider.
+ */
+ public interface RoutesListener {
+ /**
+ * Called when routes have been returned from a request to getRoutes.
+ *
+ * @param record The session that the routes were requested for.
+ * @param routes The matching routes returned by the provider.
+ * @param reqId The request id this is responding to.
+ */
+ public void onRoutesUpdated(String sessionId, ArrayList<RouteInfo> routes,
+ int reqId);
+
+ /**
+ * Called when a route has successfully connected.
+ *
+ * @param session The session that was connected.
+ * @param route The route it connected to.
+ * @param options The options that were used for the connection.
+ * @param connection The connection instance that was created.
+ */
+ public void onRouteConnected(String sessionId, RouteInfo route,
+ RouteRequest options, RouteConnectionRecord connection);
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java b/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java
new file mode 100644
index 0000000..cf1d95ab
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java
@@ -0,0 +1,229 @@
+/*
+ * 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.server.media;
+
+import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.media.routeprovider.RouteProviderService;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.UUID;
+
+/**
+ * Watches for media route provider services to be installed. Adds a provider to
+ * the media session service for each registered service. For now just run all
+ * providers. In the future define a policy for when to run providers.
+ */
+public class MediaRouteProviderWatcher {
+ private static final String TAG = "MRPWatcher";
+ private static final boolean DEBUG = true; // Log.isLoggable(TAG,
+ // Log.DEBUG);
+
+ private final Context mContext;
+ private final Callback mCallback;
+ private final Handler mHandler;
+ private final int mUserId;
+ private final PackageManager mPackageManager;
+
+ private final ArrayList<MediaRouteProviderProxy> mProviders =
+ new ArrayList<MediaRouteProviderProxy>();
+ private boolean mRunning;
+
+ public MediaRouteProviderWatcher(Context context, Callback callback, Handler handler,
+ int userId) {
+ mContext = context;
+ mCallback = callback;
+ mHandler = handler;
+ mUserId = userId;
+ mPackageManager = context.getPackageManager();
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(prefix + " mUserId=" + mUserId);
+ pw.println(prefix + " mRunning=" + mRunning);
+ pw.println(prefix + " mProviders.size()=" + mProviders.size());
+ }
+
+ public void start() {
+ if (!mRunning) {
+ mRunning = true;
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverAsUser(mScanPackagesReceiver,
+ new UserHandle(mUserId), filter, null, mHandler);
+
+ // Scan packages.
+ // Also has the side-effect of restarting providers if needed.
+ mHandler.post(mScanPackagesRunnable);
+ }
+ }
+
+ public void stop() {
+ if (mRunning) {
+ mRunning = false;
+
+ mContext.unregisterReceiver(mScanPackagesReceiver);
+ mHandler.removeCallbacks(mScanPackagesRunnable);
+
+ // Stop all providers.
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ mProviders.get(i).stop();
+ }
+ }
+ }
+
+ public ArrayList<MediaRouteProviderProxy> getProviders() {
+ return mProviders;
+ }
+
+ public MediaRouteProviderProxy getProvider(String id) {
+ int providerIndex = findProvider(id);
+ if (providerIndex != -1) {
+ return mProviders.get(providerIndex);
+ }
+ return null;
+ }
+
+ private void scanPackages() {
+ if (!mRunning) {
+ return;
+ }
+
+ // Add providers for all new services.
+ // Reorder the list so that providers left at the end will be the ones
+ // to remove.
+ int targetIndex = 0;
+ Intent intent = new Intent(RouteProviderService.SERVICE_INTERFACE);
+ for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser(
+ intent, 0, mUserId)) {
+ ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ if (DEBUG) {
+ Slog.d(TAG, "Checking service " + (serviceInfo == null ? null : serviceInfo.name));
+ }
+ if (serviceInfo != null && verifyServiceTrusted(serviceInfo)) {
+ int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
+ if (sourceIndex < 0) {
+ // TODO get declared interfaces from manifest
+ if (DEBUG) {
+ Slog.d(TAG, "Creating new provider proxy for service");
+ }
+ MediaRouteProviderProxy provider =
+ new MediaRouteProviderProxy(mContext, UUID.randomUUID().toString(),
+ new ComponentName(serviceInfo.packageName, serviceInfo.name),
+ mUserId, null);
+ provider.start();
+ mProviders.add(targetIndex++, provider);
+ mCallback.addProvider(provider);
+ } else if (sourceIndex >= targetIndex) {
+ MediaRouteProviderProxy provider = mProviders.get(sourceIndex);
+ provider.start(); // restart the provider if needed
+ provider.rebindIfDisconnected();
+ Collections.swap(mProviders, sourceIndex, targetIndex++);
+ }
+ }
+ }
+
+ // Remove providers for missing services.
+ if (targetIndex < mProviders.size()) {
+ for (int i = mProviders.size() - 1; i >= targetIndex; i--) {
+ MediaRouteProviderProxy provider = mProviders.get(i);
+ mCallback.removeProvider(provider);
+ mProviders.remove(provider);
+ provider.stop();
+ }
+ }
+ }
+
+ private boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
+ if (serviceInfo.permission == null || !serviceInfo.permission.equals(
+ Manifest.permission.BIND_ROUTE_PROVIDER)) {
+ // If the service does not require this permission then any app
+ // could potentially bind to it and mess with their routes. So we
+ // only want to trust providers that require the
+ // correct permissions.
+ Slog.w(TAG, "Ignoring route provider service because it did not "
+ + "require the BIND_ROUTE_PROVIDER permission in its manifest: "
+ + serviceInfo.packageName + "/" + serviceInfo.name);
+ return false;
+ }
+ // Looks good.
+ return true;
+ }
+
+ private int findProvider(String id) {
+ int count = mProviders.size();
+ for (int i = 0; i < count; i++) {
+ MediaRouteProviderProxy provider = mProviders.get(i);
+ if (TextUtils.equals(id, provider.getId())) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private int findProvider(String packageName, String className) {
+ int count = mProviders.size();
+ for (int i = 0; i < count; i++) {
+ MediaRouteProviderProxy provider = mProviders.get(i);
+ if (provider.hasComponentName(packageName, className)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received package manager broadcast: " + intent);
+ }
+ scanPackages();
+ }
+ };
+
+ private final Runnable mScanPackagesRunnable = new Runnable() {
+ @Override
+ public void run() {
+ scanPackages();
+ }
+ };
+
+ public interface Callback {
+ void addProvider(MediaRouteProviderProxy provider);
+
+ void removeProvider(MediaRouteProviderProxy provider);
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 1ff925c..ac7f4f3 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -17,11 +17,20 @@
package com.android.server.media;
import android.content.Intent;
-import android.media.session.IMediaController;
-import android.media.session.IMediaControllerCallback;
-import android.media.session.IMediaSession;
-import android.media.session.IMediaSessionCallback;
+import android.media.routeprovider.RouteRequest;
+import android.media.session.ISessionController;
+import android.media.session.ISessionControllerCallback;
+import android.media.session.ISession;
+import android.media.session.ISessionCallback;
+import android.media.session.SessionController;
import android.media.session.MediaMetadata;
+import android.media.session.RouteCommand;
+import android.media.session.RouteInfo;
+import android.media.session.RouteOptions;
+import android.media.session.RouteEvent;
+import android.media.session.Session;
+import android.media.session.SessionInfo;
+import android.media.session.RouteInterface;
import android.media.session.PlaybackState;
import android.media.Rating;
import android.os.Bundle;
@@ -31,37 +40,44 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.view.KeyEvent;
import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
/**
* This is the system implementation of a Session. Apps will interact with the
* MediaSession wrapper class instead.
*/
public class MediaSessionRecord implements IBinder.DeathRecipient {
- private static final String TAG = "MediaSessionImpl";
+ private static final String TAG = "MediaSessionRecord";
private final MessageHandler mHandler;
private final int mPid;
- private final String mPackageName;
+ private final SessionInfo mSessionInfo;
private final String mTag;
private final ControllerStub mController;
private final SessionStub mSession;
private final SessionCb mSessionCb;
private final MediaSessionService mService;
- private final Object mControllerLock = new Object();
- private final ArrayList<IMediaControllerCallback> mControllerCallbacks =
- new ArrayList<IMediaControllerCallback>();
- private final ArrayList<String> mInterfaces = new ArrayList<String>();
+ private final Object mLock = new Object();
+ private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
+ new ArrayList<ISessionControllerCallback>();
+ private final ArrayList<RouteRequest> mRequests = new ArrayList<RouteRequest>();
private boolean mTransportPerformerEnabled = false;
- private Bundle mRoute;
+ private RouteInfo mRoute;
+ private RouteOptions mRequest;
+ private RouteConnectionRecord mConnection;
+ // TODO define a RouteState class with relevant info
+ private int mRouteState;
// TransportPerformer fields
@@ -72,10 +88,10 @@
private boolean mIsPublished = false;
- public MediaSessionRecord(int pid, String packageName, IMediaSessionCallback cb, String tag,
+ public MediaSessionRecord(int pid, String packageName, ISessionCallback cb, String tag,
MediaSessionService service, Handler handler) {
mPid = pid;
- mPackageName = packageName;
+ mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), packageName);
mTag = tag;
mController = new ControllerStub();
mSession = new SessionStub();
@@ -84,31 +100,140 @@
mHandler = new MessageHandler(handler.getLooper());
}
- public IMediaSession getSessionBinder() {
+ /**
+ * Get the binder for the {@link Session}.
+ *
+ * @return The session binder apps talk to.
+ */
+ public ISession getSessionBinder() {
return mSession;
}
- public IMediaController getControllerBinder() {
+ /**
+ * Get the binder for the {@link SessionController}.
+ *
+ * @return The controller binder apps talk to.
+ */
+ public ISessionController getControllerBinder() {
return mController;
}
+ /**
+ * Get the set of route requests this session is interested in.
+ *
+ * @return The list of RouteRequests
+ */
+ public List<RouteRequest> getRouteRequests() {
+ return mRequests;
+ }
+
+ /**
+ * Get the route this session is currently on.
+ *
+ * @return The route the session is on.
+ */
+ public RouteInfo getRoute() {
+ return mRoute;
+ }
+
+ /**
+ * Get the info for this session.
+ *
+ * @return Info that identifies this session.
+ */
+ public SessionInfo getSessionInfo() {
+ return mSessionInfo;
+ }
+
+ /**
+ * Set the selected route. This does not connect to the route, just notifies
+ * the app that a new route has been selected.
+ *
+ * @param route The route that was selected.
+ */
+ public void selectRoute(RouteInfo route) {
+ synchronized (mLock) {
+ if (route != mRoute) {
+ if (mConnection != null) {
+ mConnection.disconnect();
+ mConnection = null;
+ }
+ }
+ mRoute = route;
+ }
+ mSessionCb.sendRouteChange(route);
+ }
+
+ /**
+ * Update the state of the route this session is using and notify the
+ * session.
+ *
+ * @param state The new state of the route.
+ */
+ public void setRouteState(int state) {
+ mSessionCb.sendRouteStateChange(state);
+ }
+
+ /**
+ * Send an event to this session from the route it is using.
+ *
+ * @param event The event to send.
+ */
+ public void sendRouteEvent(RouteEvent event) {
+ mSessionCb.sendRouteEvent(event);
+ }
+
+ /**
+ * Set the connection to use for the selected route and notify the app it is
+ * now connected.
+ *
+ * @param route The route the connection is to.
+ * @param request The request that was used to connect.
+ * @param connection The connection to the route.
+ * @return True if this connection is still valid, false if it is stale.
+ */
+ public boolean setRouteConnected(RouteInfo route, RouteOptions request,
+ RouteConnectionRecord connection) {
+ synchronized (mLock) {
+ if (mRoute == null || !TextUtils.equals(route.getId(), mRoute.getId())) {
+ Log.w(TAG, "setRouteConnected: connected route is stale");
+ // TODO figure out disconnection path
+ return false;
+ }
+ if (request != mRequest) {
+ Log.w(TAG, "setRouteConnected: connection request is stale");
+ // TODO figure out disconnection path
+ return false;
+ }
+ mConnection = connection;
+ mConnection.setListener(mConnectionListener);
+ mSessionCb.sendRouteConnected();
+ }
+ return true;
+ }
+
+ /**
+ * Check if this session has been published by the app yet.
+ *
+ * @return True if it has been published, false otherwise.
+ */
+ public boolean isPublished() {
+ return mIsPublished;
+ }
+
@Override
public void binderDied() {
mService.sessionDied(this);
}
- public boolean isPublished() {
- return mIsPublished;
- }
-
private void onDestroy() {
mService.destroySession(this);
}
private void pushPlaybackStateUpdate() {
- synchronized (mControllerLock) {
+ synchronized (mLock) {
for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
- IMediaControllerCallback cb = mControllerCallbacks.get(i);
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
cb.onPlaybackStateChanged(mPlaybackState);
} catch (RemoteException e) {
@@ -120,9 +245,9 @@
}
private void pushMetadataUpdate() {
- synchronized (mControllerLock) {
+ synchronized (mLock) {
for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
- IMediaControllerCallback cb = mControllerCallbacks.get(i);
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
cb.onMetadataChanged(mMetadata);
} catch (RemoteException e) {
@@ -134,9 +259,9 @@
}
private void pushRouteUpdate() {
- synchronized (mControllerLock) {
+ synchronized (mLock) {
for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
- IMediaControllerCallback cb = mControllerCallbacks.get(i);
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
cb.onRouteChanged(mRoute);
} catch (RemoteException e) {
@@ -148,21 +273,50 @@
}
private void pushEvent(String event, Bundle data) {
- synchronized (mControllerLock) {
+ synchronized (mLock) {
for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
- IMediaControllerCallback cb = mControllerCallbacks.get(i);
+ ISessionControllerCallback cb = mControllerCallbacks.get(i);
try {
cb.onEvent(event, data);
} catch (RemoteException e) {
- Log.w(TAG, "Removing dead callback in pushRouteUpdate.", e);
- mControllerCallbacks.remove(i);
+ Log.w(TAG, "Error with callback in pushEvent.", e);
}
}
}
}
- private final class SessionStub extends IMediaSession.Stub {
+ private void pushRouteCommand(RouteCommand command, ResultReceiver cb) {
+ synchronized (mLock) {
+ if (mRoute == null || !TextUtils.equals(command.getRouteInfo(), mRoute.getId())) {
+ if (cb != null) {
+ cb.send(RouteInterface.RESULT_ROUTE_IS_STALE, null);
+ return;
+ }
+ }
+ if (mConnection != null) {
+ mConnection.sendCommand(command, cb);
+ } else if (cb != null) {
+ cb.send(RouteInterface.RESULT_NOT_CONNECTED, null);
+ }
+ }
+ }
+ private final RouteConnectionRecord.Listener mConnectionListener
+ = new RouteConnectionRecord.Listener() {
+ @Override
+ public void onEvent(RouteEvent event) {
+ RouteEvent eventForSession = new RouteEvent(null, event.getIface(),
+ event.getEvent(), event.getExtras());
+ mSessionCb.sendRouteEvent(eventForSession);
+ }
+
+ @Override
+ public void disconnect() {
+ // TODO
+ }
+ };
+
+ private final class SessionStub extends ISession.Stub {
@Override
public void destroy() {
onDestroy();
@@ -174,21 +328,11 @@
}
@Override
- public IMediaController getMediaController() {
+ public ISessionController getController() {
return mController;
}
@Override
- public void setRouteState(Bundle routeState) {
- }
-
- @Override
- public void setRoute(Bundle mediaRouteDescriptor) {
- mRoute = mediaRouteDescriptor;
- mHandler.post(MessageHandler.MSG_UPDATE_ROUTE);
- }
-
- @Override
public void publish() {
mIsPublished = true; // TODO push update to service
}
@@ -198,11 +342,6 @@
}
@Override
- public List<String> getSupportedInterfaces() {
- return mInterfaces;
- }
-
- @Override
public void setMetadata(MediaMetadata metadata) {
mMetadata = metadata;
mHandler.post(MessageHandler.MSG_UPDATE_METADATA);
@@ -218,12 +357,44 @@
public void setRatingType(int type) {
mRatingType = type;
}
+
+ @Override
+ public void sendRouteCommand(RouteCommand command, ResultReceiver cb) {
+ mHandler.post(MessageHandler.MSG_SEND_COMMAND,
+ new Pair<RouteCommand, ResultReceiver>(command, cb));
+ }
+
+ @Override
+ public boolean setRoute(RouteInfo route) throws RemoteException {
+ // TODO decide if allowed to set route and if the route exists
+ return false;
+ }
+
+ @Override
+ public void connectToRoute(RouteInfo route, RouteOptions request)
+ throws RemoteException {
+ if (mRoute == null || !TextUtils.equals(route.getId(), mRoute.getId())) {
+ throw new RemoteException("RouteInfo does not match current route");
+ }
+ mService.connectToRoute(MediaSessionRecord.this, route, request);
+ mRequest = request;
+ }
+
+ @Override
+ public void setRouteOptions(List<RouteOptions> options) throws RemoteException {
+ mRequests.clear();
+ for (int i = options.size() - 1; i >= 0; i--) {
+ RouteRequest request = new RouteRequest(mSessionInfo, options.get(i),
+ false);
+ mRequests.add(request);
+ }
+ }
}
class SessionCb {
- private final IMediaSessionCallback mCb;
+ private final ISessionCallback mCb;
- public SessionCb(IMediaSessionCallback cb) {
+ public SessionCb(ISessionCallback cb) {
mCb = cb;
}
@@ -245,6 +416,38 @@
}
}
+ public void sendRouteChange(RouteInfo route) {
+ try {
+ mCb.onRequestRouteChange(route);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in sendRouteChange.", e);
+ }
+ }
+
+ public void sendRouteStateChange(int state) {
+ try {
+ mCb.onRouteStateChange(state);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in sendRouteStateChange.", e);
+ }
+ }
+
+ public void sendRouteEvent(RouteEvent event) {
+ try {
+ mCb.onRouteEvent(event);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in sendRouteEvent.", e);
+ }
+ }
+
+ public void sendRouteConnected() {
+ try {
+ mCb.onRouteConnected(mRoute, mRequest);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in sendRouteStateChange.", e);
+ }
+ }
+
public void play() {
try {
mCb.onPlay();
@@ -318,7 +521,7 @@
}
}
- class ControllerStub extends IMediaController.Stub {
+ class ControllerStub extends ISessionController.Stub {
@Override
public void sendCommand(String command, Bundle extras, ResultReceiver cb)
throws RemoteException {
@@ -331,8 +534,8 @@
}
@Override
- public void registerCallbackListener(IMediaControllerCallback cb) {
- synchronized (mControllerLock) {
+ public void registerCallbackListener(ISessionControllerCallback cb) {
+ synchronized (mLock) {
if (!mControllerCallbacks.contains(cb)) {
mControllerCallbacks.add(cb);
}
@@ -340,9 +543,9 @@
}
@Override
- public void unregisterCallbackListener(IMediaControllerCallback cb)
+ public void unregisterCallbackListener(ISessionControllerCallback cb)
throws RemoteException {
- synchronized (mControllerLock) {
+ synchronized (mLock) {
mControllerCallbacks.remove(cb);
}
}
@@ -409,9 +612,14 @@
}
@Override
- public boolean isTransportControlEnabled() throws RemoteException {
+ public boolean isTransportControlEnabled() {
return mTransportPerformerEnabled;
}
+
+ @Override
+ public void showRoutePicker() {
+ mService.showRoutePickerForSession(MediaSessionRecord.this);
+ }
}
private class MessageHandler extends Handler {
@@ -419,6 +627,8 @@
private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
private static final int MSG_UPDATE_ROUTE = 3;
private static final int MSG_SEND_EVENT = 4;
+ private static final int MSG_UPDATE_ROUTE_FILTERS = 5;
+ private static final int MSG_SEND_COMMAND = 6;
public MessageHandler(Looper looper) {
super(looper);
@@ -438,6 +648,11 @@
case MSG_SEND_EVENT:
pushEvent((String) msg.obj, msg.getData());
break;
+ case MSG_SEND_COMMAND:
+ Pair<RouteCommand, ResultReceiver> cmd =
+ (Pair<RouteCommand, ResultReceiver>) msg.obj;
+ pushRouteCommand(cmd.first, cmd.second);
+ break;
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 8fe6055..bc91370 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -17,9 +17,12 @@
package com.android.server.media;
import android.content.Context;
-import android.media.session.IMediaSession;
-import android.media.session.IMediaSessionCallback;
-import android.media.session.IMediaSessionManager;
+import android.media.routeprovider.RouteRequest;
+import android.media.session.ISession;
+import android.media.session.ISessionCallback;
+import android.media.session.ISessionManager;
+import android.media.session.RouteInfo;
+import android.media.session.RouteOptions;
import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
@@ -38,21 +41,77 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final SessionManagerImpl mSessionManagerImpl;
+ private final MediaRouteProviderWatcher mRouteProviderWatcher;
private final ArrayList<MediaSessionRecord> mSessions
= new ArrayList<MediaSessionRecord>();
+ private final ArrayList<MediaRouteProviderProxy> mProviders
+ = new ArrayList<MediaRouteProviderProxy>();
private final Object mLock = new Object();
// TODO do we want a separate thread for handling mediasession messages?
private final Handler mHandler = new Handler();
+ // Used to keep track of the current request to show routes for a specific
+ // session so we drop late callbacks properly.
+ private int mShowRoutesRequestId = 0;
+
+ // TODO refactor to have per user state. See MediaRouterService for an
+ // example
+
public MediaSessionService(Context context) {
super(context);
mSessionManagerImpl = new SessionManagerImpl();
+ mRouteProviderWatcher = new MediaRouteProviderWatcher(context, mProviderWatcherCallback,
+ mHandler, context.getUserId());
}
@Override
public void onStart() {
publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
+ mRouteProviderWatcher.start();
+ }
+
+ /**
+ * Should trigger showing the Media route picker dialog. Right now it just
+ * kicks off a query to all the providers to get routes.
+ *
+ * @param record The session to show the picker for.
+ */
+ public void showRoutePickerForSession(MediaSessionRecord record) {
+ // TODO for now just toggle the route to test (we will only have one
+ // match for now)
+ if (record.getRoute() != null) {
+ // For now send null to mean the local route
+ record.selectRoute(null);
+ return;
+ }
+ mShowRoutesRequestId++;
+ ArrayList<MediaRouteProviderProxy> providers = mRouteProviderWatcher.getProviders();
+ for (int i = providers.size() - 1; i >= 0; i--) {
+ MediaRouteProviderProxy provider = providers.get(i);
+ provider.getRoutes(record, mShowRoutesRequestId);
+ }
+ }
+
+ /**
+ * Connect a session to the given route.
+ *
+ * @param session The session to connect.
+ * @param route The route to connect to.
+ * @param options The options to use for the connection.
+ */
+ public void connectToRoute(MediaSessionRecord session, RouteInfo route,
+ RouteOptions options) {
+ synchronized (mLock) {
+ MediaRouteProviderProxy proxy = getProviderLocked(route.getProvider());
+ if (proxy == null) {
+ Log.w(TAG, "Provider for route " + route.getName() + " does not exist.");
+ return;
+ }
+ RouteRequest request = new RouteRequest(session.getSessionInfo(), options, true);
+ // TODO make connect an async call to a ThreadPoolExecutor
+ proxy.connectToRoute(session, route, request);
+ }
}
void sessionDied(MediaSessionRecord session) {
@@ -86,14 +145,14 @@
}
private MediaSessionRecord createSessionInternal(int pid, String packageName,
- IMediaSessionCallback cb, String tag) {
+ ISessionCallback cb, String tag) {
synchronized (mLock) {
return createSessionLocked(pid, packageName, cb, tag);
}
}
private MediaSessionRecord createSessionLocked(int pid, String packageName,
- IMediaSessionCallback cb, String tag) {
+ ISessionCallback cb, String tag) {
final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this,
mHandler);
try {
@@ -110,9 +169,82 @@
return session;
}
- class SessionManagerImpl extends IMediaSessionManager.Stub {
+ private MediaRouteProviderProxy getProviderLocked(String providerId) {
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ MediaRouteProviderProxy provider = mProviders.get(i);
+ if (TextUtils.equals(providerId, provider.getId())) {
+ return provider;
+ }
+ }
+ return null;
+ }
+
+ private int findIndexOfSessionForIdLocked(String sessionId) {
+ for (int i = mSessions.size() - 1; i >= 0; i--) {
+ MediaSessionRecord session = mSessions.get(i);
+ if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private MediaRouteProviderWatcher.Callback mProviderWatcherCallback
+ = new MediaRouteProviderWatcher.Callback() {
@Override
- public IMediaSession createSession(String packageName, IMediaSessionCallback cb, String tag)
+ public void removeProvider(MediaRouteProviderProxy provider) {
+ synchronized (mLock) {
+ mProviders.remove(provider);
+ provider.setRoutesListener(null);
+ provider.setInterested(false);
+ }
+ }
+
+ @Override
+ public void addProvider(MediaRouteProviderProxy provider) {
+ synchronized (mLock) {
+ mProviders.add(provider);
+ provider.setRoutesListener(mRoutesCallback);
+ provider.setInterested(true);
+ }
+ }
+ };
+
+ private MediaRouteProviderProxy.RoutesListener mRoutesCallback
+ = new MediaRouteProviderProxy.RoutesListener() {
+ @Override
+ public void onRoutesUpdated(String sessionId, ArrayList<RouteInfo> routes,
+ int reqId) {
+ // TODO for now select the first route to test, eventually add the
+ // new routes to the dialog if it is still open
+ synchronized (mLock) {
+ int index = findIndexOfSessionForIdLocked(sessionId);
+ if (index != -1 && routes != null && routes.size() > 0) {
+ MediaSessionRecord record = mSessions.get(index);
+ record.selectRoute(routes.get(0));
+ }
+ }
+ }
+
+ @Override
+ public void onRouteConnected(String sessionId, RouteInfo route,
+ RouteRequest options, RouteConnectionRecord connection) {
+ synchronized (mLock) {
+ int index = findIndexOfSessionForIdLocked(sessionId);
+ if (index != -1) {
+ MediaSessionRecord session = mSessions.get(index);
+ session.setRouteConnected(route, options.getConnectionOptions(), connection);
+ }
+ }
+ }
+ };
+
+ class SessionManagerImpl extends ISessionManager.Stub {
+ // TODO add createSessionAsUser, pass user-id to
+ // ActivityManagerNative.handleIncomingUser and stash result for use
+ // when starting services on that session's behalf.
+ @Override
+ public ISession createSession(String packageName, ISessionCallback cb, String tag)
throws RemoteException {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/media/RouteConnectionRecord.java b/services/core/java/com/android/server/media/RouteConnectionRecord.java
new file mode 100644
index 0000000..8da0f95
--- /dev/null
+++ b/services/core/java/com/android/server/media/RouteConnectionRecord.java
@@ -0,0 +1,108 @@
+/*
+ * 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.server.media;
+
+import android.media.routeprovider.IRouteConnection;
+import android.media.session.RouteCommand;
+import android.media.session.RouteEvent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+/**
+ * A connection between a Session and a Route.
+ */
+public class RouteConnectionRecord {
+ private static final String TAG = "RouteConnRecord";
+ private final IRouteConnection mBinder;
+ private Listener mListener;
+
+ public RouteConnectionRecord(IRouteConnection binder) {
+ mBinder = binder;
+ }
+
+ /**
+ * Add a listener to get route events on.
+ *
+ * @param listener The listener to get events on.
+ */
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Check if this connection matches the token given.
+ *
+ * @param binder The token to check
+ * @return True if this is the connection you're looking for, false
+ * otherwise.
+ */
+ public boolean isConnection(IBinder binder) {
+ return binder != null && binder.equals(mBinder.asBinder());
+ }
+
+ /**
+ * Send an event from this connection.
+ *
+ * @param event The event to send.
+ */
+ public void sendEvent(RouteEvent event) {
+ if (mListener != null) {
+ mListener.onEvent(event);
+ }
+ }
+
+ /**
+ * Send a command to this connection.
+ *
+ * @param command The command to send.
+ * @param cb The receiver to get a result on.
+ */
+ public void sendCommand(RouteCommand command, ResultReceiver cb) {
+ try {
+ mBinder.onCommand(command, cb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in sendCommand", e);
+ }
+ }
+
+ /**
+ * Tell the session that the provider has disconnected it.
+ */
+ public void disconnect() {
+ if (mListener != null) {
+ mListener.disconnect();
+ }
+ }
+
+ /**
+ * Listener to receive updates from the provider for this connection.
+ */
+ public static interface Listener {
+ /**
+ * Called when an event is sent on this connection.
+ *
+ * @param event The event that was sent.
+ */
+ public void onEvent(RouteEvent event);
+
+ /**
+ * Called when the provider has disconnected the route.
+ */
+ public void disconnect();
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
new file mode 100644
index 0000000..29af433
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -0,0 +1,257 @@
+/**
+ * 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.server.notification;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import libcore.util.Objects;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+public class ConditionProviders extends ManagedServices {
+
+ private final ZenModeHelper mZenModeHelper;
+ private final ArrayMap<IBinder, IConditionListener> mListeners
+ = new ArrayMap<IBinder, IConditionListener>();
+ private final ArrayMap<Uri, ManagedServiceInfo> mConditions
+ = new ArrayMap<Uri, ManagedServiceInfo>();
+
+ private Uri mCurrentConditionId;
+
+ public ConditionProviders(Context context, Handler handler,
+ UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
+ super(context, handler, new Object(), userProfiles);
+ mZenModeHelper = zenModeHelper;
+ mZenModeHelper.addCallback(new ZenModeHelperCallback());
+ }
+
+ @Override
+ protected Config getConfig() {
+ Config c = new Config();
+ c.caption = "condition provider";
+ c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
+ c.secureSettingName = Settings.Secure.ENABLED_CONDITION_PROVIDERS;
+ c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
+ c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS;
+ c.clientLabel = R.string.condition_provider_service_binding_label;
+ return c;
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ super.dump(pw);
+ synchronized(mMutex) {
+ pw.print(" mCurrentConditionId="); pw.println(mCurrentConditionId);
+ pw.print(" mListeners("); pw.print(mListeners.size()); pw.println("):");
+ for (int i = 0; i < mListeners.size(); i++) {
+ pw.print(" "); pw.println(mListeners.keyAt(i));
+ }
+ pw.print(" mConditions("); pw.print(mConditions.size()); pw.println("):");
+ for (int i = 0; i < mConditions.size(); i++) {
+ pw.print(" "); pw.print(mConditions.keyAt(i));
+ final ManagedServiceInfo info = mConditions.valueAt(i);
+ pw.print(" -> "); pw.print(info.component);
+ if (!mServices.contains(info)) {
+ pw.print(" (orphan)");
+ }
+ pw.println();
+ }
+ }
+ }
+
+ @Override
+ protected IInterface asInterface(IBinder binder) {
+ return IConditionProvider.Stub.asInterface(binder);
+ }
+
+ @Override
+ protected void onServiceAdded(IInterface service) {
+ Slog.d(TAG, "onServiceAdded " + service);
+ final IConditionProvider provider = (IConditionProvider) service;
+ try {
+ provider.onConnected();
+ } catch (RemoteException e) {
+ // we tried
+ }
+ }
+
+ @Override
+ protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
+ if (removed == null) return;
+ for (int i = mConditions.size() - 1; i >= 0; i--) {
+ if (removed.equals(mConditions.valueAt(i))) {
+ mConditions.removeAt(i);
+ }
+ }
+ }
+
+ public ManagedServiceInfo checkServiceToken(IConditionProvider provider) {
+ synchronized(mMutex) {
+ return checkServiceTokenLocked(provider);
+ }
+ }
+
+ public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback
+ + " requested=" + requested);
+ if (callback == null) return;
+ if (requested) {
+ mListeners.put(callback.asBinder(), callback);
+ requestConditionsLocked(Condition.FLAG_RELEVANT_NOW);
+ } else {
+ mListeners.remove(callback.asBinder());
+ if (mListeners.isEmpty()) {
+ requestConditionsLocked(0);
+ }
+ }
+ }
+ }
+
+ public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions="
+ + (conditions == null ? null : Arrays.asList(conditions)));
+ if (conditions == null || conditions.length == 0) return;
+ final int N = conditions.length;
+ boolean valid = true;
+ for (int i = 0; i < N; i++) {
+ final Uri id = conditions[i].id;
+ if (!Condition.isValidId(id, pkg)) {
+ Slog.w(TAG, "Ignoring conditions from " + pkg + " for invalid id: " + id);
+ valid = false;
+ }
+ }
+ if (!valid) return;
+
+ for (int i = 0; i < N; i++) {
+ mConditions.put(conditions[i].id, info);
+ }
+ for (IConditionListener listener : mListeners.values()) {
+ try {
+ listener.onConditionsReceived(conditions);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error sending conditions to listener " + listener, e);
+ }
+ }
+ if (mCurrentConditionId != null) {
+ for (int i = 0; i < N; i++) {
+ final Condition c = conditions[i];
+ if (!c.id.equals(mCurrentConditionId)) continue;
+ if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_ERROR) {
+ triggerExitLocked(c.state == Condition.STATE_ERROR);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private void triggerExitLocked(boolean error) {
+ if (error) {
+ Slog.w(TAG, "Zen mode exit condition failed");
+ } else if (DEBUG) {
+ Slog.d(TAG, "Zen mode exit condition triggered");
+ }
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ unsubscribeLocked(mCurrentConditionId);
+ mCurrentConditionId = null;
+ }
+
+ public void setZenModeCondition(Uri conditionId) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
+ if (Objects.equal(mCurrentConditionId, conditionId)) return;
+
+ if (mCurrentConditionId != null) {
+ unsubscribeLocked(mCurrentConditionId);
+ }
+ if (conditionId != null) {
+ final ManagedServiceInfo info = mConditions.get(conditionId);
+ final IConditionProvider provider = provider(info);
+ if (provider == null) return;
+ try {
+ provider.onSubscribe(conditionId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error subscribing to " + conditionId
+ + " from " + info.component, e);
+ }
+ }
+ mCurrentConditionId = conditionId;
+ }
+ }
+
+ private void unsubscribeLocked(Uri conditionId) {
+ final ManagedServiceInfo info = mConditions.get(mCurrentConditionId);
+ final IConditionProvider provider = provider(info);
+ if (provider == null) return;
+ try {
+ provider.onUnsubscribe(conditionId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, e);
+ }
+ }
+
+ private static IConditionProvider provider(ManagedServiceInfo info) {
+ return info == null ? null : (IConditionProvider) info.service;
+ }
+
+ private void requestConditionsLocked(int flags) {
+ for (ManagedServiceInfo info : mServices) {
+ final IConditionProvider provider = provider(info);
+ if (provider == null) continue;
+ try {
+ provider.onRequestConditions(flags);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error requesting conditions from " + info.component, e);
+ }
+ }
+ }
+
+ private class ZenModeHelperCallback extends ZenModeHelper.Callback {
+ @Override
+ void onZenModeChanged() {
+ final int mode = mZenModeHelper.getZenMode();
+ if (mode == Global.ZEN_MODE_OFF) {
+ synchronized (mMutex) {
+ if (mCurrentConditionId != null) {
+ if (DEBUG) Slog.d(TAG, "Zen mode off, forcing unsubscribe from "
+ + mCurrentConditionId);
+ unsubscribeLocked(mCurrentConditionId);
+ mCurrentConditionId = null;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
new file mode 100644
index 0000000..0621f58
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -0,0 +1,621 @@
+/**
+ * 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.server.notification;
+
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Manages the lifecycle of application-provided services bound by system server.
+ *
+ * Services managed by this helper must have:
+ * - An associated system settings value with a list of enabled component names.
+ * - A well-known action for services to use in their intent-filter.
+ * - A system permission for services to require in order to ensure system has exclusive binding.
+ * - A settings page for user configuration of enabled services, and associated intent action.
+ * - A remote interface definition (aidl) provided by the service used for communication.
+ */
+abstract public class ManagedServices {
+ protected final String TAG = getClass().getSimpleName();
+ protected static final boolean DEBUG = true;
+
+ private static final String ENABLED_SERVICES_SEPARATOR = ":";
+
+ private final Context mContext;
+ protected final Object mMutex;
+ private final UserProfiles mUserProfiles;
+ private final SettingsObserver mSettingsObserver;
+ private final Config mConfig;
+
+ // contains connections to all connected services, including app services
+ // and system services
+ protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
+ // things that will be put into mServices as soon as they're ready
+ private final ArrayList<String> mServicesBinding = new ArrayList<String>();
+ // lists the component names of all enabled (and therefore connected)
+ // app services for current profiles.
+ private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
+ = new ArraySet<ComponentName>();
+ // Just the packages from mEnabledServicesForCurrentProfiles
+ private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<String>();
+
+ public ManagedServices(Context context, Handler handler, Object mutex,
+ UserProfiles userProfiles) {
+ mContext = context;
+ mMutex = mutex;
+ mUserProfiles = userProfiles;
+ mConfig = getConfig();
+ mSettingsObserver = new SettingsObserver(handler);
+ }
+
+ abstract protected Config getConfig();
+
+ private String getCaption() {
+ return mConfig.caption;
+ }
+
+ abstract protected IInterface asInterface(IBinder binder);
+
+ abstract protected void onServiceAdded(IInterface service);
+
+ protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
+
+ private ManagedServiceInfo newServiceInfo(IInterface service,
+ ComponentName component, int userid, boolean isSystem, ServiceConnection connection,
+ int targetSdkVersion) {
+ return new ManagedServiceInfo(service, component, userid, isSystem, connection,
+ targetSdkVersion);
+ }
+
+ public void onBootPhaseAppsCanStart() {
+ mSettingsObserver.observe();
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
+ + ") enabled for current profiles:");
+ for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
+ pw.println(" " + cmpt);
+ }
+
+ pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
+ for (ManagedServiceInfo info : mServices) {
+ pw.println(" " + info.component
+ + " (user " + info.userid + "): " + info.service
+ + (info.isSystem?" SYSTEM":""));
+ }
+ }
+
+ public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
+ if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
+ + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
+ + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
+ boolean anyServicesInvolved = false;
+ if (pkgList != null && (pkgList.length > 0)) {
+ for (String pkgName : pkgList) {
+ if (mEnabledServicesPackageNames.contains(pkgName)) {
+ anyServicesInvolved = true;
+ }
+ }
+ }
+
+ if (anyServicesInvolved) {
+ // if we're not replacing a package, clean up orphaned bits
+ if (!queryReplace) {
+ disableNonexistentServices();
+ }
+ // make sure we're still bound to any of our services who may have just upgraded
+ rebindServices();
+ }
+ }
+
+ public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
+ checkNotNull(service);
+ final IBinder token = service.asBinder();
+ final int N = mServices.size();
+ for (int i=0; i<N; i++) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (info.service.asBinder() == token) return info;
+ }
+ throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
+ + service);
+ }
+
+ public void unregisterService(IInterface service, int userid) {
+ checkNotNull(service);
+ // no need to check permissions; if your service binder is in the list,
+ // that's proof that you had permission to add it in the first place
+ unregisterServiceImpl(service, userid);
+ }
+
+ public void registerService(IInterface service, ComponentName component, int userid) {
+ checkNotNull(service);
+ registerServiceImpl(service, component, userid);
+ }
+
+ /**
+ * Remove access for any services that no longer exist.
+ */
+ private void disableNonexistentServices() {
+ int[] userIds = mUserProfiles.getCurrentProfileIds();
+ final int N = userIds.length;
+ for (int i = 0 ; i < N; ++i) {
+ disableNonexistentServices(userIds[i]);
+ }
+ }
+
+ private void disableNonexistentServices(int userId) {
+ String flatIn = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ mConfig.secureSettingName,
+ userId);
+ if (!TextUtils.isEmpty(flatIn)) {
+ if (DEBUG) Slog.v(TAG, "flat before: " + flatIn);
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
+ new Intent(mConfig.serviceInterface),
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+ userId);
+ if (DEBUG) Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
+ Set<ComponentName> installed = new ArraySet<ComponentName>();
+ for (int i = 0, count = installedServices.size(); i < count; i++) {
+ ResolveInfo resolveInfo = installedServices.get(i);
+ ServiceInfo info = resolveInfo.serviceInfo;
+
+ if (!mConfig.bindPermission.equals(info.permission)) {
+ Slog.w(TAG, "Skipping " + getCaption() + " service "
+ + info.packageName + "/" + info.name
+ + ": it does not require the permission "
+ + mConfig.bindPermission);
+ continue;
+ }
+ installed.add(new ComponentName(info.packageName, info.name));
+ }
+
+ String flatOut = "";
+ if (!installed.isEmpty()) {
+ String[] enabled = flatIn.split(ENABLED_SERVICES_SEPARATOR);
+ ArrayList<String> remaining = new ArrayList<String>(enabled.length);
+ for (int i = 0; i < enabled.length; i++) {
+ ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]);
+ if (installed.contains(enabledComponent)) {
+ remaining.add(enabled[i]);
+ }
+ }
+ flatOut = TextUtils.join(ENABLED_SERVICES_SEPARATOR, remaining);
+ }
+ if (DEBUG) Slog.v(TAG, "flat after: " + flatOut);
+ if (!flatIn.equals(flatOut)) {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ mConfig.secureSettingName,
+ flatOut, userId);
+ }
+ }
+ }
+
+ /**
+ * Called whenever packages change, the user switches, or the secure setting
+ * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
+ */
+ private void rebindServices() {
+ if (DEBUG) Slog.d(TAG, "rebindServices");
+ final int[] userIds = mUserProfiles.getCurrentProfileIds();
+ final int nUserIds = userIds.length;
+
+ final SparseArray<String> flat = new SparseArray<String>();
+
+ for (int i = 0; i < nUserIds; ++i) {
+ flat.put(userIds[i], Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ mConfig.secureSettingName,
+ userIds[i]));
+ }
+
+ ManagedServiceInfo[] toRemove = new ManagedServiceInfo[mServices.size()];
+ final SparseArray<ArrayList<ComponentName>> toAdd
+ = new SparseArray<ArrayList<ComponentName>>();
+
+ synchronized (mMutex) {
+ // unbind and remove all existing services
+ toRemove = mServices.toArray(toRemove);
+
+ final ArraySet<ComponentName> newEnabled = new ArraySet<ComponentName>();
+ final ArraySet<String> newPackages = new ArraySet<String>();
+
+ for (int i = 0; i < nUserIds; ++i) {
+ final ArrayList<ComponentName> add = new ArrayList<ComponentName>();
+ toAdd.put(userIds[i], add);
+
+ // decode the list of components
+ String toDecode = flat.get(userIds[i]);
+ if (toDecode != null) {
+ String[] components = toDecode.split(ENABLED_SERVICES_SEPARATOR);
+ for (int j = 0; j < components.length; j++) {
+ final ComponentName component
+ = ComponentName.unflattenFromString(components[j]);
+ if (component != null) {
+ newEnabled.add(component);
+ add.add(component);
+ newPackages.add(component.getPackageName());
+ }
+ }
+
+ }
+ }
+ mEnabledServicesForCurrentProfiles = newEnabled;
+ mEnabledServicesPackageNames = newPackages;
+ }
+
+ for (ManagedServiceInfo info : toRemove) {
+ final ComponentName component = info.component;
+ final int oldUser = info.userid;
+ Slog.v(TAG, "disabling " + getCaption() + " for user "
+ + oldUser + ": " + component);
+ unregisterService(component, info.userid);
+ }
+
+ for (int i = 0; i < nUserIds; ++i) {
+ final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
+ final int N = add.size();
+ for (int j = 0; j < N; j++) {
+ final ComponentName component = add.get(j);
+ Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
+ + component);
+ registerService(component, userIds[i]);
+ }
+ }
+ }
+
+ /**
+ * Version of registerService that takes the name of a service component to bind to.
+ */
+ private void registerService(final ComponentName name, final int userid) {
+ if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
+
+ synchronized (mMutex) {
+ final String servicesBindingTag = name.toString() + "/" + userid;
+ if (mServicesBinding.contains(servicesBindingTag)) {
+ // stop registering this thing already! we're working on it
+ return;
+ }
+ mServicesBinding.add(servicesBindingTag);
+
+ final int N = mServices.size();
+ for (int i=N-1; i>=0; i--) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (name.equals(info.component)
+ && info.userid == userid) {
+ // cut old connections
+ if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
+ + info.service);
+ removeServiceLocked(i);
+ if (info.connection != null) {
+ mContext.unbindService(info.connection);
+ }
+ }
+ }
+
+ Intent intent = new Intent(mConfig.serviceInterface);
+ intent.setComponent(name);
+
+ intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
+
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ mContext, 0, new Intent(mConfig.settingsAction), 0);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
+
+ ApplicationInfo appInfo = null;
+ try {
+ appInfo = mContext.getPackageManager().getApplicationInfo(
+ name.getPackageName(), 0);
+ } catch (NameNotFoundException e) {
+ // Ignore if the package doesn't exist we won't be able to bind to the service.
+ }
+ final int targetSdkVersion =
+ appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
+
+ try {
+ if (DEBUG) Slog.v(TAG, "binding: " + intent);
+ if (!mContext.bindServiceAsUser(intent,
+ new ServiceConnection() {
+ IInterface mService;
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder binder) {
+ boolean added = false;
+ synchronized (mMutex) {
+ mServicesBinding.remove(servicesBindingTag);
+ try {
+ mService = asInterface(binder);
+ ManagedServiceInfo info = newServiceInfo(mService, name,
+ userid, false /*isSystem*/, this, targetSdkVersion);
+ binder.linkToDeath(info, 0);
+ added = mServices.add(info);
+ } catch (RemoteException e) {
+ // already dead
+ }
+ }
+ if (added) {
+ onServiceAdded(mService);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Slog.v(TAG, getCaption() + " connection lost: " + name);
+ }
+ },
+ Context.BIND_AUTO_CREATE,
+ new UserHandle(userid)))
+ {
+ mServicesBinding.remove(servicesBindingTag);
+ Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
+ return;
+ }
+ } catch (SecurityException ex) {
+ Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Remove a service for the given user by ComponentName
+ */
+ private void unregisterService(ComponentName name, int userid) {
+ synchronized (mMutex) {
+ final int N = mServices.size();
+ for (int i=N-1; i>=0; i--) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (name.equals(info.component)
+ && info.userid == userid) {
+ removeServiceLocked(i);
+ if (info.connection != null) {
+ try {
+ mContext.unbindService(info.connection);
+ } catch (IllegalArgumentException ex) {
+ // something happened to the service: we think we have a connection
+ // but it's bogus.
+ Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a service from the list but does not unbind
+ *
+ * @return the removed service.
+ */
+ private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
+ if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
+ ManagedServiceInfo serviceInfo = null;
+ synchronized (mMutex) {
+ final int N = mServices.size();
+ for (int i=N-1; i>=0; i--) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (info.service.asBinder() == service.asBinder()
+ && info.userid == userid) {
+ if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
+ serviceInfo = removeServiceLocked(i);
+ }
+ }
+ }
+ return serviceInfo;
+ }
+
+ private ManagedServiceInfo removeServiceLocked(int i) {
+ final ManagedServiceInfo info = mServices.remove(i);
+ onServiceRemovedLocked(info);
+ return info;
+ }
+
+ private void checkNotNull(IInterface service) {
+ if (service == null) {
+ throw new IllegalArgumentException(getCaption() + " must not be null");
+ }
+ }
+
+ private void registerServiceImpl(final IInterface service,
+ final ComponentName component, final int userid) {
+ synchronized (mMutex) {
+ try {
+ ManagedServiceInfo info = newServiceInfo(service, component, userid,
+ true /*isSystem*/, null, Build.VERSION_CODES.L);
+ service.asBinder().linkToDeath(info, 0);
+ mServices.add(info);
+ } catch (RemoteException e) {
+ // already dead
+ }
+ }
+ }
+
+ /**
+ * Removes a service from the list and unbinds.
+ */
+ private void unregisterServiceImpl(IInterface service, int userid) {
+ ManagedServiceInfo info = removeServiceImpl(service, userid);
+ if (info != null && info.connection != null) {
+ mContext.unbindService(info.connection);
+ }
+ }
+
+ private class SettingsObserver extends ContentObserver {
+ private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
+
+ private SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ private void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(mSecureSettingsUri,
+ false, this, UserHandle.USER_ALL);
+ update(null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update(uri);
+ }
+
+ private void update(Uri uri) {
+ if (uri == null || mSecureSettingsUri.equals(uri)) {
+ rebindServices();
+ }
+ }
+ }
+
+ public class ManagedServiceInfo implements IBinder.DeathRecipient {
+ public IInterface service;
+ public ComponentName component;
+ public int userid;
+ public boolean isSystem;
+ public ServiceConnection connection;
+ public int targetSdkVersion;
+
+ public ManagedServiceInfo(IInterface service, ComponentName component,
+ int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
+ this.service = service;
+ this.component = component;
+ this.userid = userid;
+ this.isSystem = isSystem;
+ this.connection = connection;
+ this.targetSdkVersion = targetSdkVersion;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("ManagedServiceInfo[")
+ .append("component=").append(component)
+ .append(",userid=").append(userid)
+ .append(",isSystem=").append(isSystem)
+ .append(",targetSdkVersion=").append(targetSdkVersion)
+ .append(",connection=").append(connection == null ? null : "<connection>")
+ .append(",service=").append(service)
+ .append(']').toString();
+ }
+
+ public boolean enabledAndUserMatches(int nid) {
+ if (!isEnabledForCurrentProfiles()) {
+ return false;
+ }
+ if (this.userid == UserHandle.USER_ALL) return true;
+ if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
+ return supportsProfiles() && mUserProfiles.isCurrentProfile(nid);
+ }
+
+ public boolean supportsProfiles() {
+ return targetSdkVersion >= Build.VERSION_CODES.L;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) Slog.d(TAG, "binderDied");
+ // Remove the service, but don't unbind from the service. The system will bring the
+ // service back up, and the onServiceConnected handler will readd the service with the
+ // new binding. If this isn't a bound service, and is just a registered
+ // service, just removing it from the list is all we need to do anyway.
+ removeServiceImpl(this.service, this.userid);
+ }
+
+ /** convenience method for looking in mEnabledServicesForCurrentProfiles */
+ public boolean isEnabledForCurrentProfiles() {
+ if (this.isSystem) return true;
+ if (this.connection == null) return false;
+ return mEnabledServicesForCurrentProfiles.contains(this.component);
+ }
+ }
+
+ public static class UserProfiles {
+ // Profiles of the current user.
+ private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
+
+ public void updateCache(Context context) {
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ if (userManager != null) {
+ int currentUserId = ActivityManager.getCurrentUser();
+ List<UserInfo> profiles = userManager.getProfiles(currentUserId);
+ synchronized (mCurrentProfiles) {
+ mCurrentProfiles.clear();
+ for (UserInfo user : profiles) {
+ mCurrentProfiles.put(user.id, user);
+ }
+ }
+ }
+ }
+
+ public int[] getCurrentProfileIds() {
+ synchronized (mCurrentProfiles) {
+ int[] users = new int[mCurrentProfiles.size()];
+ final int N = mCurrentProfiles.size();
+ for (int i = 0; i < N; ++i) {
+ users[i] = mCurrentProfiles.keyAt(i);
+ }
+ return users;
+ }
+ }
+
+ public boolean isCurrentProfile(int userId) {
+ synchronized (mCurrentProfiles) {
+ return mCurrentProfiles.get(userId) != null;
+ }
+ }
+ }
+
+ protected static class Config {
+ String caption;
+ String serviceInterface;
+ String secureSettingName;
+ String bindPermission;
+ String settingsAction;
+ int clientLabel;
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5b597a3..6e4eb565 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -36,14 +36,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -51,26 +47,29 @@
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
+import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IInterface;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.INotificationListener;
+import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
+import android.service.notification.Condition;
+import android.service.notification.ZenModeConfig;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.Xml;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -78,20 +77,27 @@
import com.android.internal.R;
import com.android.internal.notification.NotificationScorer;
+import com.android.internal.util.FastXmlSerializer;
import com.android.server.EventLogTags;
-import com.android.server.notification.NotificationUsageStats.SingleNotificationStats;
-import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.SystemService;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+import com.android.server.notification.ManagedServices.ManagedServiceInfo;
+import com.android.server.notification.ManagedServices.UserProfiles;
+import com.android.server.notification.NotificationUsageStats.SingleNotificationStats;
+import com.android.server.statusbar.StatusBarManagerInternal;
+
+import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Array;
@@ -100,11 +106,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.NoSuchElementException;
-import java.util.Set;
-
-import libcore.io.IoUtils;
/** {@hide} */
public class NotificationManagerService extends SystemService {
@@ -115,6 +117,7 @@
// message codes
static final int MESSAGE_TIMEOUT = 2;
+ static final int MESSAGE_SAVE_POLICY_FILE = 3;
static final int LONG_DELAY = 3500; // 3.5 seconds
static final int SHORT_DELAY = 2000; // 2 seconds
@@ -137,8 +140,6 @@
static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
static final boolean ENABLE_BLOCKED_TOASTS = true;
- static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
-
private IActivityManager mAm;
AudioManager mAudioManager;
StatusBarManagerInternal mStatusBar;
@@ -179,19 +180,6 @@
private AppOpsManager mAppOps;
- // contains connections to all connected listeners, including app services
- // and system listeners
- private ArrayList<NotificationListenerInfo> mListeners
- = new ArrayList<NotificationListenerInfo>();
- // things that will be put into mListeners as soon as they're ready
- private ArrayList<String> mServicesBinding = new ArrayList<String>();
- // lists the component names of all enabled (and therefore connected) listener
- // app services for current profiles.
- private HashSet<ComponentName> mEnabledListenersForCurrentProfiles
- = new HashSet<ComponentName>();
- // Just the packages from mEnabledListenersForCurrentProfiles
- private HashSet<String> mEnabledListenerPackageNames = new HashSet<String>();
-
// Notification control database. For now just contains disabled packages.
private AtomicFile mPolicyFile;
private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -207,22 +195,14 @@
final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+ private final UserProfiles mUserProfiles = new UserProfiles();
+ private NotificationListeners mListeners;
+ private ConditionProviders mConditionProviders;
+
private final NotificationUsageStats mUsageStats = new NotificationUsageStats();
- private int mZenMode;
- // temporary, until we update apps to provide metadata
- private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList(
- "com.google.android.dialer",
- "com.android.phone"
- ));
- private static final Set<String> ALARM_PACKAGES = new HashSet<String>(Arrays.asList(
- "com.google.android.deskclock"
- ));
private static final String EXTRA_INTERCEPT = "android.intercept";
- // Profiles of the current user.
- final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
-
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
private static final int REASON_DELEGATE_CLICK = 1;
@@ -237,85 +217,6 @@
private static final int REASON_LISTENER_CANCEL = 10;
private static final int REASON_LISTENER_CANCEL_ALL = 11;
- private class NotificationListenerInfo implements IBinder.DeathRecipient {
- INotificationListener listener;
- ComponentName component;
- int userid;
- boolean isSystem;
- ServiceConnection connection;
- int targetSdkVersion;
-
- public NotificationListenerInfo(INotificationListener listener, ComponentName component,
- int userid, boolean isSystem, int targetSdkVersion) {
- this.listener = listener;
- this.component = component;
- this.userid = userid;
- this.isSystem = isSystem;
- this.connection = null;
- this.targetSdkVersion = targetSdkVersion;
- }
-
- public NotificationListenerInfo(INotificationListener listener, ComponentName component,
- int userid, ServiceConnection connection, int targetSdkVersion) {
- this.listener = listener;
- this.component = component;
- this.userid = userid;
- this.isSystem = false;
- this.connection = connection;
- this.targetSdkVersion = targetSdkVersion;
- }
-
- boolean enabledAndUserMatches(StatusBarNotification sbn) {
- final int nid = sbn.getUserId();
- if (!isEnabledForCurrentProfiles()) {
- return false;
- }
- if (this.userid == UserHandle.USER_ALL) return true;
- if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
- return supportsProfiles() && isCurrentProfile(nid);
- }
-
- boolean supportsProfiles() {
- return targetSdkVersion >= Build.VERSION_CODES.L;
- }
-
- public void notifyPostedIfUserMatch(StatusBarNotification sbn) {
- if (!enabledAndUserMatches(sbn)) {
- return;
- }
- try {
- listener.onNotificationPosted(sbn);
- } catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
- }
- }
-
- public void notifyRemovedIfUserMatch(StatusBarNotification sbn) {
- if (!enabledAndUserMatches(sbn)) return;
- try {
- listener.onNotificationRemoved(sbn);
- } catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
- }
- }
-
- @Override
- public void binderDied() {
- // Remove the listener, but don't unbind from the service. The system will bring the
- // service back up, and the onServiceConnected handler will readd the listener with the
- // new binding. If this isn't a bound service, and is just a registered
- // INotificationListener, just removing it from the list is all we need to do anyway.
- removeListenerImpl(this.listener, this.userid);
- }
-
- /** convenience method for looking in mEnabledListenersForCurrentProfiles */
- public boolean isEnabledForCurrentProfiles() {
- if (this.isSystem) return true;
- if (this.connection == null) return false;
- return mEnabledListenersForCurrentProfiles.contains(this.component);
- }
- }
-
private static class Archive {
static final int BUFFER_SIZE = 250;
ArrayDeque<StatusBarNotification> mBuffer = new ArrayDeque<StatusBarNotification>(BUFFER_SIZE);
@@ -421,53 +322,82 @@
Archive mArchive = new Archive();
- private void loadBlockDb() {
- synchronized(mBlockedPackages) {
- if (mPolicyFile == null) {
- File dir = new File("/data/system");
- mPolicyFile = new AtomicFile(new File(dir, "notification_policy.xml"));
+ private void loadPolicyFile() {
+ synchronized(mPolicyFile) {
+ mBlockedPackages.clear();
- mBlockedPackages.clear();
+ FileInputStream infile = null;
+ try {
+ infile = mPolicyFile.openRead();
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(infile, null);
- FileInputStream infile = null;
- try {
- infile = mPolicyFile.openRead();
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(infile, null);
-
- int type;
- String tag;
- int version = DB_VERSION;
- while ((type = parser.next()) != END_DOCUMENT) {
- tag = parser.getName();
- if (type == START_TAG) {
- if (TAG_BODY.equals(tag)) {
- version = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VERSION));
- } else if (TAG_BLOCKED_PKGS.equals(tag)) {
- while ((type = parser.next()) != END_DOCUMENT) {
- tag = parser.getName();
- if (TAG_PACKAGE.equals(tag)) {
- mBlockedPackages.add(
- parser.getAttributeValue(null, ATTR_NAME));
- } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
- break;
- }
+ int type;
+ String tag;
+ int version = DB_VERSION;
+ while ((type = parser.next()) != END_DOCUMENT) {
+ tag = parser.getName();
+ if (type == START_TAG) {
+ if (TAG_BODY.equals(tag)) {
+ version = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_VERSION));
+ } else if (TAG_BLOCKED_PKGS.equals(tag)) {
+ while ((type = parser.next()) != END_DOCUMENT) {
+ tag = parser.getName();
+ if (TAG_PACKAGE.equals(tag)) {
+ mBlockedPackages.add(
+ parser.getAttributeValue(null, ATTR_NAME));
+ } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
+ break;
}
}
}
}
- } catch (FileNotFoundException e) {
- // No data yet
- } catch (IOException e) {
- Log.wtf(TAG, "Unable to read blocked notifications database", e);
- } catch (NumberFormatException e) {
- Log.wtf(TAG, "Unable to parse blocked notifications database", e);
- } catch (XmlPullParserException e) {
- Log.wtf(TAG, "Unable to parse blocked notifications database", e);
- } finally {
- IoUtils.closeQuietly(infile);
+ mZenModeHelper.readXml(parser);
}
+ } catch (FileNotFoundException e) {
+ // No data yet
+ } catch (IOException e) {
+ Log.wtf(TAG, "Unable to read notification policy", e);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Unable to parse notification policy", e);
+ } catch (XmlPullParserException e) {
+ Log.wtf(TAG, "Unable to parse notification policy", e);
+ } finally {
+ IoUtils.closeQuietly(infile);
+ }
+ }
+ }
+
+ public void savePolicyFile() {
+ mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
+ mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
+ }
+
+ private void handleSavePolicyFile() {
+ Slog.d(TAG, "handleSavePolicyFile");
+ synchronized (mPolicyFile) {
+ final FileOutputStream stream;
+ try {
+ stream = mPolicyFile.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to save policy file", e);
+ return;
+ }
+
+ try {
+ final XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, TAG_BODY);
+ out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+ mZenModeHelper.writeXml(out);
+ out.endTag(null, TAG_BODY);
+ out.endDocument();
+ mPolicyFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to save policy file, restoring backup", e);
+ mPolicyFile.failWrite(stream);
}
}
}
@@ -511,328 +441,6 @@
}
- /**
- * Remove notification access for any services that no longer exist.
- */
- void disableNonexistentListeners() {
- int[] userIds = getCurrentProfileIds();
- final int N = userIds.length;
- for (int i = 0 ; i < N; ++i) {
- disableNonexistentListeners(userIds[i]);
- }
- }
-
- void disableNonexistentListeners(int userId) {
- String flatIn = Settings.Secure.getStringForUser(
- getContext().getContentResolver(),
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- userId);
- if (!TextUtils.isEmpty(flatIn)) {
- if (DBG) Slog.v(TAG, "flat before: " + flatIn);
- PackageManager pm = getContext().getPackageManager();
- List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
- new Intent(NotificationListenerService.SERVICE_INTERFACE),
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
- userId);
-
- Set<ComponentName> installed = new HashSet<ComponentName>();
- for (int i = 0, count = installedServices.size(); i < count; i++) {
- ResolveInfo resolveInfo = installedServices.get(i);
- ServiceInfo info = resolveInfo.serviceInfo;
-
- if (!android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE.equals(
- info.permission)) {
- Slog.w(TAG, "Skipping notification listener service "
- + info.packageName + "/" + info.name
- + ": it does not require the permission "
- + android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
- continue;
- }
- installed.add(new ComponentName(info.packageName, info.name));
- }
-
- String flatOut = "";
- if (!installed.isEmpty()) {
- String[] enabled = flatIn.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR);
- ArrayList<String> remaining = new ArrayList<String>(enabled.length);
- for (int i = 0; i < enabled.length; i++) {
- ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]);
- if (installed.contains(enabledComponent)) {
- remaining.add(enabled[i]);
- }
- }
- flatOut = TextUtils.join(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR, remaining);
- }
- if (DBG) Slog.v(TAG, "flat after: " + flatOut);
- if (!flatIn.equals(flatOut)) {
- Settings.Secure.putStringForUser(getContext().getContentResolver(),
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- flatOut, userId);
- }
- }
- }
-
- /**
- * Called whenever packages change, the user switches, or ENABLED_NOTIFICATION_LISTENERS
- * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
- */
- void rebindListenerServices() {
- final int[] userIds = getCurrentProfileIds();
- final int nUserIds = userIds.length;
-
- final SparseArray<String> flat = new SparseArray<String>();
-
- for (int i = 0; i < nUserIds; ++i) {
- flat.put(userIds[i], Settings.Secure.getStringForUser(
- getContext().getContentResolver(),
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- userIds[i]));
- }
-
- NotificationListenerInfo[] toRemove = new NotificationListenerInfo[mListeners.size()];
- final SparseArray<ArrayList<ComponentName>> toAdd
- = new SparseArray<ArrayList<ComponentName>>();
-
- synchronized (mNotificationList) {
- // unbind and remove all existing listeners
- toRemove = mListeners.toArray(toRemove);
-
- final HashSet<ComponentName> newEnabled = new HashSet<ComponentName>();
- final HashSet<String> newPackages = new HashSet<String>();
-
- for (int i = 0; i < nUserIds; ++i) {
- final ArrayList<ComponentName> add = new ArrayList<ComponentName>();
- toAdd.put(userIds[i], add);
-
- // decode the list of components
- String toDecode = flat.get(userIds[i]);
- if (toDecode != null) {
- String[] components = toDecode.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR);
- for (int j = 0; j < components.length; j++) {
- final ComponentName component
- = ComponentName.unflattenFromString(components[j]);
- if (component != null) {
- newEnabled.add(component);
- add.add(component);
- newPackages.add(component.getPackageName());
- }
- }
-
- }
- }
- mEnabledListenersForCurrentProfiles = newEnabled;
- mEnabledListenerPackageNames = newPackages;
- }
-
- for (NotificationListenerInfo info : toRemove) {
- final ComponentName component = info.component;
- final int oldUser = info.userid;
- Slog.v(TAG, "disabling notification listener for user "
- + oldUser + ": " + component);
- unregisterListenerService(component, info.userid);
- }
-
- for (int i = 0; i < nUserIds; ++i) {
- final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
- final int N = add.size();
- for (int j = 0; j < N; j++) {
- final ComponentName component = add.get(j);
- Slog.v(TAG, "enabling notification listener for user " + userIds[i] + ": "
- + component);
- registerListenerService(component, userIds[i]);
- }
- }
- }
-
-
- /**
- * Version of registerListener that takes the name of a
- * {@link android.service.notification.NotificationListenerService} to bind to.
- *
- * This is the mechanism by which third parties may subscribe to notifications.
- */
- private void registerListenerService(final ComponentName name, final int userid) {
- checkCallerIsSystem();
-
- if (DBG) Slog.v(TAG, "registerListenerService: " + name + " u=" + userid);
-
- synchronized (mNotificationList) {
- final String servicesBindingTag = name.toString() + "/" + userid;
- if (mServicesBinding.contains(servicesBindingTag)) {
- // stop registering this thing already! we're working on it
- return;
- }
- mServicesBinding.add(servicesBindingTag);
-
- final int N = mListeners.size();
- for (int i=N-1; i>=0; i--) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (name.equals(info.component)
- && info.userid == userid) {
- // cut old connections
- if (DBG) Slog.v(TAG, " disconnecting old listener: " + info.listener);
- mListeners.remove(i);
- if (info.connection != null) {
- getContext().unbindService(info.connection);
- }
- }
- }
-
- Intent intent = new Intent(NotificationListenerService.SERVICE_INTERFACE);
- intent.setComponent(name);
-
- intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
- R.string.notification_listener_binding_label);
-
- final PendingIntent pendingIntent = PendingIntent.getActivity(
- getContext(), 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0);
- intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
-
- ApplicationInfo appInfo = null;
- try {
- appInfo = getContext().getPackageManager().getApplicationInfo(
- name.getPackageName(), 0);
- } catch (NameNotFoundException e) {
- // Ignore if the package doesn't exist we won't be able to bind to the service.
- }
- final int targetSdkVersion =
- appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
-
- try {
- if (DBG) Slog.v(TAG, "binding: " + intent);
- if (!getContext().bindServiceAsUser(intent,
- new ServiceConnection() {
- INotificationListener mListener;
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- boolean added = false;
- synchronized (mNotificationList) {
- mServicesBinding.remove(servicesBindingTag);
- try {
- mListener = INotificationListener.Stub.asInterface(service);
- NotificationListenerInfo info
- = new NotificationListenerInfo(
- mListener, name, userid, this,
- targetSdkVersion);
- service.linkToDeath(info, 0);
- added = mListeners.add(info);
- } catch (RemoteException e) {
- // already dead
- }
- }
- if (added) {
- final String[] keys =
- getActiveNotificationKeysFromListener(mListener);
- try {
- mListener.onListenerConnected(keys);
- } catch (RemoteException e) {
- // we tried
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Slog.v(TAG, "notification listener connection lost: " + name);
- }
- },
- Context.BIND_AUTO_CREATE,
- new UserHandle(userid)))
- {
- mServicesBinding.remove(servicesBindingTag);
- Slog.w(TAG, "Unable to bind listener service: " + intent);
- return;
- }
- } catch (SecurityException ex) {
- Slog.e(TAG, "Unable to bind listener service: " + intent, ex);
- return;
- }
- }
- }
-
-
- /**
- * Remove a listener service for the given user by ComponentName
- */
- private void unregisterListenerService(ComponentName name, int userid) {
- checkCallerIsSystem();
-
- synchronized (mNotificationList) {
- final int N = mListeners.size();
- for (int i=N-1; i>=0; i--) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (name.equals(info.component)
- && info.userid == userid) {
- mListeners.remove(i);
- if (info.connection != null) {
- try {
- getContext().unbindService(info.connection);
- } catch (IllegalArgumentException ex) {
- // something happened to the service: we think we have a connection
- // but it's bogus.
- Slog.e(TAG, "Listener " + name + " could not be unbound: " + ex);
- }
- }
- }
- }
- }
- }
-
- /**
- * asynchronously notify all listeners about a new notification
- */
- void notifyPostedLocked(NotificationRecord n) {
- // make a copy in case changes are made to the underlying Notification object
- final StatusBarNotification sbn = n.sbn.clone();
- for (final NotificationListenerInfo info : mListeners) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- info.notifyPostedIfUserMatch(sbn);
- }});
- }
- }
-
- /**
- * asynchronously notify all listeners about a removed notification
- */
- void notifyRemovedLocked(NotificationRecord n) {
- // make a copy in case changes are made to the underlying Notification object
- // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the notification
- final StatusBarNotification sbn_light = n.sbn.cloneLight();
-
- for (final NotificationListenerInfo info : mListeners) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- info.notifyRemovedIfUserMatch(sbn_light);
- }});
- }
- }
-
- // -- APIs to support listeners clicking/clearing notifications --
-
- private void checkNullListener(INotificationListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("Listener must not be null");
- }
- }
-
- private NotificationListenerInfo checkListenerTokenLocked(INotificationListener listener) {
- checkNullListener(listener);
- final IBinder token = listener.asBinder();
- final int N = mListeners.size();
- for (int i=0; i<N; i++) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (info.listener.asBinder() == token) return info;
- }
- throw new SecurityException("Disallowed call from unknown listener: " + listener);
- }
-
-
-
- // -- end of listener APIs --
public static final class NotificationRecord
{
@@ -1066,10 +674,7 @@
@Override
public boolean allowDisable(int what, IBinder token, String pkg) {
- if (isCall(pkg, null)) {
- return mZenMode == Settings.Global.ZEN_MODE_OFF;
- }
- return true;
+ return mZenModeHelper.allowDisable(what, token, pkg);
}
@Override
@@ -1102,7 +707,7 @@
String pkgList[] = null;
boolean queryReplace = queryRemove &&
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- if (DBG) Slog.i(TAG, "queryReplace=" + queryReplace);
+ if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
} else if (queryRestart) {
@@ -1136,28 +741,16 @@
pkgList = new String[]{pkgName};
}
- boolean anyListenersInvolved = false;
if (pkgList != null && (pkgList.length > 0)) {
for (String pkgName : pkgList) {
if (cancelNotifications) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null);
}
- if (mEnabledListenerPackageNames.contains(pkgName)) {
- anyListenersInvolved = true;
- }
}
}
-
- if (anyListenersInvolved) {
- // if we're not replacing a package, clean up orphaned bits
- if (!queryReplace) {
- disableNonexistentListeners();
- }
- // make sure we're still bound to any of our
- // listeners who may have just upgraded
- rebindListenerServices();
- }
+ mListeners.onPackagesChanged(queryReplace, pkgList);
+ mConditionProviders.onPackagesChanged(queryReplace, pkgList);
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
// Keep track of screen on/off state, but do not turn off the notification light
// until user passes through the lock screen or views the notification.
@@ -1180,9 +773,9 @@
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
// reload per-user settings
mSettingsObserver.update(null);
- updateCurrentProfilesCache(context);
+ mUserProfiles.updateCache(context);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
- updateCurrentProfilesCache(context);
+ mUserProfiles.updateCache(context);
}
}
};
@@ -1191,12 +784,6 @@
private final Uri NOTIFICATION_LIGHT_PULSE_URI
= Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
- private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
- = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
-
- private final Uri ZEN_MODE
- = Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
-
SettingsObserver(Handler handler) {
super(handler);
}
@@ -1205,10 +792,6 @@
ContentResolver resolver = getContext().getContentResolver();
resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
- false, this, UserHandle.USER_ALL);
- resolver.registerContentObserver(ZEN_MODE,
- false, this);
update(null);
}
@@ -1226,16 +809,11 @@
updateNotificationPulse();
}
}
- if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) {
- rebindListenerServices();
- }
- if (ZEN_MODE.equals(uri)) {
- updateZenMode();
- }
}
}
private SettingsObserver mSettingsObserver;
+ private ZenModeHelper mZenModeHelper;
static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
int[] ar = r.getIntArray(resid);
@@ -1261,9 +839,21 @@
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mHandler = new WorkerHandler();
+ mZenModeHelper = new ZenModeHelper(getContext(), mHandler);
+ mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
+ @Override
+ public void onConfigChanged() {
+ savePolicyFile();
+ }
+ });
+ final File systemDir = new File(Environment.getDataDirectory(), "system");
+ mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
importOldBlockDb();
+ mListeners = new NotificationListeners();
+ mConditionProviders = new ConditionProviders(getContext(),
+ mHandler, mUserProfiles, mZenModeHelper);
mStatusBar = getLocalService(StatusBarManagerInternal.class);
mStatusBar.setNotificationDelegate(mNotificationDelegate);
@@ -1297,9 +887,9 @@
Settings.Global.DEVICE_PROVISIONED, 0)) {
mDisableNotificationAlerts = true;
}
- updateZenMode();
+ mZenModeHelper.updateZenMode();
- updateCurrentProfilesCache(getContext());
+ mUserProfiles.updateCache(getContext());
// register for various Intents
IntentFilter filter = new IntentFilter();
@@ -1350,7 +940,7 @@
* Read the old XML-based app block database and import those blockages into the AppOps system.
*/
private void importOldBlockDb() {
- loadBlockDb();
+ loadPolicyFile();
PackageManager pm = getContext().getPackageManager();
for (String pkg : mBlockedPackages) {
@@ -1363,9 +953,6 @@
}
}
mBlockedPackages.clear();
- if (mPolicyFile != null) {
- mPolicyFile.delete();
- }
}
@Override
@@ -1381,6 +968,8 @@
// This observer will force an update when observe is called, causing us to
// bind to listener services.
mSettingsObserver.observe();
+ mListeners.onBootPhaseAppsCanStart();
+ mConditionProviders.onBootPhaseAppsCanStart();
}
}
@@ -1610,8 +1199,7 @@
public void registerListener(final INotificationListener listener,
final ComponentName component, final int userid) {
checkCallerIsSystem();
- checkNullListener(listener);
- registerListenerImpl(listener, component, userid);
+ mListeners.registerService(listener, component, userid);
}
/**
@@ -1619,10 +1207,7 @@
*/
@Override
public void unregisterListener(INotificationListener listener, int userid) {
- checkNullListener(listener);
- // no need to check permissions; if your listener binder is in the list,
- // that's proof that you had permission to add it in the first place
- unregisterListenerImpl(listener, userid);
+ mListeners.unregisterService(listener, userid);
}
/**
@@ -1639,16 +1224,16 @@
long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
- final NotificationListenerInfo info = checkListenerTokenLocked(token);
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
if (keys != null) {
final int N = keys.length;
for (int i = 0; i < N; i++) {
NotificationRecord r = mNotificationsByKey.get(keys[i]);
final int userId = r.sbn.getUserId();
if (userId != info.userid && userId != UserHandle.USER_ALL &&
- !isCurrentProfile(userId)) {
+ !mUserProfiles.isCurrentProfile(userId)) {
throw new SecurityException("Disallowed call from listener: "
- + info.listener);
+ + info.service);
}
if (r != null) {
cancelNotificationFromListenerLocked(info, callingUid, callingPid,
@@ -1666,7 +1251,7 @@
}
}
- private void cancelNotificationFromListenerLocked(NotificationListenerInfo info,
+ private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
@@ -1689,7 +1274,7 @@
long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
- final NotificationListenerInfo info = checkListenerTokenLocked(token);
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
if (info.supportsProfiles()) {
Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
+ "from " + info.component
@@ -1715,14 +1300,14 @@
public StatusBarNotification[] getActiveNotificationsFromListener(
INotificationListener token, String[] keys) {
synchronized (mNotificationList) {
- final NotificationListenerInfo info = checkListenerTokenLocked(token);
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
final ArrayList<StatusBarNotification> list
= new ArrayList<StatusBarNotification>();
if (keys == null) {
final int N = mNotificationList.size();
for (int i=0; i<N; i++) {
StatusBarNotification sbn = mNotificationList.get(i).sbn;
- if (info.enabledAndUserMatches(sbn)) {
+ if (info.enabledAndUserMatches(sbn.getUserId())) {
list.add(sbn);
}
}
@@ -1730,7 +1315,7 @@
final int N = keys.length;
for (int i=0; i<N; i++) {
NotificationRecord r = mNotificationsByKey.get(keys[i]);
- if (r != null && info.enabledAndUserMatches(r.sbn)) {
+ if (r != null && info.enabledAndUserMatches(r.sbn.getUserId())) {
list.add(r.sbn);
}
}
@@ -1745,6 +1330,49 @@
}
@Override
+ public ZenModeConfig getZenModeConfig() {
+ checkCallerIsSystem();
+ return mZenModeHelper.getConfig();
+ }
+
+ @Override
+ public boolean setZenModeConfig(ZenModeConfig config) {
+ checkCallerIsSystem();
+ return mZenModeHelper.setConfig(config);
+ }
+
+ @Override
+ public void notifyConditions(String pkg, IConditionProvider provider,
+ Condition[] conditions) {
+ final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
+ checkCallerIsSystemOrSameApp(pkg);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mConditionProviders.notifyConditions(pkg, info, conditions);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+ enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions");
+ mConditionProviders.requestZenModeConditions(callback, requested);
+ }
+
+ @Override
+ public void setZenModeCondition(Uri conditionId) {
+ enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
+ mConditionProviders.setZenModeCondition(conditionId);
+ }
+
+ private void enforceSystemOrSystemUI(String message) {
+ if (isCallerSystem()) return;
+ getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+ message);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
@@ -1760,12 +1388,12 @@
private String[] getActiveNotificationKeysFromListener(INotificationListener token) {
synchronized (mNotificationList) {
- final NotificationListenerInfo info = checkListenerTokenLocked(token);
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
final ArrayList<String> keys = new ArrayList<String>();
final int N = mNotificationList.size();
for (int i=0; i<N; i++) {
final StatusBarNotification sbn = mNotificationList.get(i).sbn;
- if (info.enabledAndUserMatches(sbn)) {
+ if (info.enabledAndUserMatches(sbn.getUserId())) {
keys.add(sbn.getKey());
}
}
@@ -1776,19 +1404,6 @@
void dumpImpl(PrintWriter pw) {
pw.println("Current Notification Manager state:");
- pw.println(" Listeners (" + mEnabledListenersForCurrentProfiles.size()
- + ") enabled for current profiles:");
- for (ComponentName cmpt : mEnabledListenersForCurrentProfiles) {
- pw.println(" " + cmpt);
- }
-
- pw.println(" Live listeners (" + mListeners.size() + "):");
- for (NotificationListenerInfo info : mListeners) {
- pw.println(" " + info.component
- + " (user " + info.userid + "): " + info.listener
- + (info.isSystem?" SYSTEM":""));
- }
-
int N;
synchronized (mToastQueue) {
@@ -1825,7 +1440,6 @@
pw.println(" mSoundNotification=" + mSoundNotification);
pw.println(" mVibrateNotification=" + mVibrateNotification);
pw.println(" mDisableNotificationAlerts=" + mDisableNotificationAlerts);
- pw.println(" mZenMode=" + Settings.Global.zenModeToString(mZenMode));
pw.println(" mSystemReady=" + mSystemReady);
pw.println(" mArchive=" + mArchive.toString());
Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
@@ -1841,6 +1455,14 @@
pw.println("\n Usage Stats:");
mUsageStats.dump(pw, " ");
+ pw.println("\n Zen Mode:");
+ mZenModeHelper.dump(pw, " ");
+
+ pw.println("\n Notification listeners:");
+ mListeners.dump(pw);
+
+ pw.println("\n Condition providers:");
+ mConditionProviders.dump(pw);
}
}
@@ -1973,7 +1595,7 @@
}
// Is this notification intercepted by zen mode?
- final boolean intercept = shouldIntercept(pkg, notification);
+ final boolean intercept = mZenModeHelper.shouldIntercept(pkg, notification);
notification.extras.putBoolean(EXTRA_INTERCEPT, intercept);
// Should this notification make noise, vibe, or use the LED?
@@ -2046,7 +1668,7 @@
sendAccessibilityEvent(notification, pkg);
}
- notifyPostedLocked(r);
+ mListeners.notifyPostedLocked(r.sbn);
} else {
Slog.e(TAG, "Not posting notification with icon==0: " + notification);
if (old != null && old.statusBarKey != null) {
@@ -2057,7 +1679,7 @@
Binder.restoreCallingIdentity(identity);
}
- notifyRemovedLocked(r);
+ mListeners.notifyRemovedLocked(r.sbn);
}
// ATTENTION: in a future release we will bail out here
// so that we do not play sounds, show lights, etc. for invalid
@@ -2072,7 +1694,7 @@
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (r.getUserId() == UserHandle.USER_ALL ||
(r.getUserId() == userId && r.getUserId() == currentUser) ||
- isCurrentProfile(r.getUserId()))
+ mUserProfiles.isCurrentProfile(r.getUserId()))
&& canInterrupt
&& mSystemReady
&& mAudioManager != null) {
@@ -2203,52 +1825,6 @@
idOut[0] = id;
}
- void registerListenerImpl(final INotificationListener listener,
- final ComponentName component, final int userid) {
- synchronized (mNotificationList) {
- try {
- NotificationListenerInfo info
- = new NotificationListenerInfo(listener, component, userid,
- /*isSystem*/ true, Build.VERSION_CODES.L);
- listener.asBinder().linkToDeath(info, 0);
- mListeners.add(info);
- } catch (RemoteException e) {
- // already dead
- }
- }
- }
-
- /**
- * Removes a listener from the list and unbinds from its service.
- */
- void unregisterListenerImpl(final INotificationListener listener, final int userid) {
- NotificationListenerInfo info = removeListenerImpl(listener, userid);
- if (info != null && info.connection != null) {
- getContext().unbindService(info.connection);
- }
- }
-
- /**
- * Removes a listener from the list but does not unbind from the listener's service.
- *
- * @return the removed listener.
- */
- NotificationListenerInfo removeListenerImpl(
- final INotificationListener listener, final int userid) {
- NotificationListenerInfo listenerInfo = null;
- synchronized (mNotificationList) {
- final int N = mListeners.size();
- for (int i=N-1; i>=0; i--) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (info.listener.asBinder() == listener.asBinder()
- && info.userid == userid) {
- listenerInfo = mListeners.remove(i);
- }
- }
- }
- return listenerInfo;
- }
-
void showNextToastLocked() {
ToastRecord record = mToastQueue.get(0);
while (record != null) {
@@ -2358,6 +1934,9 @@
case MESSAGE_TIMEOUT:
handleTimeout((ToastRecord)msg.obj);
break;
+ case MESSAGE_SAVE_POLICY_FILE:
+ handleSavePolicyFile();
+ break;
}
}
}
@@ -2411,7 +1990,7 @@
Binder.restoreCallingIdentity(identity);
}
r.statusBarKey = null;
- notifyRemovedLocked(r);
+ mListeners.notifyRemovedLocked(r.sbn);
}
// sound
@@ -2478,7 +2057,7 @@
void cancelNotification(final int callingUid, final int callingPid,
final String pkg, final String tag, final int id,
final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
- final int userId, final int reason, final NotificationListenerInfo listener) {
+ final int userId, final int reason, final ManagedServiceInfo listener) {
// In enqueueNotificationInternal notifications are added by scheduling the
// work on the worker handler. Hence, we also schedule the cancel on this
// handler to avoid a scenario where an add notification call followed by a
@@ -2540,7 +2119,7 @@
*/
private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
return notificationMatchesUserId(r, userId)
- || isCurrentProfile(r.getUserId());
+ || mUserProfiles.isCurrentProfile(r.getUserId());
}
/**
@@ -2549,7 +2128,7 @@
*/
boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
int mustNotHaveFlags, boolean doit, int userId, int reason,
- NotificationListenerInfo listener) {
+ ManagedServiceInfo listener) {
EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
listener == null ? null : listener.component.toShortString());
@@ -2590,46 +2169,8 @@
}
}
-
-
- // Return true if the UID is a system or phone UID and therefore should not have
- // any notifications or toasts blocked.
- boolean isUidSystem(int uid) {
- final int appid = UserHandle.getAppId(uid);
- return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
- }
-
- // same as isUidSystem(int, int) for the Binder caller's UID.
- boolean isCallerSystem() {
- return isUidSystem(Binder.getCallingUid());
- }
-
- void checkCallerIsSystem() {
- if (isCallerSystem()) {
- return;
- }
- throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
- }
-
- void checkCallerIsSystemOrSameApp(String pkg) {
- if (isCallerSystem()) {
- return;
- }
- final int uid = Binder.getCallingUid();
- try {
- ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
- pkg, 0, UserHandle.getCallingUserId());
- if (!UserHandle.isSameApp(ai.uid, uid)) {
- throw new SecurityException("Calling uid " + uid + " gave package"
- + pkg + " which is owned by uid " + ai.uid);
- }
- } catch (RemoteException re) {
- throw new SecurityException("Unknown package " + pkg + "\n" + re);
- }
- }
-
void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
- NotificationListenerInfo listener, boolean includeCurrentProfiles) {
+ ManagedServiceInfo listener, boolean includeCurrentProfiles) {
EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
null, userId, 0, 0, reason,
listener == null ? null : listener.component.toShortString());
@@ -2722,85 +2263,130 @@
}
}
- private void updateZenMode() {
- final int mode = Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
- if (mode != mZenMode) {
- Slog.d(TAG, String.format("updateZenMode: %s -> %s",
- Settings.Global.zenModeToString(mZenMode),
- Settings.Global.zenModeToString(mode)));
- }
- mZenMode = mode;
-
- final String[] exceptionPackages = null; // none (for now)
-
- // call restrictions
- final boolean muteCalls = mZenMode != Settings.Global.ZEN_MODE_OFF;
- mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_RING,
- muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
- exceptionPackages);
- mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_RING,
- muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
- exceptionPackages);
-
- // alarm restrictions
- final boolean muteAlarms = false; // TODO until we save user config
- mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_ALARM,
- muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
- exceptionPackages);
- mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_ALARM,
- muteAlarms ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
- exceptionPackages);
-
- // restrict vibrations with no hints
- mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.USE_DEFAULT_STREAM_TYPE,
- (muteAlarms || muteCalls) ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
- exceptionPackages);
+ private static boolean isUidSystem(int uid) {
+ final int appid = UserHandle.getAppId(uid);
+ return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
}
- private void updateCurrentProfilesCache(Context context) {
- UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if (userManager != null) {
- int currentUserId = ActivityManager.getCurrentUser();
- List<UserInfo> profiles = userManager.getProfiles(currentUserId);
- synchronized (mCurrentProfiles) {
- mCurrentProfiles.clear();
- for (UserInfo user : profiles) {
- mCurrentProfiles.put(user.id, user);
- }
+ private static boolean isCallerSystem() {
+ return isUidSystem(Binder.getCallingUid());
+ }
+
+ private static void checkCallerIsSystem() {
+ if (isCallerSystem()) {
+ return;
+ }
+ throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
+ }
+
+ private static void checkCallerIsSystemOrSameApp(String pkg) {
+ if (isCallerSystem()) {
+ return;
+ }
+ final int uid = Binder.getCallingUid();
+ try {
+ ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+ pkg, 0, UserHandle.getCallingUserId());
+ if (!UserHandle.isSameApp(ai.uid, uid)) {
+ throw new SecurityException("Calling uid " + uid + " gave package"
+ + pkg + " which is owned by uid " + ai.uid);
+ }
+ } catch (RemoteException re) {
+ throw new SecurityException("Unknown package " + pkg + "\n" + re);
+ }
+ }
+
+ public class NotificationListeners extends ManagedServices {
+
+ public NotificationListeners() {
+ super(getContext(), mHandler, mNotificationList, mUserProfiles);
+ }
+
+ @Override
+ protected Config getConfig() {
+ Config c = new Config();
+ c.caption = "notification listener";
+ c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
+ c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
+ c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
+ c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
+ c.clientLabel = R.string.notification_listener_binding_label;
+ return c;
+ }
+
+ @Override
+ protected IInterface asInterface(IBinder binder) {
+ return INotificationListener.Stub.asInterface(binder);
+ }
+
+ @Override
+ public void onServiceAdded(IInterface service) {
+ final INotificationListener listener = (INotificationListener) service;
+ final String[] keys = getActiveNotificationKeysFromListener(listener);
+ try {
+ listener.onListenerConnected(keys);
+ } catch (RemoteException e) {
+ // we tried
}
}
- }
- private int[] getCurrentProfileIds() {
- synchronized (mCurrentProfiles) {
- int[] users = new int[mCurrentProfiles.size()];
- final int N = mCurrentProfiles.size();
- for (int i = 0; i < N; ++i) {
- users[i] = mCurrentProfiles.keyAt(i);
+ /**
+ * asynchronously notify all listeners about a new notification
+ */
+ public void notifyPostedLocked(StatusBarNotification sbn) {
+ // make a copy in case changes are made to the underlying Notification object
+ final StatusBarNotification sbnClone = sbn.clone();
+ for (final ManagedServiceInfo info : mServices) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ notifyPostedIfUserMatch(info, sbnClone);
+ }
+ });
}
- return users;
}
- }
- private boolean isCurrentProfile(int userId) {
- synchronized (mCurrentProfiles) {
- return mCurrentProfiles.get(userId) != null;
+ /**
+ * asynchronously notify all listeners about a removed notification
+ */
+ public void notifyRemovedLocked(StatusBarNotification sbn) {
+ // make a copy in case changes are made to the underlying Notification object
+ // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
+ // notification
+ final StatusBarNotification sbnLight = sbn.cloneLight();
+ for (ManagedServiceInfo serviceInfo : mServices) {
+ final ManagedServiceInfo info = (ManagedServiceInfo) serviceInfo;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ notifyRemovedIfUserMatch(info, sbnLight);
+ }
+ });
+ }
}
- }
- private boolean isCall(String pkg, Notification n) {
- return CALL_PACKAGES.contains(pkg);
- }
-
- private boolean isAlarm(String pkg, Notification n) {
- return ALARM_PACKAGES.contains(pkg);
- }
-
- private boolean shouldIntercept(String pkg, Notification n) {
- if (mZenMode != Settings.Global.ZEN_MODE_OFF) {
- return !isAlarm(pkg, n);
+ private void notifyPostedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn) {
+ if (!info.enabledAndUserMatches(sbn.getUserId())) {
+ return;
+ }
+ final INotificationListener listener = (INotificationListener)info.service;
+ try {
+ listener.onNotificationPosted(sbn);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
+ }
}
- return false;
+
+ private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn) {
+ if (!info.enabledAndUserMatches(sbn.getUserId())) {
+ return;
+ }
+ final INotificationListener listener = (INotificationListener)info.service;
+ try {
+ listener.onNotificationRemoved(sbn);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
new file mode 100644
index 0000000..137730a
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -0,0 +1,335 @@
+/**
+ * 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.server.notification;
+
+import android.app.AlarmManager;
+import android.app.AppOpsManager;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.provider.Settings.Global;
+import android.service.notification.ZenModeConfig;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * NotificationManagerService helper for functionality related to zen mode.
+ */
+public class ZenModeHelper {
+ private static final String TAG = "ZenModeHelper";
+
+ private static final String ACTION_ENTER_ZEN = "enter_zen";
+ private static final int REQUEST_CODE_ENTER = 100;
+ private static final String ACTION_EXIT_ZEN = "exit_zen";
+ private static final int REQUEST_CODE_EXIT = 101;
+ private static final String EXTRA_TIME = "time";
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final SettingsObserver mSettingsObserver;
+ private final AppOpsManager mAppOps;
+ private final ZenModeConfig mDefaultConfig;
+ private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+
+ private int mZenMode;
+ private ZenModeConfig mConfig;
+
+ // temporary, until we update apps to provide metadata
+ private static final Set<String> CALL_PACKAGES = new HashSet<String>(Arrays.asList(
+ "com.google.android.dialer",
+ "com.android.phone"
+ ));
+ private static final Set<String> MESSAGE_PACKAGES = new HashSet<String>(Arrays.asList(
+ "com.google.android.talk",
+ "com.android.mms"
+ ));
+
+ public ZenModeHelper(Context context, Handler handler) {
+ mContext = context;
+ mHandler = handler;
+ mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mDefaultConfig = readDefaultConfig(context.getResources());
+ mConfig = mDefaultConfig;
+ mSettingsObserver = new SettingsObserver(mHandler);
+ mSettingsObserver.observe();
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_ENTER_ZEN);
+ filter.addAction(ACTION_EXIT_ZEN);
+ mContext.registerReceiver(new ZenBroadcastReceiver(), filter);
+ }
+
+ public static ZenModeConfig readDefaultConfig(Resources resources) {
+ XmlResourceParser parser = null;
+ try {
+ parser = resources.getXml(R.xml.default_zen_mode_config);
+ while (parser.next() != XmlPullParser.END_DOCUMENT) {
+ final ZenModeConfig config = ZenModeConfig.readXml(parser);
+ if (config != null) return config;
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Error reading default zen mode config from resource", e);
+ } finally {
+ IoUtils.closeQuietly(parser);
+ }
+ return new ZenModeConfig();
+ }
+
+ public void addCallback(Callback callback) {
+ mCallbacks.add(callback);
+ }
+
+ public boolean shouldIntercept(String pkg, Notification n) {
+ if (mZenMode != Global.ZEN_MODE_OFF) {
+ if (isCall(pkg, n)) {
+ return !mConfig.allowCalls;
+ }
+ if (isMessage(pkg, n)) {
+ return !mConfig.allowMessages;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public int getZenMode() {
+ return mZenMode;
+ }
+
+ public void setZenMode(int zenModeValue) {
+ Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
+ }
+
+ public void updateZenMode() {
+ final int mode = Global.getInt(mContext.getContentResolver(),
+ Global.ZEN_MODE, Global.ZEN_MODE_OFF);
+ if (mode != mZenMode) {
+ Slog.d(TAG, String.format("updateZenMode: %s -> %s",
+ Global.zenModeToString(mZenMode),
+ Global.zenModeToString(mode)));
+ }
+ mZenMode = mode;
+ final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
+ final String[] exceptionPackages = null; // none (for now)
+
+ // call restrictions
+ final boolean muteCalls = zen && !mConfig.allowCalls;
+ mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.STREAM_RING,
+ muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+ exceptionPackages);
+ mAppOps.setRestriction(AppOpsManager.OP_PLAY_AUDIO, AudioManager.STREAM_RING,
+ muteCalls ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+ exceptionPackages);
+
+ // restrict vibrations with no hints
+ mAppOps.setRestriction(AppOpsManager.OP_VIBRATE, AudioManager.USE_DEFAULT_STREAM_TYPE,
+ zen ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+ exceptionPackages);
+ dispatchOnZenModeChanged();
+ }
+
+ public boolean allowDisable(int what, IBinder token, String pkg) {
+ if (isCall(pkg, null)) {
+ return mZenMode == Global.ZEN_MODE_OFF || mConfig.allowCalls;
+ }
+ return true;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("mZenMode=");
+ pw.println(Global.zenModeToString(mZenMode));
+ pw.print(prefix); pw.print("mConfig="); pw.println(mConfig);
+ pw.print(prefix); pw.print("mDefaultConfig="); pw.println(mDefaultConfig);
+ }
+
+ public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+ final ZenModeConfig config = ZenModeConfig.readXml(parser);
+ if (config != null) {
+ setConfig(config);
+ }
+ }
+
+ public void writeXml(XmlSerializer out) throws IOException {
+ mConfig.writeXml(out);
+ }
+
+ public ZenModeConfig getConfig() {
+ return mConfig;
+ }
+
+ public boolean setConfig(ZenModeConfig config) {
+ if (config == null || !config.isValid()) return false;
+ if (config.equals(mConfig)) return true;
+ mConfig = config;
+ Slog.d(TAG, "mConfig=" + mConfig);
+ dispatchOnConfigChanged();
+ final String val = Integer.toString(mConfig.hashCode());
+ Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
+ updateAlarms();
+ updateZenMode();
+ return true;
+ }
+
+ private void dispatchOnConfigChanged() {
+ for (Callback callback : mCallbacks) {
+ callback.onConfigChanged();
+ }
+ }
+
+ private void dispatchOnZenModeChanged() {
+ for (Callback callback : mCallbacks) {
+ callback.onZenModeChanged();
+ }
+ }
+
+ private boolean isCall(String pkg, Notification n) {
+ return CALL_PACKAGES.contains(pkg);
+ }
+
+ private boolean isMessage(String pkg, Notification n) {
+ return MESSAGE_PACKAGES.contains(pkg);
+ }
+
+ private void updateAlarms() {
+ updateAlarm(ACTION_ENTER_ZEN, REQUEST_CODE_ENTER,
+ mConfig.sleepStartHour, mConfig.sleepStartMinute);
+ updateAlarm(ACTION_EXIT_ZEN, REQUEST_CODE_EXIT,
+ mConfig.sleepEndHour, mConfig.sleepEndMinute);
+ }
+
+ private void updateAlarm(String action, int requestCode, int hr, int min) {
+ final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ final long now = System.currentTimeMillis();
+ final Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(now);
+ c.set(Calendar.HOUR_OF_DAY, hr);
+ c.set(Calendar.MINUTE, min);
+ c.set(Calendar.SECOND, 0);
+ c.set(Calendar.MILLISECOND, 0);
+ if (c.getTimeInMillis() <= now) {
+ c.add(Calendar.DATE, 1);
+ }
+ final long time = c.getTimeInMillis();
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
+ new Intent(action).putExtra(EXTRA_TIME, time), PendingIntent.FLAG_UPDATE_CURRENT);
+ alarms.cancel(pendingIntent);
+ if (mConfig.sleepMode != null) {
+ Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
+ action, ts(time), time - now, ts(now)));
+ alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+ }
+ }
+
+ private static String ts(long time) {
+ return new Date(time) + " (" + time + ")";
+ }
+
+ public static boolean isWeekend(long time, int offsetDays) {
+ final Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(time);
+ if (offsetDays != 0) {
+ c.add(Calendar.DATE, offsetDays);
+ }
+ final int day = c.get(Calendar.DAY_OF_WEEK);
+ return day == Calendar.SATURDAY || day == Calendar.SUNDAY;
+ }
+
+ private class SettingsObserver extends ContentObserver {
+ private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
+
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void observe() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(ZEN_MODE, false /*notifyForDescendents*/, this);
+ update(null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ update(uri);
+ }
+
+ public void update(Uri uri) {
+ if (ZEN_MODE.equals(uri)) {
+ updateZenMode();
+ }
+ }
+ }
+
+ private class ZenBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_ENTER_ZEN.equals(intent.getAction())) {
+ setZenMode(intent, 1, Global.ZEN_MODE_ON);
+ } else if (ACTION_EXIT_ZEN.equals(intent.getAction())) {
+ setZenMode(intent, 0, Global.ZEN_MODE_OFF);
+ }
+ }
+
+ private void setZenMode(Intent intent, int wkendOffsetDays, int zenModeValue) {
+ final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
+ final long now = System.currentTimeMillis();
+ Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
+ intent.getAction(), ts(schTime), ts(now), now - schTime));
+
+ final boolean skip = ZenModeConfig.SLEEP_MODE_WEEKNIGHTS.equals(mConfig.sleepMode) &&
+ isWeekend(schTime, wkendOffsetDays);
+
+ if (skip) {
+ Slog.d(TAG, "Skipping zen mode update for the weekend");
+ } else {
+ ZenModeHelper.this.setZenMode(zenModeValue);
+ }
+ updateAlarms();
+ }
+ }
+
+ public static class Callback {
+ void onConfigChanged() {}
+ void onZenModeChanged() {}
+ }
+}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 27c7b39..6030d4d 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -144,6 +144,7 @@
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ mainIntent.setPackage(packageName);
long ident = Binder.clearCallingIdentity();
try {
List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent, 0,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 747d0a7..2c623b5 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -104,7 +104,6 @@
import android.os.FileObserver;
import android.os.FileUtils;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -199,8 +198,6 @@
private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
private static final int SHELL_UID = Process.SHELL_UID;
- private static final boolean GET_CERTIFICATES = true;
-
// Cap the size of permission trees that 3rd party apps can define
private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; // characters of text
@@ -264,6 +261,7 @@
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
private static final String LIB_DIR_NAME = "lib";
+ private static final String LIB64_DIR_NAME = "lib64";
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
@@ -277,8 +275,6 @@
final PackageHandler mHandler;
final int mSdkVersion = Build.VERSION.SDK_INT;
- final String mSdkCodename = "REL".equals(Build.VERSION.CODENAME)
- ? null : Build.VERSION.CODENAME;
final Context mContext;
final boolean mFactoryTest;
@@ -1536,6 +1532,9 @@
mSettings.readDefaultPreferredAppsLPw(this, 0);
}
+ // All the changes are done during package scanning.
+ mSettings.updateInternalDatabaseVersion();
+
// can downgrade to reader
mSettings.writeLPr();
@@ -2164,6 +2163,24 @@
}
@Override
+ public boolean activitySupportsIntent(ComponentName component, Intent intent,
+ String resolvedType) {
+ synchronized (mPackages) {
+ PackageParser.Activity a = mActivities.mActivities.get(component);
+ if (a == null) {
+ return false;
+ }
+ for (int i=0; i<a.intents.size(); i++) {
+ if (a.intents.get(i).match(intent.getAction(), resolvedType, intent.getScheme(),
+ intent.getData(), intent.getCategories(), TAG) >= 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get receiver info");
@@ -3782,27 +3799,25 @@
private boolean collectCertificatesLI(PackageParser pp, PackageSetting ps,
PackageParser.Package pkg, File srcFile, int parseFlags) {
- if (GET_CERTIFICATES) {
- if (ps != null
- && ps.codePath.equals(srcFile)
- && ps.timeStamp == srcFile.lastModified()) {
- if (ps.signatures.mSignatures != null
- && ps.signatures.mSignatures.length != 0) {
- // Optimization: reuse the existing cached certificates
- // if the package appears to be unchanged.
- pkg.mSignatures = ps.signatures.mSignatures;
- return true;
- }
-
- Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them.");
- } else {
- Log.i(TAG, srcFile.toString() + " changed; collecting certs");
+ if (ps != null
+ && ps.codePath.equals(srcFile)
+ && ps.timeStamp == srcFile.lastModified()) {
+ if (ps.signatures.mSignatures != null
+ && ps.signatures.mSignatures.length != 0) {
+ // Optimization: reuse the existing cached certificates
+ // if the package appears to be unchanged.
+ pkg.mSignatures = ps.signatures.mSignatures;
+ return true;
}
-
- if (!pp.collectCertificates(pkg, parseFlags)) {
- mLastScanError = pp.getParseError();
- return false;
- }
+
+ Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them.");
+ } else {
+ Log.i(TAG, srcFile.toString() + " changed; collecting certs");
+ }
+
+ if (!pp.collectCertificates(pkg, parseFlags)) {
+ mLastScanError = pp.getParseError();
+ return false;
}
return true;
}
@@ -4318,6 +4333,14 @@
private boolean updateSharedLibrariesLPw(PackageParser.Package pkg,
PackageParser.Package changingLib) {
+ // We might be upgrading from a version of the platform that did not
+ // provide per-package native library directories for system apps.
+ // Fix that up here.
+ if (isSystemApp(pkg)) {
+ PackageSetting ps = mSettings.mPackages.get(pkg.applicationInfo.packageName);
+ setInternalAppNativeLibraryPath(pkg, ps);
+ }
+
if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
if (mTmpSharedLibraries == null ||
mTmpSharedLibraries.length < mSharedLibraries.size()) {
@@ -4483,17 +4506,6 @@
// writer
synchronized (mPackages) {
- if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
- // Check all shared libraries and map to their actual file path.
- // We only do this here for apps not on a system dir, because those
- // are the only ones that can fail an install due to this. We
- // will take care of the system apps by updating all of their
- // library paths after the scan is done.
- if (!updateSharedLibrariesLPw(pkg, null)) {
- return null;
- }
- }
-
if (pkg.mSharedUserId != null) {
suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, true);
if (suid == null) {
@@ -4604,6 +4616,17 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
+ if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ // Check all shared libraries and map to their actual file path.
+ // We only do this here for apps not on a system dir, because those
+ // are the only ones that can fail an install due to this. We
+ // will take care of the system apps by updating all of their
+ // library paths after the scan is done.
+ if (!updateSharedLibrariesLPw(pkg, null)) {
+ return null;
+ }
+ }
+
if (mFoundPolicyFile) {
SELinuxMMAC.assignSeinfoValue(pkg);
}
@@ -4830,7 +4853,6 @@
pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
}
}
-
pkgSetting.uidError = uidError;
}
@@ -5411,10 +5433,57 @@
}
}
+ private String calculateApkRoot(final String codePathString) {
+ final File codePath = new File(codePathString);
+ final File codeRoot;
+ if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
+ codeRoot = Environment.getRootDirectory();
+ } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
+ codeRoot = Environment.getOemDirectory();
+ } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
+ codeRoot = Environment.getVendorDirectory();
+ } else {
+ // Unrecognized code path; take its top real segment as the apk root:
+ // e.g. /something/app/blah.apk => /something
+ try {
+ File f = codePath.getCanonicalFile();
+ File parent = f.getParentFile(); // non-null because codePath is a file
+ File tmp;
+ while ((tmp = parent.getParentFile()) != null) {
+ f = parent;
+ parent = tmp;
+ }
+ codeRoot = f;
+ Slog.w(TAG, "Unrecognized code path "
+ + codePath + " - using " + codeRoot);
+ } catch (IOException e) {
+ // Can't canonicalize the lib path -- shenanigans?
+ Slog.w(TAG, "Can't canonicalize code path " + codePath);
+ return Environment.getRootDirectory().getPath();
+ }
+ }
+ return codeRoot.getPath();
+ }
+
+ // This is the initial scan-time determination of how to handle a given
+ // package for purposes of native library location.
private void setInternalAppNativeLibraryPath(PackageParser.Package pkg,
PackageSetting pkgSetting) {
- final String apkLibPath = getApkName(pkgSetting.codePathString);
- final String nativeLibraryPath = new File(mAppLibInstallDir, apkLibPath).getPath();
+ // "bundled" here means system-installed with no overriding update
+ final boolean bundledApk = isSystemApp(pkg) && !isUpdatedSystemApp(pkg);
+ final String apkName = getApkName(pkg.applicationInfo.sourceDir);
+ final File libDir;
+ if (bundledApk) {
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ String apkRoot = calculateApkRoot(pkg.applicationInfo.sourceDir);
+ File lib64 = new File(apkRoot, LIB64_DIR_NAME);
+ File packLib64 = new File(lib64, apkName);
+ libDir = (packLib64.exists()) ? lib64 : new File(apkRoot, LIB_DIR_NAME);
+ } else {
+ libDir = mAppLibInstallDir;
+ }
+ final String nativeLibraryPath = (new File(libDir, apkName)).getPath();
pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
pkgSetting.nativeLibraryPathString = nativeLibraryPath;
}
@@ -9397,7 +9466,7 @@
return;
}
}
- if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
+ if (!pp.collectCertificates(pkg, parseFlags)) {
res.returnCode = pp.getParseError();
return;
}
@@ -9926,13 +9995,14 @@
}
// writer
synchronized (mPackages) {
+ PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);
+ setInternalAppNativeLibraryPath(newPkg, ps);
updatePermissionsLPw(newPkg.packageName, newPkg,
UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG);
if (applyUserRestrictions) {
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across reinstall");
}
- PackageSetting ps = mSettings.mPackages.get(newPkg.packageName);
for (int i = 0; i < allUserHandles.length; i++) {
if (DEBUG_REMOVE) {
Slog.d(TAG, " user " + allUserHandles[i]
@@ -11007,6 +11077,8 @@
public static final int DUMP_KEYSETS = 1 << 11;
+ public static final int DUMP_VERSION = 1 << 12;
+
public static final int OPTION_SHOW_FILTERS = 1 << 0;
private int mTypes;
@@ -11105,6 +11177,7 @@
pw.println(" s[hared-users]: dump shared user IDs");
pw.println(" m[essages]: print collected runtime messages");
pw.println(" v[erifiers]: print package verifier info");
+ pw.println(" version: print database version info");
pw.println(" <package.name>: info about given package");
pw.println(" k[eysets]: print known keysets");
return;
@@ -11153,6 +11226,8 @@
dumpState.setDump(DumpState.DUMP_MESSAGES);
} else if ("v".equals(cmd) || "verifiers".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_VERIFIERS);
+ } else if ("version".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_VERSION);
} else if ("k".equals(cmd) || "keysets".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_KEYSETS);
}
@@ -11164,6 +11239,24 @@
// reader
synchronized (mPackages) {
+ if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
+ if (!checkin) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Database versions:");
+ pw.print(" SDK Version:");
+ pw.print(" internal=");
+ pw.print(mSettings.mInternalSdkPlatform);
+ pw.print(" external=");
+ pw.println(mSettings.mExternalSdkPlatform);
+ pw.print(" DB Version:");
+ pw.print(" internal=");
+ pw.print(mSettings.mInternalDatabaseVersion);
+ pw.print(" external=");
+ pw.println(mSettings.mExternalDatabaseVersion);
+ }
+ }
+
if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
if (!checkin) {
if (dumpState.onTitlePrinted())
@@ -11694,6 +11787,9 @@
| (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
+
+ mSettings.updateExternalDatabaseVersion();
+
// can downgrade to reader
// Persist settings
mSettings.writeLPr();
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 80f716c..a69940f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -89,6 +89,28 @@
final class Settings {
private static final String TAG = "PackageSettings";
+ /**
+ * Current version of the package database. Set it to the latest version in
+ * the {@link DatabaseVersion} class below to ensure the database upgrade
+ * doesn't happen repeatedly.
+ * <p>
+ * Note that care should be taken to make sure all database upgrades are
+ * idempotent.
+ */
+ private static final int CURRENT_DATABASE_VERSION = DatabaseVersion.FIRST_VERSION;
+
+ /**
+ * This class contains constants that can be referred to from upgrade code.
+ * Insert constant values here that describe the upgrade reason. The version
+ * code must be monotonically increasing.
+ */
+ public static class DatabaseVersion {
+ /**
+ * The initial version of the database.
+ */
+ public static final int FIRST_VERSION = 1;
+ }
+
private static final boolean DEBUG_STOPPED = false;
private static final boolean DEBUG_MU = false;
@@ -133,6 +155,14 @@
int mInternalSdkPlatform;
int mExternalSdkPlatform;
+ /**
+ * The current database version for apps on internal storage. This is
+ * used to upgrade the format of the packages.xml database not necessarily
+ * tied to an SDK version.
+ */
+ int mInternalDatabaseVersion;
+ int mExternalDatabaseVersion;
+
Boolean mReadExternalStorageEnforced;
/** Device identity for the purpose of package verification. */
@@ -825,6 +855,40 @@
}
}
+ /**
+ * Returns whether the current database has is older than {@code version}
+ * for apps on internal storage.
+ */
+ public boolean isInternalDatabaseVersionOlderThan(int version) {
+ return mInternalDatabaseVersion < version;
+ }
+
+ /**
+ * Returns whether the current database has is older than {@code version}
+ * for apps on external storage.
+ */
+ public boolean isExternalDatabaseVersionOlderThan(int version) {
+ return mExternalDatabaseVersion < version;
+ }
+
+ /**
+ * Updates the database version for apps on internal storage. Called after
+ * call the updates to the database format are done for apps on internal
+ * storage after the initial start-up scan.
+ */
+ public void updateInternalDatabaseVersion() {
+ mInternalDatabaseVersion = CURRENT_DATABASE_VERSION;
+ }
+
+ /**
+ * Updates the database version for apps on internal storage. Called after
+ * call the updates to the database format are done for apps on internal
+ * storage after the initial start-up scan.
+ */
+ public void updateExternalDatabaseVersion() {
+ mExternalDatabaseVersion = CURRENT_DATABASE_VERSION;
+ }
+
private void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
@@ -1355,6 +1419,11 @@
serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
serializer.endTag(null, "last-platform-version");
+ serializer.startTag(null, "database-version");
+ serializer.attribute(null, "internal", Integer.toString(mInternalDatabaseVersion));
+ serializer.attribute(null, "external", Integer.toString(mExternalDatabaseVersion));
+ serializer.endTag(null, "database-version");
+
if (mVerifierDeviceIdentity != null) {
serializer.startTag(null, "verifier");
serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
@@ -1830,6 +1899,19 @@
}
} catch (NumberFormatException e) {
}
+ } else if (tagName.equals("database-version")) {
+ mInternalDatabaseVersion = mExternalDatabaseVersion = 0;
+ try {
+ String internalDbVersionString = parser.getAttributeValue(null, "internal");
+ if (internalDbVersionString != null) {
+ mInternalDatabaseVersion = Integer.parseInt(internalDbVersionString);
+ }
+ String externalDbVersionString = parser.getAttributeValue(null, "external");
+ if (externalDbVersionString != null) {
+ mExternalDatabaseVersion = Integer.parseInt(externalDbVersionString);
+ }
+ } catch (NumberFormatException ignored) {
+ }
} else if (tagName.equals("verifier")) {
final String deviceIdentity = parser.getAttributeValue(null, "device");
try {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a6e83a7..f8103de 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -23,6 +23,7 @@
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.IStopUserCallback;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -257,24 +258,62 @@
}
@Override
- public List<UserInfo> getProfiles(int userId) {
+ public List<UserInfo> getProfiles(int userId, boolean enabledOnly) {
if (userId != UserHandle.getCallingUserId()) {
checkManageUsersPermission("getting profiles related to user " + userId);
}
- synchronized (mPackagesLock) {
- UserInfo user = getUserInfoLocked(userId);
- ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
- for (int i = 0; i < mUsers.size(); i++) {
- UserInfo profile = mUsers.valueAt(i);
- if (!isProfileOf(user, profile)) {
- continue;
- }
- users.add(profile);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mPackagesLock) {
+ return getProfilesLocked(userId, enabledOnly);
}
- return users;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
+ /** Assume permissions already checked and caller's identity cleared */
+ private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) {
+ // Getting the service here is not good for testing purposes.
+ // However, this service is not available when UserManagerService starts
+ // up so we need a lazy load.
+
+ DevicePolicyManager dpm = null;
+ if (enabledOnly) {
+ dpm = (DevicePolicyManager)
+ mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ }
+
+ UserInfo user = getUserInfoLocked(userId);
+ ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserInfo profile = mUsers.valueAt(i);
+ if (!isProfileOf(user, profile)) {
+ continue;
+ }
+
+ if (enabledOnly && profile.isManagedProfile()) {
+ if (dpm != null) {
+ if (!dpm.isProfileEnabled(profile.id)) {
+ continue;
+ }
+ } else {
+ Log.w(LOG_TAG,
+ "Attempting to reach DevicePolicyManager before it is started");
+ // TODO: There might be system apps that need to call this.
+ // Make sure that DevicePolicyManagerService is ready at that
+ // time (otherwise, any default value is a bad one).
+ throw new IllegalArgumentException(String.format(
+ "Attempting to get enabled profiles for %d before "
+ + "DevicePolicyManagerService has been started.",
+ userId));
+ }
+ }
+ users.add(profile);
+ }
+ return users;
+ }
+
private boolean isProfileOf(UserInfo user, UserInfo profile) {
return user.id == profile.id ||
(user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
@@ -431,7 +470,7 @@
synchronized (mPackagesLock) {
Bundle restrictions = mUserRestrictions.get(userId);
- return restrictions != null ? restrictions : Bundle.EMPTY;
+ return restrictions != null ? new Bundle(restrictions) : new Bundle();
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 82cef7f..cfe24fe 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -168,6 +168,10 @@
// Poll interval in milliseconds for watching boot animation finished.
private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
+ //powerHint
+ private static final int POWER_HINT_LOW_POWER_MODE = 5;
+ private static boolean mLowPowerModeEnabled;
+
private final Context mContext;
private LightsManager mLightsManager;
private BatteryService mBatteryService;
@@ -530,7 +534,9 @@
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_BRIGHTNESS_MODE),
false, mSettingsObserver, UserHandle.USER_ALL);
-
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.LOW_POWER_MODE),
+ false, mSettingsObserver, UserHandle.USER_ALL);
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -610,6 +616,14 @@
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
+ boolean mIsEnabled = Settings.Global.getInt(resolver,
+ Settings.Global.LOW_POWER_MODE, 0) != 0;
+ if (mIsEnabled != mLowPowerModeEnabled) {
+ BinderService bs = new BinderService();
+ bs.powerHint(POWER_HINT_LOW_POWER_MODE, mIsEnabled ? 1 : 0);
+ mLowPowerModeEnabled = mIsEnabled;
+ }
+
mDirty |= DIRTY_SETTINGS;
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 75e5857..5ceb992 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -19,6 +19,9 @@
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -26,12 +29,18 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.database.Cursor;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.TvContract;
import android.tv.ITvInputClient;
import android.tv.ITvInputManager;
import android.tv.ITvInputService;
@@ -40,12 +49,14 @@
import android.tv.ITvInputSessionCallback;
import android.tv.TvInputInfo;
import android.tv.TvInputService;
-import android.util.ArrayMap;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Surface;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.SomeArgs;
+import com.android.server.IoThread;
import com.android.server.SystemService;
import java.util.ArrayList;
@@ -61,6 +72,8 @@
private final Context mContext;
+ private final ContentResolver mContentResolver;
+
// A global lock.
private final Object mLock = new Object();
@@ -70,10 +83,17 @@
// A map from user id to UserState.
private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
+ private final Handler mLogHandler;
+
public TvInputManagerService(Context context) {
super(context);
+
mContext = context;
+ mContentResolver = context.getContentResolver();
+ mLogHandler = new LogHandler(IoThread.get().getLooper());
+
registerBroadcastReceivers();
+
synchronized (mLock) {
mUserStates.put(mCurrentUserId, new UserState());
buildTvInputListLocked(mCurrentUserId);
@@ -116,17 +136,19 @@
UserState userState = getUserStateLocked(userId);
userState.inputList.clear();
+ if (DEBUG) Slog.d(TAG, "buildTvInputList");
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> services = pm.queryIntentServices(
new Intent(TvInputService.SERVICE_INTERFACE), PackageManager.GET_SERVICES);
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
- Log.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
+ Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
+ android.Manifest.permission.BIND_TV_INPUT);
continue;
}
TvInputInfo info = new TvInputInfo(ri);
+ if (DEBUG) Slog.d(TAG, "add " + info.getId());
userState.inputList.add(info);
}
}
@@ -161,7 +183,7 @@
try {
state.session.release();
} catch (RemoteException e) {
- Log.e(TAG, "error in release", e);
+ Slog.e(TAG, "error in release", e);
}
}
}
@@ -173,7 +195,7 @@
try {
serviceState.service.unregisterCallback(serviceState.callback);
} catch (RemoteException e) {
- Log.e(TAG, "error in unregisterCallback", e);
+ Slog.e(TAG, "error in unregisterCallback", e);
}
}
serviceState.clients.clear();
@@ -244,7 +266,7 @@
return;
}
if (DEBUG) {
- Log.i(TAG, "bindServiceAsUser(name=" + name.getClassName() + ", userId=" + userId
+ Slog.d(TAG, "bindServiceAsUser(name=" + name.getClassName() + ", userId=" + userId
+ ")");
}
Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(name);
@@ -255,7 +277,7 @@
// This means that the service is already connected but its state indicates that we have
// nothing to do with it. Then, disconnect the service.
if (DEBUG) {
- Log.i(TAG, "unbindService(name=" + name.getClassName() + ")");
+ Slog.d(TAG, "unbindService(name=" + name.getClassName() + ")");
}
mContext.unbindService(serviceState.connection);
userState.serviceStateMap.remove(name);
@@ -267,7 +289,7 @@
final SessionState sessionState =
getUserStateLocked(userId).sessionStateMap.get(sessionToken);
if (DEBUG) {
- Log.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName()
+ Slog.d(TAG, "createSessionInternalLocked(name=" + sessionState.name.getClassName()
+ ")");
}
// Set up a callback to send the session token.
@@ -275,7 +297,7 @@
@Override
public void onSessionCreated(ITvInputSession session) {
if (DEBUG) {
- Log.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")");
+ Slog.d(TAG, "onSessionCreated(name=" + sessionState.name.getClassName() + ")");
}
synchronized (mLock) {
sessionState.session = session;
@@ -295,7 +317,7 @@
try {
service.createSession(callback);
} catch (RemoteException e) {
- Log.e(TAG, "error in createSession", e);
+ Slog.e(TAG, "error in createSession", e);
removeSessionStateLocked(sessionToken, userId);
sendSessionTokenToClientLocked(sessionState.client, sessionState.name, null,
sessionState.seq, userId);
@@ -307,7 +329,7 @@
try {
client.onSessionCreated(name, sessionToken, seq);
} catch (RemoteException exception) {
- Log.e(TAG, "error in onSessionCreated", exception);
+ Slog.e(TAG, "error in onSessionCreated", exception);
}
if (sessionToken == null) {
@@ -321,6 +343,14 @@
UserState userState = getUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.remove(sessionToken);
+ // Close the open log entry, if any.
+ if (sessionState.logUri != null) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = sessionState.logUri;
+ args.arg2 = System.currentTimeMillis();
+ mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args).sendToTarget();
+ }
+
// Also remove the session token from the session token list of the current service.
ServiceState serviceState = userState.serviceStateMap.get(sessionState.name);
if (serviceState != null) {
@@ -380,7 +410,7 @@
UserState userState = getUserStateLocked(resolvedUserId);
ServiceState serviceState = userState.serviceStateMap.get(name);
if (serviceState == null) {
- serviceState = new ServiceState(name, resolvedUserId);
+ serviceState = new ServiceState(resolvedUserId);
userState.serviceStateMap.put(name, serviceState);
}
IBinder iBinder = client.asBinder();
@@ -396,7 +426,7 @@
try {
serviceState.service.registerCallback(serviceState.callback);
} catch (RemoteException e) {
- Log.e(TAG, "error in registerCallback", e);
+ Slog.e(TAG, "error in registerCallback", e);
}
} else {
updateServiceConnectionLocked(name, resolvedUserId);
@@ -432,7 +462,7 @@
try {
serviceState.service.unregisterCallback(serviceState.callback);
} catch (RemoteException e) {
- Log.e(TAG, "error in unregisterCallback", e);
+ Slog.e(TAG, "error in unregisterCallback", e);
} finally {
serviceState.callback = null;
updateServiceConnectionLocked(name, resolvedUserId);
@@ -464,7 +494,7 @@
// Also, add them to the session state map of the current service.
ServiceState serviceState = userState.serviceStateMap.get(name);
if (serviceState == null) {
- serviceState = new ServiceState(name, resolvedUserId);
+ serviceState = new ServiceState(resolvedUserId);
userState.serviceStateMap.put(name, serviceState);
}
serviceState.sessionTokens.add(sessionToken);
@@ -493,7 +523,7 @@
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).release();
} catch (RemoteException e) {
- Log.e(TAG, "error in release", e);
+ Slog.e(TAG, "error in release", e);
}
removeSessionStateLocked(sessionToken, resolvedUserId);
@@ -515,7 +545,7 @@
getSessionLocked(sessionToken, callingUid, resolvedUserId).setSurface(
surface);
} catch (RemoteException e) {
- Log.e(TAG, "error in setSurface", e);
+ Slog.e(TAG, "error in setSurface", e);
}
}
} finally {
@@ -535,7 +565,7 @@
getSessionLocked(sessionToken, callingUid, resolvedUserId).setVolume(
volume);
} catch (RemoteException e) {
- Log.e(TAG, "error in setVolume", e);
+ Slog.e(TAG, "error in setVolume", e);
}
}
} finally {
@@ -551,13 +581,39 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- SessionState sessionState = getUserStateLocked(resolvedUserId)
- .sessionStateMap.get(sessionToken);
- final String serviceName = sessionState.name.getClassName();
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(channelUri);
+
+ long currentTime = System.currentTimeMillis();
+ long channelId = ContentUris.parseId(channelUri);
+
+ // Close the open log entry first, if any.
+ UserState userState = getUserStateLocked(resolvedUserId);
+ SessionState sessionState = userState.sessionStateMap.get(sessionToken);
+ if (sessionState.logUri != null) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = sessionState.logUri;
+ args.arg2 = currentTime;
+ mLogHandler.obtainMessage(LogHandler.MSG_CLOSE_ENTRY, args)
+ .sendToTarget();
+ }
+
+ // Create a log entry and fill it later.
+ ContentValues values = new ContentValues();
+ values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+ currentTime);
+ values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, 0);
+ values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
+
+ sessionState.logUri = mContentResolver.insert(
+ TvContract.WatchedPrograms.CONTENT_URI, values);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = sessionState.logUri;
+ args.arg2 = ContentUris.parseId(channelUri);
+ args.arg3 = currentTime;
+ mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
} catch (RemoteException e) {
- Log.e(TAG, "error in tune", e);
+ Slog.e(TAG, "error in tune", e);
return;
}
}
@@ -565,6 +621,67 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
+ int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "createOverlayView");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId)
+ .createOverlayView(windowToken, frame);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in createOverlayView", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void relayoutOverlayView(IBinder sessionToken, Rect frame, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "relayoutOverlayView");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId)
+ .relayoutOverlayView(frame);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in relayoutOverlayView", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void removeOverlayView(IBinder sessionToken, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "removeOverlayView");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId)
+ .removeOverlayView();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in removeOverlayView", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
}
private static final class UserState {
@@ -590,7 +707,7 @@
private boolean bound;
private boolean available;
- private ServiceState(ComponentName name, int userId) {
+ private ServiceState(int userId) {
this.connection = new InputServiceConnection(userId);
}
}
@@ -602,6 +719,7 @@
private final int callingUid;
private ITvInputSession session;
+ private Uri logUri;
private SessionState(ComponentName name, ITvInputClient client, int seq, int callingUid) {
this.name = name;
@@ -621,7 +739,7 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) {
- Log.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")");
+ Slog.d(TAG, "onServiceConnected(name=" + name.getClassName() + ")");
}
synchronized (mLock) {
ServiceState serviceState = getServiceStateLocked(name, mUserId);
@@ -633,7 +751,7 @@
try {
serviceState.service.registerCallback(serviceState.callback);
} catch (RemoteException e) {
- Log.e(TAG, "error in registerCallback", e);
+ Slog.e(TAG, "error in registerCallback", e);
}
}
@@ -647,7 +765,7 @@
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) {
- Log.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")");
+ Slog.d(TAG, "onServiceDisconnected(name=" + name.getClassName() + ")");
}
}
}
@@ -663,7 +781,7 @@
public void onAvailabilityChanged(ComponentName name, boolean isAvailable)
throws RemoteException {
if (DEBUG) {
- Log.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable="
+ Slog.d(TAG, "onAvailabilityChanged(name=" + name.getClassName() + ", isAvailable="
+ isAvailable + ")");
}
synchronized (mLock) {
@@ -676,4 +794,147 @@
}
}
}
+
+ private final class LogHandler extends Handler {
+ private static final int MSG_OPEN_ENTRY = 1;
+ private static final int MSG_UPDATE_ENTRY = 2;
+ private static final int MSG_CLOSE_ENTRY = 3;
+
+ public LogHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_OPEN_ENTRY: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Uri uri = (Uri) args.arg1;
+ long channelId = (long) args.arg2;
+ long time = (long) args.arg3;
+ onOpenEntry(uri, channelId, time);
+ args.recycle();
+ return;
+ }
+ case MSG_UPDATE_ENTRY: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Uri uri = (Uri) args.arg1;
+ long channelId = (long) args.arg2;
+ long time = (long) args.arg3;
+ onUpdateEntry(uri, channelId, time);
+ args.recycle();
+ return;
+ }
+ case MSG_CLOSE_ENTRY: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Uri uri = (Uri) args.arg1;
+ long time = (long) args.arg2;
+ onCloseEntry(uri, time);
+ args.recycle();
+ return;
+ }
+ default: {
+ Log.w(TAG, "Unhandled message code: " + msg.what);
+ return;
+ }
+ }
+ }
+
+ private void onOpenEntry(Uri uri, long channelId, long watchStarttime) {
+ String[] projection = {
+ TvContract.Programs.TITLE,
+ TvContract.Programs.START_TIME_UTC_MILLIS,
+ TvContract.Programs.END_TIME_UTC_MILLIS,
+ TvContract.Programs.DESCRIPTION
+ };
+ String selection = TvContract.Programs.CHANNEL_ID + "=? AND "
+ + TvContract.Programs.START_TIME_UTC_MILLIS + "<=? AND "
+ + TvContract.Programs.END_TIME_UTC_MILLIS + ">?";
+ String[] selectionArgs = {
+ String.valueOf(channelId),
+ String.valueOf(watchStarttime),
+ String.valueOf(watchStarttime)
+ };
+ String sortOrder = TvContract.Programs.START_TIME_UTC_MILLIS + " ASC";
+ Cursor cursor = null;
+ try {
+ cursor = mContentResolver.query(TvContract.Programs.CONTENT_URI, projection,
+ selection, selectionArgs, sortOrder);
+ if (cursor != null && cursor.moveToNext()) {
+ ContentValues values = new ContentValues();
+ values.put(TvContract.WatchedPrograms.TITLE, cursor.getString(0));
+ values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, cursor.getLong(1));
+ long endTime = cursor.getLong(2);
+ values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime);
+ values.put(TvContract.WatchedPrograms.DESCRIPTION, cursor.getString(3));
+ mContentResolver.update(uri, values, null, null);
+
+ // Schedule an update when the current program ends.
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = uri;
+ args.arg2 = channelId;
+ args.arg3 = endTime;
+ Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args);
+ sendMessageDelayed(msg, endTime - System.currentTimeMillis());
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ private void onUpdateEntry(Uri uri, long channelId, long time) {
+ String[] projection = {
+ TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.TITLE,
+ TvContract.WatchedPrograms.START_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.END_TIME_UTC_MILLIS,
+ TvContract.WatchedPrograms.DESCRIPTION
+ };
+ Cursor cursor = null;
+ try {
+ cursor = mContentResolver.query(uri, projection, null, null, null);
+ if (cursor != null && cursor.moveToNext()) {
+ long watchStartTime = cursor.getLong(0);
+ long watchEndTime = cursor.getLong(1);
+ String title = cursor.getString(2);
+ long startTime = cursor.getLong(3);
+ long endTime = cursor.getLong(4);
+ String description = cursor.getString(5);
+
+ // Do nothing if the current log entry is already closed.
+ if (watchEndTime > 0) {
+ return;
+ }
+
+ // The current program has just ended. Create a (complete) log entry off the
+ // current entry.
+ ContentValues values = new ContentValues();
+ values.put(TvContract.WatchedPrograms.WATCH_START_TIME_UTC_MILLIS,
+ watchStartTime);
+ values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, time);
+ values.put(TvContract.WatchedPrograms.CHANNEL_ID, channelId);
+ values.put(TvContract.WatchedPrograms.TITLE, title);
+ values.put(TvContract.WatchedPrograms.START_TIME_UTC_MILLIS, startTime);
+ values.put(TvContract.WatchedPrograms.END_TIME_UTC_MILLIS, endTime);
+ values.put(TvContract.WatchedPrograms.DESCRIPTION, description);
+ mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ // Re-open the current log entry with the next program information.
+ onOpenEntry(uri, channelId, time);
+ }
+
+ private void onCloseEntry(Uri uri, long watchEndTime) {
+ ContentValues values = new ContentValues();
+ values.put(TvContract.WatchedPrograms.WATCH_END_TIME_UTC_MILLIS, watchEndTime);
+ mContentResolver.update(uri, values, null, null);
+ }
+ }
}
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.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 @@
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/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index f17b2f4..9039236 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -162,13 +162,10 @@
private final Interpolator mThumbnailFadeoutInterpolator;
private int mCurrentUserId = 0;
- private boolean mUseAlternateThumbnailAnimation;
AppTransition(Context context, Handler h) {
mContext = context;
mH = h;
- mUseAlternateThumbnailAnimation =
- SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
mConfigShortAnimTime = context.getResources().getInteger(
com.android.internal.R.integer.config_shortAnimTime);
mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
@@ -668,7 +665,7 @@
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
int appWidth, int appHeight, int orientation,
- Rect containingFrame, Rect contentInsets) {
+ Rect containingFrame, Rect contentInsets, Configuration configuration) {
Animation a;
if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -689,7 +686,8 @@
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
- if (mUseAlternateThumbnailAnimation) {
+ boolean useAlternateThumbnailAnimation = (configuration.smallestScreenWidthDp < 600);
+ if (useAlternateThumbnailAnimation) {
a = createAlternateThumbnailEnterExitAnimationLocked(
getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
transit, containingFrame, contentInsets);
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
index fbfca93..35d19c1 100644
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -22,7 +22,6 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
@@ -40,6 +39,7 @@
private int mLastDH;
private boolean mDrawNeeded;
private Paint mPaint;
+ private int mRotation;
public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) {
SurfaceControl ctrl = null;
@@ -78,7 +78,26 @@
if (c == null) {
return;
}
- c.drawCircle(160, 160, 160, mPaint);
+ int cx = 160;
+ int cy = 160;
+ switch (mRotation) {
+ case Surface.ROTATION_0:
+ case Surface.ROTATION_90:
+ // chin bottom or right
+ cx = 160;
+ cy = 160;
+ break;
+ case Surface.ROTATION_180:
+ // chin top
+ cx = 160;
+ cy = 145;
+ break;
+ case Surface.ROTATION_270:
+ cx = 145;
+ cy = 160;
+ break;
+ }
+ c.drawCircle(cx, cy, 160, mPaint);
mSurface.unlockCanvasAndPost(c);
}
@@ -97,7 +116,7 @@
}
}
- void positionSurface(int dw, int dh) {
+ void positionSurface(int dw, int dh, int rotation) {
if (mLastDW == dw && mLastDH == dh) {
return;
}
@@ -105,6 +124,7 @@
mLastDH = dh;
mSurfaceControl.setSize(dw, dh);
mDrawNeeded = true;
+ mRotation = rotation;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 524d78b..637beec 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -287,8 +287,6 @@
private static final String DENSITY_OVERRIDE = "ro.config.density_override";
private static final String SIZE_OVERRIDE = "ro.config.size_override";
- private static final String SCREEN_CIRCULAR = "ro.display.circular";
-
private static final int MAX_SCREENSHOT_RETRIES = 3;
final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -3192,7 +3190,7 @@
}
Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
- mCurConfiguration.orientation, containingFrame, contentInsets);
+ mCurConfiguration.orientation, containingFrame, contentInsets, mCurConfiguration);
if (a != null) {
if (DEBUG_ANIM) {
RuntimeException e = null;
@@ -5489,7 +5487,9 @@
}
public void showCircularDisplayMaskIfNeeded() {
- if (SystemProperties.getBoolean(SCREEN_CIRCULAR, false)) {
+ // we're fullscreen and not hosted in an ActivityView
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_windowIsRound)) {
mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK));
}
}
@@ -8660,8 +8660,7 @@
wtoken.deferClearAllDrawn = false;
}
- boolean useAlternateThumbnailAnimation =
- SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
+ boolean useAlternateThumbnailAnimation = (mCurConfiguration.smallestScreenWidthDp < 600);
AppWindowAnimator appAnimator =
topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
@@ -9001,7 +9000,7 @@
mStrictModeFlash.positionSurface(defaultDw, defaultDh);
}
if (mCircularDisplayMask != null) {
- mCircularDisplayMask.positionSurface(defaultDw, defaultDh);
+ mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation);
}
boolean focusDisplayed = false;
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 1b3887c..51583a5 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -11,7 +11,9 @@
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
$(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
new file mode 100644
index 0000000..f3e8f3c
--- /dev/null
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "HdmiCecControllerJni"
+
+#define LOG_NDEBUG 1
+
+#include "JNIHelp.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <hardware/hdmi_cec.h>
+
+namespace android {
+
+static struct {
+ jmethodID handleMessage;
+} gHdmiCecControllerClassInfo;
+
+
+class HdmiCecController {
+public:
+ HdmiCecController(jobject callbacksObj);
+
+private:
+ static void onReceived(const hdmi_event_t* event, void* arg);
+
+ jobject mCallbacksObj;
+};
+
+HdmiCecController::HdmiCecController(jobject callbacksObj) :
+ mCallbacksObj(callbacksObj) {
+}
+
+// static
+void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
+ HdmiCecController* handler = static_cast<HdmiCecController*>(arg);
+ if (handler == NULL) {
+ return;
+ }
+
+ // TODO: propagate message to Java layer.
+}
+
+
+//------------------------------------------------------------------------------
+static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) {
+ // TODO: initialize hal and pass it to controller if ready.
+
+ HdmiCecController* controller = new HdmiCecController(
+ env->NewGlobalRef(callbacksObj));
+
+ return reinterpret_cast<jlong>(controller);
+}
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J",
+ (void *) nativeInit },
+};
+
+#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
+
+int register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bf9f7f4..1feb325 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -38,7 +38,9 @@
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_dreams_McuHal(JNIEnv* env);
+int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_hdmi_HdmiCecService(JNIEnv* env);
+int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
};
using namespace android;
@@ -72,7 +74,10 @@
register_android_server_ConsumerIrService(env);
register_android_server_dreams_McuHal(env);
register_android_server_BatteryStatsService(env);
+ register_android_server_hdmi_HdmiCecController(env);
+ // TODO: remove this once replaces HdmiCecService with HdmiControlService.
register_android_server_hdmi_HdmiCecService(env);
+ register_android_server_hdmi_HdmiMhlController(env);
return JNI_VERSION_1_4;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 1b048a1..629dea2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -53,6 +53,7 @@
private static final String ATTR_NAME = "name";
private static final String ATTR_PACKAGE = "package";
private static final String ATTR_USERID = "userId";
+ private static final String ATTR_ENABLED = "profileEnabled";
private AtomicFile fileForWriting;
@@ -61,11 +62,10 @@
private OutputStream mOutputStreamForTest;
// Internal state for the device owner package.
- private String mDeviceOwnerPackageName;
- private String mDeviceOwnerName;
+ private OwnerInfo mDeviceOwner;
// Internal state for the profile owner packages.
- private final HashMap<Integer, String[]> mProfileOwners = new HashMap<Integer, String[]>();
+ private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
// Private default constructor.
private DeviceOwner() {
@@ -95,8 +95,7 @@
*/
static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
DeviceOwner owner = new DeviceOwner();
- owner.mDeviceOwnerPackageName = packageName;
- owner.mDeviceOwnerName = ownerName;
+ owner.mDeviceOwner = new OwnerInfo(ownerName, packageName);
return owner;
}
@@ -105,25 +104,25 @@
*/
static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) {
DeviceOwner owner = new DeviceOwner();
- owner.mProfileOwners.put(userId, new String[] { packageName, ownerName });
+ owner.mProfileOwners.put(
+ userId, new OwnerInfo(ownerName, packageName, false /* disabled */));
return owner;
}
String getDeviceOwnerPackageName() {
- return mDeviceOwnerPackageName;
+ return mDeviceOwner != null ? mDeviceOwner.packageName : null;
}
String getDeviceOwnerName() {
- return mDeviceOwnerName;
+ return mDeviceOwner != null ? mDeviceOwner.name : null;
}
void setDeviceOwner(String packageName, String ownerName) {
- mDeviceOwnerPackageName = packageName;
- mDeviceOwnerName = ownerName;
+ mDeviceOwner = new OwnerInfo(ownerName, packageName);
}
void setProfileOwner(String packageName, String ownerName, int userId) {
- mProfileOwners.put(userId, new String[] { packageName, ownerName });
+ mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName, false /* disabled */));
}
void removeProfileOwner(int userId) {
@@ -131,17 +130,30 @@
}
String getProfileOwnerPackageName(int userId) {
- String[] profileOwner = mProfileOwners.get(userId);
- return profileOwner != null ? profileOwner[0] : null;
+ OwnerInfo profileOwner = mProfileOwners.get(userId);
+ return profileOwner != null ? profileOwner.packageName : null;
}
String getProfileOwnerName(int userId) {
- String[] profileOwner = mProfileOwners.get(userId);
- return profileOwner != null ? profileOwner[1] : null;
+ OwnerInfo profileOwner = mProfileOwners.get(userId);
+ return profileOwner != null ? profileOwner.name : null;
+ }
+
+ boolean isProfileEnabled(int userId) {
+ OwnerInfo profileOwner = mProfileOwners.get(userId);
+ return profileOwner != null ? profileOwner.enabled : true;
+ }
+
+ void setProfileEnabled(int userId) {
+ OwnerInfo profileOwner = mProfileOwners.get(userId);
+ if (profileOwner == null) {
+ throw new IllegalArgumentException("No profile owner exists.");
+ }
+ profileOwner.enabled = true;
}
boolean hasDeviceOwner() {
- return mDeviceOwnerPackageName != null;
+ return mDeviceOwner != null;
}
static boolean isInstalled(String packageName, PackageManager pm) {
@@ -185,14 +197,18 @@
String tag = parser.getName();
if (tag.equals(TAG_DEVICE_OWNER)) {
- mDeviceOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
- mDeviceOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+ mDeviceOwner = new OwnerInfo(
+ parser.getAttributeValue(null, ATTR_NAME),
+ parser.getAttributeValue(null, ATTR_PACKAGE));
} else if (tag.equals(TAG_PROFILE_OWNER)) {
String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+ Boolean profileEnabled = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_ENABLED));
int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
mProfileOwners.put(userId,
- new String[] { profileOwnerPackageName, profileOwnerName });
+ new OwnerInfo(
+ profileOwnerPackageName, profileOwnerName, profileEnabled));
} else {
throw new XmlPullParserException(
"Unexpected tag in device owner file: " + tag);
@@ -220,21 +236,22 @@
out.startDocument(null, true);
// Write device owner tag
- if (mDeviceOwnerPackageName != null) {
+ if (mDeviceOwner != null) {
out.startTag(null, TAG_DEVICE_OWNER);
- out.attribute(null, ATTR_PACKAGE, mDeviceOwnerPackageName);
- if (mDeviceOwnerName != null) {
- out.attribute(null, ATTR_NAME, mDeviceOwnerName);
+ out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
+ if (mDeviceOwner.packageName != null) {
+ out.attribute(null, ATTR_NAME, mDeviceOwner.packageName);
}
out.endTag(null, TAG_DEVICE_OWNER);
}
// Write profile owner tags
if (mProfileOwners.size() > 0) {
- for (HashMap.Entry<Integer, String[]> owner : mProfileOwners.entrySet()) {
+ for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
out.startTag(null, TAG_PROFILE_OWNER);
- out.attribute(null, ATTR_PACKAGE, owner.getValue()[0]);
- out.attribute(null, ATTR_NAME, owner.getValue()[1]);
+ out.attribute(null, ATTR_PACKAGE, owner.getValue().packageName);
+ out.attribute(null, ATTR_NAME, owner.getValue().name);
+ out.attribute(null, ATTR_ENABLED, String.valueOf(owner.getValue().enabled));
out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
out.endTag(null, TAG_PROFILE_OWNER);
}
@@ -271,4 +288,20 @@
fileForWriting.finishWrite((FileOutputStream) stream);
}
}
+
+ static class OwnerInfo {
+ public String name;
+ public String packageName;
+ public boolean enabled = true; // only makes sense for managed profiles
+
+ public OwnerInfo(String name, String packageName, boolean enabled) {
+ this(name, packageName);
+ this.enabled = enabled;
+ }
+
+ public OwnerInfo(String name, String packageName) {
+ this.name = name;
+ this.packageName = packageName;
+ }
+ }
}
\ No newline at end of file
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d6f9dea..f1ee280 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2828,7 +2828,7 @@
return null;
}
synchronized (this) {
- if (mDeviceOwner != null) {
+ if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
return mDeviceOwner.getDeviceOwnerPackageName();
}
}
@@ -2900,9 +2900,13 @@
}
// Check if this is the profile owner who is calling
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- Slog.d(LOG_TAG, "Enabling the profile for: " + UserHandle.getCallingUserId());
- long id = Binder.clearCallingIdentity();
+ int userId = UserHandle.getCallingUserId();
+ Slog.d(LOG_TAG, "Enabling the profile for: " + userId);
+ mDeviceOwner.setProfileEnabled(userId);
+ mDeviceOwner.writeOwnerFile();
+
+ long id = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId()));
@@ -2944,6 +2948,23 @@
return null;
}
+ @Override
+ public boolean isProfileEnabled(int userHandle) {
+ if (!mHasFeature) {
+ // If device policy management is not enabled, then the userHandle cannot belong to a
+ // managed profile. All other profiles are considered enabled.
+ return true;
+ }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+
+ synchronized (this) {
+ if (mDeviceOwner != null) {
+ return mDeviceOwner.isProfileEnabled(userHandle);
+ }
+ }
+ return true;
+ }
+
private boolean isDeviceProvisioned() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) > 0;
@@ -3097,4 +3118,24 @@
}
}
}
+
+ @Override
+ public void setUserRestriction(ComponentName who, String key, boolean enabled) {
+ final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
+
+ synchronized (this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ UserManager um = UserManager.get(mContext);
+ long id = Binder.clearCallingIdentity();
+ try {
+ um.setUserRestriction(key, enabled, userHandle);
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 912ac4d..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.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;
@@ -61,6 +62,7 @@
import com.android.server.content.ContentService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
+import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
import com.android.server.lights.LightsManager;
import com.android.server.lights.LightsService;
@@ -114,6 +116,8 @@
"com.android.server.devicepolicy.DevicePolicyManagerService$Lifecycle";
private static final String APPWIDGET_SERVICE_CLASS =
"com.android.server.appwidget.AppWidgetService";
+ private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS =
+ "com.android.server.voiceinteraction.VoiceInteractionManagerService";
private static final String PRINT_MANAGER_SERVICE_CLASS =
"com.android.server.print.PrintManagerService";
private static final String USB_SERVICE_CLASS =
@@ -198,6 +202,10 @@
// 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);
@@ -290,6 +298,7 @@
// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
+ mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
}
private void startCoreServices() {
@@ -311,6 +320,7 @@
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
ConnectivityService connectivity = null;
+ NetworkScoreService networkScore = null;
NsdService serviceDiscovery= null;
IPackageManager pm = null;
WindowManagerService wm = null;
@@ -643,6 +653,14 @@
}
try {
+ Slog.i(TAG, "Network Score Service");
+ networkScore = new NetworkScoreService(context);
+ ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
+ } catch (Throwable e) {
+ reportWtf("starting Network Score Service", e);
+ }
+
+ try {
Slog.i(TAG, "Network Service Discovery Service");
serviceDiscovery = NsdService.create(context);
ServiceManager.addService(
@@ -817,6 +835,15 @@
} catch (Throwable e) {
reportWtf("starting Recognition Service", e);
}
+
+ try {
+ if (pm.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) {
+ Slog.i(TAG, "Voice Recognition Service");
+ mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
+ }
+ } catch (Throwable e) {
+ reportWtf("starting Voice Recognition Service", e);
+ }
}
try {
@@ -910,6 +937,12 @@
}
try {
+ mSystemServiceManager.startService(HdmiControlService.class);
+ } catch (Throwable e) {
+ reportWtf("starting HdmiControlService", e);
+ }
+
+ try {
Slog.i(TAG, "TvInputManagerService");
mSystemServiceManager.startService(TvInputManagerService.class);
} catch (Throwable e) {
@@ -1021,6 +1054,7 @@
final NetworkStatsService networkStatsF = networkStats;
final NetworkPolicyManagerService networkPolicyF = networkPolicy;
final ConnectivityService connectivityF = connectivity;
+ final NetworkScoreService networkScoreF = networkScore;
final DockObserver dockF = dock;
final WallpaperManagerService wallpaperF = wallpaper;
final InputMethodManagerService immF = imm;
@@ -1069,6 +1103,11 @@
reportWtf("making Battery Service ready", e);
}
try {
+ if (networkScoreF != null) networkScoreF.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making Network Score Service ready", e);
+ }
+ try {
if (networkManagementF != null) networkManagementF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Managment Service ready", e);
diff --git a/services/voiceinteraction/Android.mk b/services/voiceinteraction/Android.mk
new file mode 100644
index 0000000..c9e5dd0
--- /dev/null
+++ b/services/voiceinteraction/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.voiceinteraction
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
new file mode 100644
index 0000000..9e2bcab
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -0,0 +1,209 @@
+/*
+ * 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.server.voiceinteraction;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.voice.IVoiceInteractionService;
+import android.service.voice.IVoiceInteractionSession;
+import android.util.Slog;
+import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.SystemService;
+import com.android.server.UiThread;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+
+/**
+ * SystemService that publishes an IVoiceInteractionManagerService.
+ */
+public class VoiceInteractionManagerService extends SystemService {
+
+ static final String TAG = "VoiceInteractionManagerService";
+
+ final Context mContext;
+ final ContentResolver mResolver;
+
+ public VoiceInteractionManagerService(Context context) {
+ super(context);
+ mContext = context;
+ mResolver = context.getContentResolver();
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mServiceStub.systemRunning(isSafeMode());
+ }
+ }
+
+ @Override
+ public void onSwitchUser(int userHandle) {
+ mServiceStub.switchUser(userHandle);
+ }
+
+ // implementation entry point and binder service
+ private final VoiceInteractionManagerServiceStub mServiceStub
+ = new VoiceInteractionManagerServiceStub();
+
+ class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
+
+ VoiceInteractionManagerServiceImpl mImpl;
+
+ private boolean mSafeMode;
+ private int mCurUser;
+
+ public void systemRunning(boolean safeMode) {
+ mSafeMode = safeMode;
+
+ mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
+ UserHandle.ALL, true);
+ new SettingsObserver(UiThread.getHandler());
+
+ synchronized (this) {
+ mCurUser = ActivityManager.getCurrentUser();
+ switchImplementationIfNeededLocked();
+ }
+ }
+
+ public void switchUser(int userHandle) {
+ synchronized (this) {
+ mCurUser = userHandle;
+ switchImplementationIfNeededLocked();
+ }
+ }
+
+ void switchImplementationIfNeededLocked() {
+ if (!mSafeMode) {
+ String curService = Settings.Secure.getStringForUser(
+ mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
+ ComponentName serviceComponent = null;
+ if (curService != null && !curService.isEmpty()) {
+ try {
+ serviceComponent = ComponentName.unflattenFromString(curService);
+ } catch (RuntimeException e) {
+ Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
+ serviceComponent = null;
+ }
+ }
+ if (mImpl == null || mImpl.mUser != mCurUser
+ || !mImpl.mComponent.equals(serviceComponent)) {
+ if (mImpl != null) {
+ mImpl.shutdownLocked();
+ }
+ if (serviceComponent != null) {
+ mImpl = new VoiceInteractionManagerServiceImpl(mContext,
+ UiThread.getHandler(), this, mCurUser, serviceComponent);
+ mImpl.startLocked();
+ } else {
+ mImpl = null;
+ }
+ }
+ }
+ }
+
+ @Override
+ public int startVoiceActivity(Intent intent, String resolvedType,
+ IVoiceInteractionService service,
+ IVoiceInteractionSession session, IVoiceInteractor interactor) {
+ synchronized (this) {
+ if (mImpl == null || service.asBinder() != mImpl.mService.asBinder()) {
+ throw new SecurityException(
+ "Caller is not the current voice interaction service");
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.startVoiceActivityLocked(callingPid, callingUid,
+ intent, resolvedType, session, interactor);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+ }
+
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.VOICE_INTERACTION_SERVICE), false, this);
+ }
+
+ @Override public void onChange(boolean selfChange) {
+ synchronized (VoiceInteractionManagerServiceStub.this) {
+ switchImplementationIfNeededLocked();
+ }
+ }
+ }
+
+ PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ return super.onHandleForceStop(intent, packages, uid, doit);
+ }
+
+ @Override
+ public void onHandleUserStop(Intent intent, int userHandle) {
+ super.onHandleUserStop(intent, userHandle);
+ }
+
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ super.onPackageDisappeared(packageName, reason);
+ }
+
+ @Override
+ public void onPackageAppeared(String packageName, int reason) {
+ super.onPackageAppeared(packageName, reason);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ super.onPackageModified(packageName);
+ }
+
+ @Override
+ public void onSomePackagesChanged() {
+ super.onSomePackagesChanged();
+ }
+ };
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
new file mode 100644
index 0000000..af8ae1e
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.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 com.android.server.voiceinteraction;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+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.VoiceInteractionService;
+import android.util.Slog;
+import com.android.internal.app.IVoiceInteractor;
+
+class VoiceInteractionManagerServiceImpl {
+ final static String TAG = "VoiceInteractionServiceManager";
+
+ final Context mContext;
+ final Handler mHandler;
+ final Object mLock;
+ final int mUser;
+ final ComponentName mComponent;
+ final IActivityManager mAm;
+ boolean mBound = false;
+ IVoiceInteractionService mService;
+ IVoiceInteractionSession mActiveSession;
+ IVoiceInteractor mActiveInteractor;
+
+ final ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mService = IVoiceInteractionService.Stub.asInterface(service);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+ };
+
+ VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock,
+ int userHandle, ComponentName service) {
+ mContext = context;
+ mHandler = handler;
+ mLock = lock;
+ 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");
+ }
+ if (interactor == null) {
+ throw new NullPointerException("interactor is null");
+ }
+ if (mActiveSession != null) {
+ // XXX cancel current session.
+ }
+ intent.addCategory(Intent.CATEGORY_VOICE);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ mActiveSession = session;
+ mActiveInteractor = interactor;
+ try {
+ return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
+ intent, resolvedType, mActiveSession, mActiveInteractor,
+ 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;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Unable to find voice interaction service: " + mComponent, e);
+ return;
+ }
+ mContext.bindServiceAsUser(intent, mConnection,
+ Context.BIND_AUTO_CREATE, new UserHandle(mUser));
+ mBound = true;
+ }
+
+ void shutdownLocked() {
+ if (mBound) {
+ mContext.unbindService(mConnection);
+ mBound = false;
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
index 4a9ae39..96069213 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
+++ b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
@@ -23,6 +23,7 @@
* Data connection real time information
*
* TODO: How to handle multiple subscriptions?
+ * @hide
*/
public class DataConnectionRealTimeInfo implements Parcelable {
private long mTime; // Time the info was collected since boot in nanos;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 7c5c648..59ec6f5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -18,6 +18,7 @@
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -199,7 +200,67 @@
*/
public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO = 0x00002000;
+ private final Handler mHandler;
+
public PhoneStateListener() {
+ this(Looper.myLooper());
+ }
+
+ /** @hide */
+ public PhoneStateListener(Looper looper) {
+ mHandler = new Handler(looper) {
+ public void handleMessage(Message msg) {
+ //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what)
+ // + " msg=" + msg);
+ switch (msg.what) {
+ case LISTEN_SERVICE_STATE:
+ PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
+ break;
+ case LISTEN_SIGNAL_STRENGTH:
+ PhoneStateListener.this.onSignalStrengthChanged(msg.arg1);
+ break;
+ case LISTEN_MESSAGE_WAITING_INDICATOR:
+ PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0);
+ break;
+ case LISTEN_CALL_FORWARDING_INDICATOR:
+ PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0);
+ break;
+ case LISTEN_CELL_LOCATION:
+ PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj);
+ break;
+ case LISTEN_CALL_STATE:
+ PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
+ break;
+ case LISTEN_DATA_CONNECTION_STATE:
+ PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2);
+ PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1);
+ break;
+ case LISTEN_DATA_ACTIVITY:
+ PhoneStateListener.this.onDataActivity(msg.arg1);
+ break;
+ case LISTEN_SIGNAL_STRENGTHS:
+ PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
+ break;
+ case LISTEN_OTASP_CHANGED:
+ PhoneStateListener.this.onOtaspChanged(msg.arg1);
+ break;
+ case LISTEN_CELL_INFO:
+ PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
+ break;
+ case LISTEN_PRECISE_CALL_STATE:
+ PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
+ break;
+ case LISTEN_PRECISE_DATA_CONNECTION_STATE:
+ PhoneStateListener.this.onPreciseDataConnectionStateChanged(
+ (PreciseDataConnectionState)msg.obj);
+ break;
+ case LISTEN_DATA_CONNECTION_REAL_TIME_INFO:
+ PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
+ (DataConnectionRealTimeInfo)msg.obj);
+ break;
+ }
+ }
+ };
}
/**
@@ -424,56 +485,4 @@
dcRtInfo).sendToTarget();
}
};
-
- Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what) + " msg=" + msg);
- switch (msg.what) {
- case LISTEN_SERVICE_STATE:
- PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
- break;
- case LISTEN_SIGNAL_STRENGTH:
- PhoneStateListener.this.onSignalStrengthChanged(msg.arg1);
- break;
- case LISTEN_MESSAGE_WAITING_INDICATOR:
- PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0);
- break;
- case LISTEN_CALL_FORWARDING_INDICATOR:
- PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0);
- break;
- case LISTEN_CELL_LOCATION:
- PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj);
- break;
- case LISTEN_CALL_STATE:
- PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
- break;
- case LISTEN_DATA_CONNECTION_STATE:
- PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2);
- PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1);
- break;
- case LISTEN_DATA_ACTIVITY:
- PhoneStateListener.this.onDataActivity(msg.arg1);
- break;
- case LISTEN_SIGNAL_STRENGTHS:
- PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
- break;
- case LISTEN_OTASP_CHANGED:
- PhoneStateListener.this.onOtaspChanged(msg.arg1);
- break;
- case LISTEN_CELL_INFO:
- PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
- break;
- case LISTEN_PRECISE_CALL_STATE:
- PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
- break;
- case LISTEN_PRECISE_DATA_CONNECTION_STATE:
- PhoneStateListener.this.onPreciseDataConnectionStateChanged((PreciseDataConnectionState)msg.obj);
- break;
- case LISTEN_DATA_CONNECTION_REAL_TIME_INFO:
- PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
- (DataConnectionRealTimeInfo)msg.obj);
- break;
- }
- }
- };
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d5c7caa..407a8d1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1094,6 +1094,10 @@
public static final int SIM_STATE_NETWORK_LOCKED = 4;
/** SIM card state: Ready */
public static final int SIM_STATE_READY = 5;
+ /** SIM card state: SIM Card Error, Sim Card is present but faulty
+ *@hide
+ */
+ public static final int SIM_STATE_CARD_IO_ERROR = 6;
/**
* @return true if a ICC card is present
@@ -1120,6 +1124,7 @@
* @see #SIM_STATE_PUK_REQUIRED
* @see #SIM_STATE_NETWORK_LOCKED
* @see #SIM_STATE_READY
+ * @see #SIM_STATE_CARD_IO_ERROR
*/
public int getSimState() {
String prop = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE);
@@ -1138,6 +1143,9 @@
else if ("READY".equals(prop)) {
return SIM_STATE_READY;
}
+ else if ("CARD_IO_ERROR".equals(prop)) {
+ return SIM_STATE_CARD_IO_ERROR;
+ }
else {
return SIM_STATE_UNKNOWN;
}
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index 236bb2f..8029713 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -28,6 +28,8 @@
public static final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY";
/* ABSENT means ICC is missing */
public static final String INTENT_VALUE_ICC_ABSENT = "ABSENT";
+ /* CARD_IO_ERROR means for three consecutive times there was SIM IO error */
+ static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = "CARD_IO_ERROR";
/* LOCKED means ICC is locked by pin or by network */
public static final String INTENT_VALUE_ICC_LOCKED = "LOCKED";
/* READY means ICC is ready to access */
@@ -63,7 +65,8 @@
NETWORK_LOCKED,
READY,
NOT_READY,
- PERM_DISABLED;
+ PERM_DISABLED,
+ CARD_IO_ERROR;
public boolean isPinLocked() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
@@ -72,7 +75,7 @@
public boolean iccCardExist() {
return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)
|| (this == NETWORK_LOCKED) || (this == READY)
- || (this == PERM_DISABLED));
+ || (this == PERM_DISABLED) || (this == CARD_IO_ERROR));
}
}
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 0ad3456..5c2583b 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -867,5 +867,13 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".ProjectionClippingActivity"
+ android:label="Reordering/Projection Clipping">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/HwAccelerationTest/res/drawable/round_rect_background.xml b/tests/HwAccelerationTest/res/drawable/round_rect_background.xml
new file mode 100644
index 0000000..14d4073
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/round_rect_background.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android" >
+ <solid android:color="#eee" />
+ <corners android:radius="30dp" />
+</shape>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/res/layout/projection_clipping.xml b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
new file mode 100644
index 0000000..7caf90a
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/projection_clipping.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <FrameLayout
+ android:translationX="50dp"
+ android:translationY="50dp"
+ android:translationZ="30dp"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ android:background="@drawable/round_rect_background">
+ <View
+ android:id="@+id/clickable1"
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:background="?android:attr/selectableItemBackground"/>
+ <View
+ android:id="@+id/clickable2"
+ android:translationX="50dp"
+ android:translationY="10dp"
+ android:layout_width="150dp"
+ android:layout_height="100dp"
+ android:background="?android:attr/selectableItemBackground"/>
+ </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
new file mode 100644
index 0000000..2ae960b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java
@@ -0,0 +1,27 @@
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.RenderNode;
+import android.view.View;
+
+public class ProjectionClippingActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.projection_clipping);
+ View.OnClickListener listener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // woo! nothing!
+ }
+ };
+ findViewById(R.id.clickable1).setOnClickListener(listener);
+ findViewById(R.id.clickable2).setOnClickListener(listener);
+ }
+}
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index 7d6ba1d..504d471 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -25,6 +25,15 @@
android:name="com.android.onemedia.OnePlayerService"
android:exported="false"
android:process="com.android.onemedia.service" />
+ <service
+ android:name=".provider.OneMediaRouteProvider"
+ android:permission="android.permission.BIND_ROUTE_PROVIDER"
+ android:exported="true"
+ android:process="com.android.onemedia.provider">
+ <intent-filter>
+ <action android:name="com.android.media.session.MediaRouteProvider" />
+ </intent-filter>
+ </service>
</application>
</manifest>
diff --git a/tests/OneMedia/res/layout/activity_one_player.xml b/tests/OneMedia/res/layout/activity_one_player.xml
index 4208355..516562f 100644
--- a/tests/OneMedia/res/layout/activity_one_player.xml
+++ b/tests/OneMedia/res/layout/activity_one_player.xml
@@ -53,6 +53,12 @@
android:layout_weight="1"
android:text="@string/play_button" />
</LinearLayout>
+ <Button
+ android:id="@+id/route_button"
+ style="@style/BottomBarButton"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/route_button" />
<TextView
android:id="@+id/status"
android:layout_width="match_parent"
diff --git a/tests/OneMedia/res/values/strings.xml b/tests/OneMedia/res/values/strings.xml
index 1b0cebb..3735c8d 100644
--- a/tests/OneMedia/res/values/strings.xml
+++ b/tests/OneMedia/res/values/strings.xml
@@ -7,6 +7,7 @@
<string name="start_button">Start</string>
<string name="play_button">Play</string>
+ <string name="route_button">Change route</string>
<string name="media_content_hint">Content</string>
<string name="media_next_hint">Next content</string>
<string name="has_video">Is video</string>
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
index 2b14384..189fa6a 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
@@ -15,8 +15,8 @@
package com.android.onemedia;
-import android.media.session.MediaSessionToken;
+import android.media.session.SessionToken;
interface IPlayerCallback {
- void onSessionChanged(in MediaSessionToken session);
+ void onSessionChanged(in SessionToken session);
}
\ No newline at end of file
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
index efdbe9a..15ea25f 100644
--- a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
@@ -15,14 +15,14 @@
package com.android.onemedia;
-import android.media.session.MediaSessionToken;
+import android.media.session.SessionToken;
import android.os.Bundle;
import com.android.onemedia.IPlayerCallback;
import com.android.onemedia.playback.IRequestCallback;
interface IPlayerService {
- MediaSessionToken getSessionToken();
+ SessionToken getSessionToken();
void registerCallback(in IPlayerCallback cb);
void unregisterCallback(in IPlayerCallback cb);
void sendRequest(String action, in Bundle params, in IRequestCallback cb);
diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
index 3114ca9..b9a6470 100644
--- a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
+++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
@@ -37,6 +37,7 @@
private Button mStartButton;
private Button mPlayButton;
+ private Button mRouteButton;
private TextView mStatusView;
private EditText mContentText;
@@ -54,6 +55,7 @@
mStartButton = (Button) findViewById(R.id.start_button);
mPlayButton = (Button) findViewById(R.id.play_button);
+ mRouteButton = (Button) findViewById(R.id.route_button);
mStatusView = (TextView) findViewById(R.id.status);
mContentText = (EditText) findViewById(R.id.content);
mNextContentText = (EditText) findViewById(R.id.next_content);
@@ -61,6 +63,7 @@
mStartButton.setOnClickListener(mButtonListener);
mPlayButton.setOnClickListener(mButtonListener);
+ mRouteButton.setOnClickListener(mButtonListener);
}
@@ -107,6 +110,9 @@
Log.d(TAG, "Start button pressed, in state " + mPlaybackState);
mPlayer.setContent(mContentText.getText().toString());
break;
+ case R.id.route_button:
+ mPlayer.showRoutePicker();
+ break;
}
}
@@ -117,6 +123,7 @@
public void onPlaybackStateChange(PlaybackState state) {
mPlaybackState = state.getState();
boolean enablePlay = false;
+ boolean enableControls = true;
StringBuilder statusBuilder = new StringBuilder();
switch (mPlaybackState) {
case PlaybackState.PLAYSTATE_PLAYING:
@@ -143,12 +150,17 @@
case PlaybackState.PLAYSTATE_NONE:
statusBuilder.append("none");
break;
+ case PlaybackState.PLAYSTATE_CONNECTING:
+ statusBuilder.append("connecting");
+ enableControls = false;
+ break;
default:
statusBuilder.append(mPlaybackState);
}
statusBuilder.append(" -- At position: ").append(state.getPosition());
mStatusView.setText(statusBuilder.toString());
mPlayButton.setEnabled(enablePlay);
+ setControlsEnabled(enableControls);
}
@Override
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
index e831ec6..e3f5c0c 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -16,9 +16,10 @@
*/
package com.android.onemedia;
-import android.media.session.MediaController;
+import android.media.session.SessionController;
import android.media.session.MediaMetadata;
-import android.media.session.MediaSessionManager;
+import android.media.session.RouteInfo;
+import android.media.session.SessionManager;
import android.media.session.PlaybackState;
import android.media.session.TransportController;
import android.os.Bundle;
@@ -39,7 +40,7 @@
public static final int STATE_DISCONNECTED = 0;
public static final int STATE_CONNECTED = 1;
- protected MediaController mController;
+ protected SessionController mController;
protected IPlayerService mBinder;
protected TransportController mTransportControls;
@@ -48,7 +49,7 @@
private Listener mListener;
private TransportListener mTransportListener = new TransportListener();
private SessionCallback mControllerCb;
- private MediaSessionManager mManager;
+ private SessionManager mManager;
private Handler mHandler = new Handler();
private boolean mResumed;
@@ -61,7 +62,7 @@
mServiceIntent = serviceIntent;
}
mControllerCb = new SessionCallback();
- mManager = (MediaSessionManager) context
+ mManager = (SessionManager) context
.getSystemService(Context.MEDIA_SESSION_SERVICE);
mResumed = false;
@@ -121,6 +122,10 @@
}
}
+ public void showRoutePicker() {
+ mController.showRoutePicker();
+ }
+
private void unbindFromService() {
mContext.unbindService(mServiceConnection);
}
@@ -150,7 +155,7 @@
mBinder = IPlayerService.Stub.asInterface(service);
Log.d(TAG, "service is " + service + " binder is " + mBinder);
try {
- mController = MediaController.fromToken(mBinder.getSessionToken());
+ mController = SessionController.fromToken(mBinder.getSessionToken());
} catch (RemoteException e) {
Log.e(TAG, "Error getting session", e);
return;
@@ -171,9 +176,9 @@
}
};
- private class SessionCallback extends MediaController.Callback {
+ private class SessionCallback extends SessionController.Callback {
@Override
- public void onRouteChanged(Bundle route) {
+ public void onRouteChanged(RouteInfo route) {
// TODO
}
}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
index 0ad6dd1..8b53ddf 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerService.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
@@ -17,7 +17,7 @@
import android.app.Service;
import android.content.Intent;
-import android.media.session.MediaSessionToken;
+import android.media.session.SessionToken;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.IBinder;
@@ -149,7 +149,7 @@
}
@Override
- public MediaSessionToken getSessionToken() throws RemoteException {
+ public SessionToken getSessionToken() throws RemoteException {
return mSession.getSessionToken();
}
}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
index a2d7897e..5dc3904 100644
--- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -17,9 +17,13 @@
import android.content.Context;
import android.content.Intent;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionToken;
+import android.media.session.Route;
+import android.media.session.RouteInfo;
+import android.media.session.RouteOptions;
+import android.media.session.RoutePlaybackControls;
+import android.media.session.Session;
+import android.media.session.SessionManager;
+import android.media.session.SessionToken;
import android.media.session.PlaybackState;
import android.media.session.TransportPerformer;
import android.os.Bundle;
@@ -27,41 +31,55 @@
import android.view.KeyEvent;
import com.android.onemedia.playback.LocalRenderer;
+import com.android.onemedia.playback.OneMRPRenderer;
import com.android.onemedia.playback.Renderer;
-import com.android.onemedia.playback.RendererFactory;
+import com.android.onemedia.playback.RequestUtils;
+
+import java.util.ArrayList;
public class PlayerSession {
private static final String TAG = "PlayerSession";
- protected MediaSession mSession;
+ protected Session mSession;
protected Context mContext;
- protected RendererFactory mRendererFactory;
- protected LocalRenderer mRenderer;
- protected MediaSession.Callback mCallback;
+ protected Renderer mRenderer;
+ protected Session.Callback mCallback;
protected Renderer.Listener mRenderListener;
protected TransportPerformer mPerformer;
protected PlaybackState mPlaybackState;
protected Listener mListener;
+ protected ArrayList<RouteOptions> mRouteOptions;
+ protected Route mRoute;
+ protected RoutePlaybackControls mRouteControls;
+ protected RouteListener mRouteListener;
+
+ private String mContent;
public PlayerSession(Context context) {
mContext = context;
- mRendererFactory = new RendererFactory();
mRenderer = new LocalRenderer(context, null);
- mCallback = new ControllerCb();
+ mCallback = new SessionCb();
mRenderListener = new RenderListener();
mPlaybackState = new PlaybackState();
mPlaybackState.setActions(PlaybackState.ACTION_PAUSE
| PlaybackState.ACTION_PLAY);
mRenderer.registerListener(mRenderListener);
+
+ // TODO need an easier way to build route options
+ mRouteOptions = new ArrayList<RouteOptions>();
+ RouteOptions.Builder bob = new RouteOptions.Builder();
+ bob.addInterface(RoutePlaybackControls.NAME);
+ mRouteOptions.add(bob.build());
+ mRouteListener = new RouteListener();
}
public void createSession() {
if (mSession != null) {
mSession.release();
}
- MediaSessionManager man = (MediaSessionManager) mContext
+ SessionManager man = (SessionManager) mContext
.getSystemService(Context.MEDIA_SESSION_SERVICE);
Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
mSession = man.createSession("OneMedia");
@@ -69,6 +87,7 @@
mPerformer = mSession.setTransportPerformerEnabled();
mPerformer.addListener(new TransportListener());
mPerformer.setPlaybackState(mPlaybackState);
+ mSession.setRouteOptions(mRouteOptions);
mSession.publish();
}
@@ -86,18 +105,24 @@
mListener = listener;
}
- public MediaSessionToken getSessionToken() {
+ public SessionToken getSessionToken() {
return mSession.getSessionToken();
}
public void setContent(Bundle request) {
mRenderer.setContent(request);
+ mContent = request.getString(RequestUtils.EXTRA_KEY_SOURCE);
}
public void setNextContent(Bundle request) {
mRenderer.setNextContent(request);
}
+ private void updateState(int newState) {
+ mPlaybackState.setState(newState);
+ mPerformer.setPlaybackState(mPlaybackState);
+ }
+
public interface Listener {
public void onPlayStateChanged(PlaybackState state);
}
@@ -145,7 +170,11 @@
mPlaybackState.setErrorMessage("unkown state");
break;
}
- mPlaybackState.setPosition(mRenderer.getSeekPosition());
+ if (mRenderer != null) {
+ mPlaybackState.setPosition(mRenderer.getSeekPosition());
+ } else {
+ mPlaybackState.setPosition(-1);
+ }
mPerformer.setPlaybackState(mPlaybackState);
if (mListener != null) {
mListener.onPlayStateChanged(mPlaybackState);
@@ -173,8 +202,7 @@
}
- private class ControllerCb extends MediaSession.Callback {
-
+ private class SessionCb extends Session.Callback {
@Override
public void onMediaButton(Intent mediaRequestIntent) {
if (Intent.ACTION_MEDIA_BUTTON.equals(mediaRequestIntent.getAction())) {
@@ -192,6 +220,40 @@
}
}
}
+
+ @Override
+ public void onRequestRouteChange(RouteInfo route) {
+ if (mRenderer != null) {
+ mRenderer.onStop();
+ }
+ if (route == null) {
+ // Use local route
+ mRoute = null;
+ mRenderer = new LocalRenderer(mContext, null);
+ mRenderer.registerListener(mRenderListener);
+ updateState(PlaybackState.PLAYSTATE_NONE);
+ } else {
+ // Use remote route
+ mSession.connect(route, mRouteOptions.get(0));
+ mRenderer = null;
+ updateState(PlaybackState.PLAYSTATE_CONNECTING);
+ }
+ }
+
+ @Override
+ public void onRouteConnected(Route route) {
+ mRoute = route;
+ mRouteControls = RoutePlaybackControls.from(route);
+ mRouteControls.addListener(mRouteListener);
+ Log.d(TAG, "Connected to route, registering listener");
+ mRenderer = new OneMRPRenderer(mRouteControls);
+ updateState(PlaybackState.PLAYSTATE_NONE);
+ }
+
+ @Override
+ public void onRouteDisconnected(Route route, int reason) {
+
+ }
}
private class TransportListener extends TransportPerformer.Listener {
@@ -206,4 +268,12 @@
}
}
+ private class RouteListener extends RoutePlaybackControls.Listener {
+ @Override
+ public void onPlaybackStateChange(int state) {
+ Log.d(TAG, "Updating state to " + state);
+ updateState(state);
+ }
+ }
+
}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
index 7f62f66..c8a8d6c 100644
--- a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
+++ b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.onemedia.playback;
import org.apache.http.Header;
@@ -370,6 +385,8 @@
* Prepares the player for the given playback request. If the holder is null
* it is assumed this is an audio only source. If playOnReady is set to true
* the media will begin playing as soon as it can.
+ *
+ * @see RequestUtils for the set of valid keys.
*/
public void setContent(Bundle request, SurfaceHolder holder) {
String source = request.getString(RequestUtils.EXTRA_KEY_SOURCE);
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java b/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java
index f9e6794..05516d2 100644
--- a/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java
+++ b/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.onemedia.playback;
import android.os.Bundle;
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
new file mode 100644
index 0000000..9b0a2b2
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java
@@ -0,0 +1,44 @@
+package com.android.onemedia.playback;
+
+import android.media.session.RoutePlaybackControls;
+import android.os.Bundle;
+
+/**
+ * Renderer for communicating with the OneMRP route
+ */
+public class OneMRPRenderer extends Renderer {
+ private final RoutePlaybackControls mControls;
+
+ public OneMRPRenderer(RoutePlaybackControls controls) {
+ super(null, null);
+ mControls = controls;
+ }
+
+ @Override
+ public void setContent(Bundle request) {
+ mControls.playNow(request.getString(RequestUtils.EXTRA_KEY_SOURCE));
+ }
+
+ @Override
+ public boolean onStop() {
+ mControls.pause();
+ return true;
+ }
+
+ @Override
+ public boolean onPlay() {
+ mControls.resume();
+ return true;
+ }
+
+ @Override
+ public boolean onPause() {
+ mControls.pause();
+ return true;
+ }
+
+ @Override
+ public long getSeekPosition() {
+ return -1;
+ }
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java b/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java
index 72d936c..ac9da23 100644
--- a/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java
+++ b/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.onemedia.playback;
import android.os.Bundle;
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java b/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java
index 2451bdf..09debcf 100644
--- a/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java
+++ b/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.onemedia.playback;
import android.content.Context;
@@ -77,39 +92,54 @@
}
public boolean onPlay() {
- throw new UnsupportedOperationException("play is not supported.");
+ // TODO consider making these log warnings instead of crashes (or
+ // Log.wtf)
+ // throw new UnsupportedOperationException("play is not supported.");
+ return false;
}
public boolean onPause() {
- throw new UnsupportedOperationException("pause is not supported.");
+ // throw new UnsupportedOperationException("pause is not supported.");
+ return false;
}
public boolean onNext() {
- throw new UnsupportedOperationException("next is not supported.");
+ // throw new UnsupportedOperationException("next is not supported.");
+ return false;
}
public boolean onPrevious() {
- throw new UnsupportedOperationException("previous is not supported.");
+ // throw new
+ // UnsupportedOperationException("previous is not supported.");
+ return false;
}
public boolean onStop() {
- throw new UnsupportedOperationException("stop is not supported.");
+ // throw new UnsupportedOperationException("stop is not supported.");
+ return false;
}
public boolean onSeekTo(int time) {
- throw new UnsupportedOperationException("seekTo is not supported.");
+ // throw new UnsupportedOperationException("seekTo is not supported.");
+ return false;
}
public long getSeekPosition() {
- throw new UnsupportedOperationException("getSeekPosition is not supported.");
+ // throw new
+ // UnsupportedOperationException("getSeekPosition is not supported.");
+ return -1;
}
public long getDuration() {
- throw new UnsupportedOperationException("getDuration is not supported.");
+ // throw new
+ // UnsupportedOperationException("getDuration is not supported.");
+ return -1;
}
public int getPlayState() {
- throw new UnsupportedOperationException("getPlayState is not supported.");
+ // throw new
+ // UnsupportedOperationException("getPlayState is not supported.");
+ return 0;
}
public void onDestroy() {
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/RendererFactory.java b/tests/OneMedia/src/com/android/onemedia/playback/RendererFactory.java
deleted file mode 100644
index f333fce..0000000
--- a/tests/OneMedia/src/com/android/onemedia/playback/RendererFactory.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.android.onemedia.playback;
-
-import android.content.Context;
-import android.media.MediaRouter;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * TODO: Insert description here.
- */
-public class RendererFactory {
- private static final String TAG = "RendererFactory";
-
- public Renderer createRenderer(MediaRouter.RouteInfo route, Context context, Bundle params) {
- if (route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_LOCAL) {
- return new LocalRenderer(context, params);
- }
- Log.e(TAG, "Unable to create renderer for route of playback type "
- + route.getPlaybackType());
- return null;
- }
-}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java b/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
index 9b50dad..dd0d982 100644
--- a/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
+++ b/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.onemedia.playback;
import android.os.Bundle;
diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
new file mode 100644
index 0000000..6edcd7d
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java
@@ -0,0 +1,204 @@
+/*
+ * 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.onemedia.provider;
+
+import android.media.routeprovider.RouteConnection;
+import android.media.routeprovider.RouteInterfaceHandler;
+import android.media.routeprovider.RoutePlaybackControlsHandler;
+import android.media.routeprovider.RouteProviderService;
+import android.media.routeprovider.RouteRequest;
+import android.media.session.RouteInfo;
+import android.media.session.RoutePlaybackControls;
+import android.media.session.RouteInterface;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import com.android.onemedia.playback.LocalRenderer;
+import com.android.onemedia.playback.Renderer;
+import com.android.onemedia.playback.RequestUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Test of MediaRouteProvider. Show a dummy provider with a simple interface for
+ * playing music.
+ */
+public class OneMediaRouteProvider extends RouteProviderService {
+ private static final String TAG = "OneMRP";
+ private static final boolean DEBUG = true;
+
+ private Renderer mRenderer;
+ private RenderListener mRenderListener;
+ private PlaybackState mPlaybackState;
+ private RouteConnection mConnection;
+ private RoutePlaybackControlsHandler mControls;
+ private String mRouteId;
+ private Handler mHandler;
+
+ @Override
+ public void onCreate() {
+ mHandler = new Handler();
+ mRouteId = UUID.randomUUID().toString();
+ mRenderer = new LocalRenderer(this, null);
+ mRenderListener = new RenderListener();
+ mPlaybackState = new PlaybackState();
+ mPlaybackState.setActions(PlaybackState.ACTION_PAUSE
+ | PlaybackState.ACTION_PLAY);
+
+ mRenderer.registerListener(mRenderListener);
+
+ if (DEBUG) {
+ Log.d(TAG, "onCreate, routeId is " + mRouteId);
+ }
+ }
+
+ @Override
+ public List<RouteInfo> getMatchingRoutes(List<RouteRequest> requests) {
+ RouteInfo.Builder bob = new RouteInfo.Builder();
+ bob.setName("OneMedia").setId(mRouteId);
+ // TODO add a helper library for generating route info with the correct
+ // options
+ Log.d(TAG, "Requests:");
+ for (RouteRequest request : requests) {
+ List<String> ifaces = request.getConnectionOptions().getInterfaceNames();
+ Log.d(TAG, " request ifaces:" + ifaces.toString());
+ if (ifaces != null && ifaces.size() == 1
+ && RoutePlaybackControls.NAME.equals(ifaces.get(0))) {
+ bob.addRouteOptions(request.getConnectionOptions());
+ }
+ }
+ ArrayList<RouteInfo> result = new ArrayList<RouteInfo>();
+ if (bob.getOptionsSize() > 0) {
+ RouteInfo info = bob.build();
+ result.add(info);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "getRoutes returning " + result.toString());
+ }
+ return result;
+ }
+
+ @Override
+ public RouteConnection connect(RouteInfo route, RouteRequest request) {
+ if (mConnection != null) {
+ disconnect(mConnection);
+ }
+ RouteConnection connection = new RouteConnection(this, route);
+ mControls = RoutePlaybackControlsHandler.addTo(connection);
+ mControls.addListener(new PlayHandler(mRouteId), mHandler);
+ if (DEBUG) {
+ Log.d(TAG, "Connected to route");
+ }
+ return connection;
+ }
+
+ private class PlayHandler extends RoutePlaybackControlsHandler.Listener {
+ private final String mRouteId;
+
+ public PlayHandler(String routeId) {
+ mRouteId = routeId;
+ }
+
+ @Override
+ public void playNow(String content, ResultReceiver cb) {
+ if (DEBUG) {
+ Log.d(TAG, "Attempting to play " + content);
+ }
+ // look up the route and send a play command to it
+ Bundle bundle = new Bundle();
+ bundle.putString(RequestUtils.EXTRA_KEY_SOURCE, content);
+ mRenderer.setContent(bundle);
+ RouteInterfaceHandler.sendResult(cb, RouteInterface.RESULT_SUCCESS, null);
+ }
+
+ @Override
+ public boolean resume() {
+ mRenderer.onPlay();
+ return true;
+ }
+
+ @Override
+ public boolean pause() {
+ mRenderer.onPause();
+ return true;
+ }
+ }
+
+ private class RenderListener implements Renderer.Listener {
+
+ @Override
+ public void onError(int type, int extra, Bundle extras, Throwable error) {
+ Log.d(TAG, "Sending onError with type " + type + " and extra " + extra);
+ if (mControls != null) {
+ mControls.sendPlaybackChangeEvent(PlaybackState.PLAYSTATE_ERROR);
+ }
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ if (newState != Renderer.STATE_ERROR) {
+ mPlaybackState.setErrorMessage(null);
+ }
+ switch (newState) {
+ case Renderer.STATE_ENDED:
+ case Renderer.STATE_STOPPED:
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED);
+ break;
+ case Renderer.STATE_INIT:
+ case Renderer.STATE_PREPARING:
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING);
+ break;
+ case Renderer.STATE_ERROR:
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+ break;
+ case Renderer.STATE_PAUSED:
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
+ break;
+ case Renderer.STATE_PLAYING:
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING);
+ break;
+ default:
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR);
+ mPlaybackState.setErrorMessage("unkown state");
+ break;
+ }
+ mPlaybackState.setPosition(mRenderer.getSeekPosition());
+
+ mControls.sendPlaybackChangeEvent(mPlaybackState.getState());
+ }
+
+ @Override
+ public void onBufferingUpdate(int percent) {
+ }
+
+ @Override
+ public void onFocusLost() {
+ Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED);
+ mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED);
+ mPlaybackState.setPosition(mRenderer.getSeekPosition());
+ }
+
+ @Override
+ public void onNextStarted() {
+ }
+ }
+}
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
index bcf3ae6..0be6755 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,26 +16,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
<viewport
- android:viewportWidth="7.30625"
- android:viewportHeight="12.25"/>
+ android:viewportHeight="12.25"
+ android:viewportWidth="7.30625" />
<group>
<path
- android:name="one"
- android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
+ android:name="one"
+ android:fill="#ffff00"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
- l -5.046875,0.0 0.0,-1.0Z"
- android:fill="#ffff00"
- />
-
-
+ l -5.046875,0.0 0.0,-1.0Z" />
<path
- android:name="two"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+ android:name="two"
+ android:fill="#ffff00"
+ android:fillOpacity="0"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -42,23 +42,20 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z"
- android:fill="#ffff00"
- android:fillOpacity="0"
- />
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
</group>
<group>
<path
- android:name="one"
- android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
+ android:name="one"
+ android:fill="#ffff00"
+ android:fillOpacity="0"
+ android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-l -5.046875,0.0 0.0,-1.0Z"
- android:fill="#ffff00"
- android:fillOpacity="0"
- />
+l -5.046875,0.0 0.0,-1.0Z" />
<path
- android:name="two"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+ android:name="two"
+ android:fill="#ffff00"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -66,14 +63,13 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z"
- android:fill="#ffff00"
- />
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
</group>
<group>
<path
- android:name="two"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+ android:name="two"
+ android:fill="#ffff00"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -81,12 +77,12 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z"
- android:fill="#ffff00"
- />
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
<path
- android:name="three"
- android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
+ android:name="three"
+ android:fill="#ffff00"
+ android:fillOpacity="0"
+ android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
@@ -98,15 +94,14 @@
q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
- q -0.40625,0.5 -1.171875,0.6875Z"
- android:fill="#ffff00"
- android:fillOpacity="0"
- />
+ q -0.40625,0.5 -1.171875,0.6875Z" />
</group>
<group>
<path
- android:name="two"
- android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
+ android:name="two"
+ android:fill="#ffff00"
+ android:fillOpacity="0"
+ android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
@@ -114,13 +109,11 @@
q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
- q -0.78125024,0.8125 -2.2187502,2.265625Z"
- android:fill="#ffff00"
- android:fillOpacity="0"
- />
+ q -0.78125024,0.8125 -2.2187502,2.265625Z" />
<path
- android:name="three"
- android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
+ android:name="three"
+ android:fill="#ffff00"
+ android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
@@ -132,16 +125,14 @@
q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
- q -0.40625,0.5 -1.171875,0.6875Z"
- android:fill="#ffff00"
- />
+ q -0.40625,0.5 -1.171875,0.6875Z" />
</group>
+ <animation
+ android:durations="2000,0,2000"
+ android:sequence="one,one,three,three" />
+ <animation
+ android:durations="2000,0,2000"
+ android:sequence="two,two,two,two" />
- <animation
- android:sequence="one,one,three,three"
- android:durations="2000,0,2000"/>
- <animation
- android:sequence="two,two,two,two"
- android:durations="2000,0,2000"/>
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
index 09934de..b3c91a88 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,27 +16,29 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
-
- <viewport android:viewportWidth="200"
- android:viewportHeight="200"/>
+ <viewport
+ android:viewportHeight="200"
+ android:viewportWidth="200" />
<group>
<path
- android:name="arrow"
- android:pathData="M 20,20 l 60,0 0,140 -60,0 z M 120,20 l 60,0 0,140 -60,0 z"
- android:fill="#ffffffff"/>
+ android:name="arrow"
+ android:fill="#ffffffff"
+ android:pathData="M 20,20 l 60,0 0,140 -60,0 z M 120,20 l 60,0 0,140 -60,0 z" />
</group>
<group>
<path
- android:name="house"
- android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
- android:fill="#ffffffff"
- android:rotation="90"
- android:pivotX="100"
- android:pivotY="100"/>
+ android:name="house"
+ android:fill="#ffffffff"
+ android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="90" />
</group>
- <animation android:sequence="arrow,house"/>
-</vector>
+
+ <animation android:sequence="arrow,house" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
index f17f67a..7aca169 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
@@ -27,88 +27,87 @@
<group>
<path
android:name="bar3"
- android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
<path
android:name="bar2"
- android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z"
- android:fill="#FF555555" />
+ android:fill="#FF555555"
+ android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
<path
android:name="bar1"
- android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z"
- android:fill="#FF555555" />
+ android:fill="#FF555555"
+ android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
<path
android:name="bar0"
- android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z"
- android:fill="#FF555555" />
+ android:fill="#FF555555"
+ android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
</group>
- <group>
+ <group>
<path
android:name="bar3"
- android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
<path
android:name="bar2"
- android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
<path
android:name="bar1"
- android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z"
- android:fill="#FF555555" />
+ android:fill="#FF555555"
+ android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
<path
android:name="bar0"
- android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z"
- android:fill="#FF555555" />
+ android:fill="#FF555555"
+ android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
</group>
-
- <group>
+ <group>
<path
android:name="bar3"
- android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
<path
android:name="bar2"
- android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
<path
android:name="bar1"
- android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
<path
android:name="bar0"
- android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z"
- android:fill="#FF555555" />
+ android:fill="#FF555555"
+ android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
</group>
-
- <group>
+ <group>
<path
android:name="bar3"
- android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
<path
android:name="bar2"
- android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
<path
android:name="bar1"
- android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M14.001,34.645 L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
<path
android:name="bar0"
- android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z"
- android:fill="#FFFFFFFF" />
+ android:fill="#FFFFFFFF"
+ android:pathData="M0,20.502l6.999,7.071 c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
</group>
- <animation
- android:sequence="bar0,bar0,bar0,bar0"
- android:durations="500,500,500"/>
- <animation
- android:sequence="bar1,bar1,bar1,bar1"
- android:durations="500,500,500"/>
- <animation
- android:sequence="bar2,bar2,bar2,bar2"
- android:durations="500,500,500"/>
- <animation
- android:sequence="bar3,bar3,bar3,bar3"
- android:durations="500,500,500"/>
-</vector>
+ <animation
+ android:durations="500,500,500"
+ android:sequence="bar0,bar0,bar0,bar0" />
+ <animation
+ android:durations="500,500,500"
+ android:sequence="bar1,bar1,bar1,bar1" />
+ <animation
+ android:durations="500,500,500"
+ android:sequence="bar2,bar2,bar2,bar2" />
+ <animation
+ android:durations="500,500,500"
+ android:sequence="bar3,bar3,bar3,bar3" />
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
index 8787b34..a4403c5 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -26,29 +26,28 @@
<group>
<path
android:name="battery"
- android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
android:fill="#3388ff"
+ android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
+ android:rotation="0"
android:stroke="#ff8833"
- android:strokeWidth="1"
- android:rotation="0"/>
- <path
+ android:strokeWidth="1" />
+ <path
android:name="spark"
- android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z"
- android:fill="#FFFF0000" />
-
+ android:fill="#FFFF0000"
+ android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
</group>
<group>
<path
android:name="battery"
- android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
android:fill="#ff8833"
+ android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
+ android:rotation="0"
android:stroke="#3388ff"
- android:strokeWidth="1"
- android:rotation="0" />
+ android:strokeWidth="1" />
<path
android:name="spark"
- android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z"
- android:fill="#FFFF0000" />
+ android:fill="#FFFF0000"
+ android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
</group>
<animation
@@ -58,5 +57,4 @@
android:durations="2000"
android:sequence="battery,battery" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 89748d5..207879d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,76 +16,72 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
-
- <viewport android:viewportWidth="600"
- android:viewportHeight="600"/>
+ <viewport
+ android:viewportHeight="600"
+ android:viewportWidth="600" />
<group>
<path
- android:name="pie1"
- android:pathData="M300,70 a230,230 0 1,0 1,0 z"
- android:stroke="#FF00FF00"
- android:strokeWidth="70"
- android:trimPathStart="0"
- android:trimPathEnd=".75"
- android:trimPathOffset="0"/>
-
+ android:name="pie1"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="70"
+ android:trimPathEnd=".75"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
<path
- android:name="v"
- android:pathData="M300,70 l 0,-70 70,70 -70,70z"
- android:fill="#FF00FF00"
- android:pivotX="300"
- android:pivotY="300"
- android:rotation="0"
- />
+ android:name="v"
+ android:fill="#FF00FF00"
+ android:pathData="M300,70 l 0,-70 70,70 -70,70z"
+ android:pivotX="300"
+ android:pivotY="300"
+ android:rotation="0" />
</group>
-
<group>
<path
- android:name="v"
- android:pathData="M300,70 l 0,-70 70,70 -70,70z"
- android:pivotX="300"
- android:pivotY="300"
- android:rotation="360"/>
+ android:name="v"
+ android:pathData="M300,70 l 0,-70 70,70 -70,70z"
+ android:pivotX="300"
+ android:pivotY="300"
+ android:rotation="360" />
<path
- android:name="pie2"
- android:pathData="M300,70 a230,230 0 1,0 1,0 z"
- android:stroke="#FF00FF00"
- android:strokeWidth="70"
- android:rotation="360"
- android:pivotX="300"
- android:pivotY="300"
- android:trimPathStart="0"
- android:trimPathEnd=".5"
- android:trimPathOffset="0"
- android:strokeLineCap="round"
- />
+ android:name="pie2"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
+ android:pivotX="300"
+ android:pivotY="300"
+ android:rotation="360"
+ android:stroke="#FF00FF00"
+ android:strokeLineCap="round"
+ android:strokeWidth="70"
+ android:trimPathEnd=".5"
+ android:trimPathOffset="0"
+ android:trimPathStart="0" />
</group>
- <animation android:sequence="pie1,pie2"
- android:durations="2000"
- android:startOffset="500"
- android:repeatCount="-1"
- android:repeatStyle="forward"
- android:animate="easeInOut"
- />
- <animation android:sequence="v,v"
- android:durations="2000"
- android:startOffset="500"
- android:repeatCount="-1"
- android:repeatStyle="forward"
- android:animate="easeInOut"
- />
- <animation android:sequence="pie1,pie2"
- android:durations="2800"
- android:startOffset="500"
- android:limitTo="trimPathEnd"
- android:repeatCount="-1"
- android:repeatStyle="reverse"
- android:animate="easeInOut"
- />
+ <animation
+ android:animate="easeInOut"
+ android:durations="2000"
+ android:repeatCount="-1"
+ android:repeatStyle="forward"
+ android:sequence="pie1,pie2"
+ android:startOffset="500" />
+ <animation
+ android:animate="easeInOut"
+ android:durations="2000"
+ android:repeatCount="-1"
+ android:repeatStyle="forward"
+ android:sequence="v,v"
+ android:startOffset="500" />
+ <animation
+ android:animate="easeInOut"
+ android:durations="2800"
+ android:limitTo="trimPathEnd"
+ android:repeatCount="-1"
+ android:repeatStyle="reverse"
+ android:sequence="pie1,pie2"
+ android:startOffset="500" />
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
index 43dda52..4a2ed90 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,68 +16,64 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
-
- <viewport android:viewportWidth="600"
- android:viewportHeight="400"/>
+ <viewport
+ android:viewportHeight="400"
+ android:viewportWidth="600" />
<group>
<path
- android:name="pie1"
- android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
- android:fill="#ffffffff"
- android:stroke="#FF00FF00"
- android:strokeWidth="1"/>
-
+ android:name="pie1"
+ android:fill="#ffffffff"
+ android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="1" />
<path
- android:name="half"
- android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
- android:fill="#FFFF0000"
- android:stroke="#FF0000FF"
- android:strokeWidth="5"
- android:rotation="0"
- android:pivotX="300"
- android:pivotY="200"/>
+ android:name="half"
+ android:fill="#FFFF0000"
+ android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+ android:pivotX="300"
+ android:pivotY="200"
+ android:rotation="0"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="5" />
</group>
-
<group>
<path
- android:name="pie2"
- android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
- android:fill="#ffff0000"
- android:stroke="#FF00FF00"
- android:strokeWidth="10"
- android:rotation="360"
- android:pivotX="300"
- android:pivotY="200"/>
-
+ android:name="pie2"
+ android:fill="#ffff0000"
+ android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
+ android:pivotX="300"
+ android:pivotY="200"
+ android:rotation="360"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
<path
- android:name="half"
- android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
- android:fill="#FFFFFF00"
- android:stroke="#FF0000FF"
- android:strokeWidth="5"
- android:rotation="-360"
- android:pivotX="300"
- android:pivotY="200"/>
+ android:name="half"
+ android:fill="#FFFFFF00"
+ android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
+ android:pivotX="300"
+ android:pivotY="200"
+ android:rotation="-360"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="5" />
</group>
- <animation android:sequence="pie1,pie2"
- android:durations="1000"
- android:startOffset="500"
- android:repeatCount="2"
- android:repeatStyle="forward"
- android:animate="easeInOut"
- />
- <animation android:sequence="half,half"
- android:durations="1000"
- android:startOffset="500"
- android:repeatCount="5"
- android:repeatStyle="forward"
- android:animate="easeInOut"
- />
+ <animation
+ android:animate="easeInOut"
+ android:durations="1000"
+ android:repeatCount="2"
+ android:repeatStyle="forward"
+ android:sequence="pie1,pie2"
+ android:startOffset="500" />
+ <animation
+ android:animate="easeInOut"
+ android:durations="1000"
+ android:repeatCount="5"
+ android:repeatStyle="forward"
+ android:sequence="half,half"
+ android:startOffset="500" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
index 0f1f149..6ebd56b 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,40 +16,39 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="800"
- android:viewportHeight="500"/>
+ <viewport
+ android:viewportHeight="500"
+ android:viewportWidth="800" />
<group>
<path
- android:name="pie1"
- android:pathData="M200,450 l 50,-25
+ android:name="pie1"
+ android:pathData="M200,450 l 50,-25
a25,25 -30 0,1 100,-50 l 50,-25
a25,50 -30 0,1 100,-50 l 50,-25
a25,75 -30 0,1 100,-50 l 50,-25
a25,100 -30 0,1 100,-50 l 50,-25"
- android:stroke="#FF00FF00"
- android:strokeWidth="10"/>
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
</group>
-
<group>
<path
- android:name="pie2"
- android:pathData="M200,350 l 50,-25
+ android:name="pie2"
+ android:pathData="M200,350 l 50,-25
a25,12 -30 0,1 100,-50 l 50,-25
a25,25 -30 0,1 100,-50 l 50,-25
a25,37 -30 0,1 100,-50 l 50,-25
a25,50 -30 0,1 100,-50 l 50,-25"
- android:stroke="#FF00FF00"
- android:strokeWidth="10"
- android:rotation="20"
- android:pivotX="90"
- android:pivotY="100"/>
-
+ android:pivotX="90"
+ android:pivotY="100"
+ android:rotation="20"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
</group>
- <animation android:sequence="pie1,pie2"/>
+ <animation android:sequence="pie1,pie2" />
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
index 6bc946f..3c92d25 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,34 +16,33 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="500"
- android:viewportHeight="400"/>
+ <viewport
+ android:viewportHeight="400"
+ android:viewportWidth="500" />
<group>
<path
- android:name="arrow"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:fill="#ffffffff"
- android:stroke="#FFFF0000"
- android:strokeWidth="1"/>
+ android:name="arrow"
+ android:fill="#ffffffff"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="1" />
</group>
-
<group>
<path
- android:name="house"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:fill="#ff440000"
- android:stroke="#FFFF0000"
- android:strokeWidth="10"
- android:rotation="180"
- android:pivotX="250"
- android:pivotY="200"/>
+ android:name="house"
+ android:fill="#ff440000"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:pivotX="250"
+ android:pivotY="200"
+ android:rotation="180"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house"/>
+ <animation android:sequence="arrow,house" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
index c9c8e8a..7e757a5 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,32 +16,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="200"
- android:viewportHeight="200"/>
+ <viewport
+ android:viewportHeight="200"
+ android:viewportWidth="200" />
<group>
<path
- android:name="arrow"
- android:pathData="M 100,10 v 180 M 10,100 h 180"
- android:stroke="#FF00FF00"
- android:strokeWidth="1"/>
+ android:name="arrow"
+ android:pathData="M 100,10 v 180 M 10,100 h 180"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="1" />
</group>
-
<group>
<path
- android:name="house"
- android:pathData="M 100,10 v 90 M 10,100 h 90"
- android:stroke="#FF00FF00"
- android:strokeWidth="10"
- android:rotation="360"
- android:pivotX="100"
- android:pivotY="100"/>
+ android:name="house"
+ android:pathData="M 100,10 v 90 M 10,100 h 90"
+ android:pivotX="100"
+ android:pivotY="100"
+ android:rotation="360"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house"/>
+ <animation android:sequence="arrow,house" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
index 83dfbd2..69212f5 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,31 +16,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="500"
- android:viewportHeight="400"/>
+ <viewport
+ android:viewportHeight="400"
+ android:viewportWidth="500" />
<group>
<path
- android:name="arrow"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:stroke="#FFFFFF00"
- android:strokeWidth="10"/>
+ android:name="arrow"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:stroke="#FFFFFF00"
+ android:strokeWidth="10" />
</group>
-
<group>
<path
- android:name="house"
- android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
- android:strokeWidth="10"
- android:rotation="360"
- android:pivotX="250"
- android:pivotY="200"/>
+ android:name="house"
+ android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
+ android:pivotX="250"
+ android:pivotY="200"
+ android:rotation="360"
+ android:strokeWidth="10" />
</group>
- <animation android:sequence="arrow,house"/>
+ <animation android:sequence="arrow,house" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
index 013254f..2dca48d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,31 +16,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="1000"
- android:viewportHeight="800"/>
+ <viewport
+ android:viewportHeight="800"
+ android:viewportWidth="1000" />
<group>
<path
- android:name="arrow"
- android:pathData="M10,300 Q400,50 600,300 T1000,300"
- android:stroke="#FF00FFFF"
- android:strokeWidth="40"/>
+ android:name="arrow"
+ android:pathData="M10,300 Q400,50 600,300 T1000,300"
+ android:stroke="#FF00FFFF"
+ android:strokeWidth="40" />
</group>
-
<group>
<path
- android:name="house"
- android:pathData="M10,300 Q400,550 600,300 T1000,300"
- android:stroke="#FFFF0000"
- android:strokeWidth="60"
- android:pivotX="90"
- android:pivotY="100"/>
+ android:name="house"
+ android:pathData="M10,300 Q400,550 600,300 T1000,300"
+ android:pivotX="90"
+ android:pivotY="100"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="60" />
</group>
- <animation android:sequence="arrow,house"/>
+ <animation android:sequence="arrow,house" />
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
index aba7e5f..b8af7e2 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
@@ -15,23 +16,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
<size
- android:width="64dp"
- android:height="64dp"/>
+ android:height="64dp"
+ android:width="64dp" />
- <viewport android:viewportWidth="480"
- android:viewportHeight="480"/>
+ <viewport
+ android:viewportHeight="480"
+ android:viewportWidth="480" />
<group>
<path
- android:name="edit"
- android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
+ android:name="edit"
+ android:fill="#FF00FFFF"
+ android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333
c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40
c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522
c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z"
- android:stroke="#FF000000"
- android:fill="#FF00FFFF"
- android:strokeWidth="10"/>
+ android:stroke="#FF000000"
+ android:strokeWidth="10" />
</group>
-
-</vector>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
index 8897181..22ce795 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,17 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z"
- android:fill="#FF000000"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
index 2c7ebbd..042173c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,17 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z"
- android:fill="#FF000000"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
index e4cf78c..6b6f43d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,17 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"
- android:fill="#FF000000"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
index cec12ba..ba8ebca 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,21 +14,22 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z"
- android:fillOpacity="0.9"
- />
-<path
- android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z"
- android:fillOpacity="0.9"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fillOpacity="0.9"
+ android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" />
+ <path
+ android:fillOpacity="0.9"
+ android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
index 5fe1fb6..896a938 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,17 +14,19 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="64dp"
-android:height="64dp"/>
- <viewport android:viewportWidth="24"
- android:viewportHeight="24"/>
+ <size
+ android:height="64dp"
+ android:width="64dp" />
-<group>
-<path
- android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z"
- android:fill="#FF000000"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="24"
+ android:viewportWidth="24" />
+
+ <group>
+ <path
+ android:fill="#FF000000"
+ android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
index 6beb9d8..a9091ab 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,19 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="128dp"
-android:height="128dp"/>
- <viewport android:viewportWidth="512"
- android:viewportHeight="512"/>
+ <size
+ android:height="128dp"
+ android:width="128dp" />
-<group>
-<path
- android:name="002b"
- android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
- android:stroke="#FF0000FF"
- android:strokeWidth="4"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="512"
+ android:viewportWidth="512" />
+
+ <group>
+ <path
+ android:name="002b"
+ android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="4" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_test02.xml b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
index 2c1a28e..ab58c06 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_test02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2014 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.
You may obtain a copy of the License at"+
@@ -13,19 +14,21 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" >
-<size
-android:width="128dp"
-android:height="128dp"/>
- <viewport android:viewportWidth="512"
- android:viewportHeight="512"/>
+ <size
+ android:height="128dp"
+ android:width="128dp" />
-<group>
-<path
- android:name="002b"
- android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
- android:stroke="#FF0000FF"
- android:strokeWidth="4"
- />
-</group>
-</vector>
+ <viewport
+ android:viewportHeight="512"
+ android:viewportWidth="512" />
+
+ <group>
+ <path
+ android:name="002b"
+ android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="4" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VoiceInteraction/Android.mk b/tests/VoiceInteraction/Android.mk
new file mode 100644
index 0000000..8decca7
--- /dev/null
+++ b/tests/VoiceInteraction/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := VoiceInteraction
+
+include $(BUILD_PACKAGE)
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
new file mode 100644
index 0000000..9c5acf9
--- /dev/null
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.voiceinteraction">
+
+ <application>
+ <activity android:name="VoiceInteractionMain" android:label="Voice Interaction">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <service android:name="MainInteractionService"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":interactor">
+ <intent-filter>
+ <action android:name="android.service.voice.VoiceInteractionService" />
+ </intent-filter>
+ </service>
+ <activity android:name="TestInteractionActivity" android:label="Voice Interaction Target">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/VoiceInteraction/res/layout/main.xml b/tests/VoiceInteraction/res/layout/main.xml
new file mode 100644
index 0000000..3d7a418
--- /dev/null
+++ b/tests/VoiceInteraction/res/layout/main.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <Button android:id="@+id/start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/start"
+ />
+
+</LinearLayout>
+
+
diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml
new file mode 100644
index 0000000..2abf65194
--- /dev/null
+++ b/tests/VoiceInteraction/res/layout/test_interaction.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:text="We are interacting!"
+ />
+
+ <TextView android:id="@+id/log"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:layout_marginTop="10dp"
+ android:textSize="12sp"
+ android:textColor="#ffffffff"
+ />
+
+</LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
new file mode 100644
index 0000000..12edb31
--- /dev/null
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<resources>
+
+ <string name="start">Start!</string>
+
+</resources>
+
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
new file mode 100644
index 0000000..35702f1
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.content.Intent;
+import android.service.voice.VoiceInteractionService;
+import android.util.Log;
+
+public class MainInteractionService extends VoiceInteractionService {
+ static final String TAG = "MainInteractionService";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i(TAG, "Creating " + this);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ startVoiceActivity(new Intent(this, TestInteractionActivity.class),
+ new MainInteractionSession(this));
+ 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
new file mode 100644
index 0000000..adc0df4
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -0,0 +1,53 @@
+/*
+ * 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.content.Context;
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.util.Log;
+
+public class MainInteractionSession extends VoiceInteractionSession {
+ static final String TAG = "MainInteractionSession";
+
+ MainInteractionSession(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean[] onGetSupportedCommands(Caller caller, String[] commands) {
+ return new boolean[commands.length];
+ }
+
+ @Override
+ public void onConfirm(Caller caller, Request request, String prompt, Bundle extras) {
+ Log.i(TAG, "onConform: prompt=" + prompt + " extras=" + extras);
+ request.sendConfirmResult(true, null);
+ }
+
+ @Override
+ public void onCommand(Caller caller, Request request, String command, Bundle extras) {
+ Log.i(TAG, "onCommand: command=" + command + " extras=" + extras);
+ request.sendCommandResult(null);
+ }
+
+ @Override
+ public void onCancel(Request request) {
+ Log.i(TAG, "onCancel");
+ request.sendCancelResult();
+ }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
new file mode 100644
index 0000000..016a80e
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -0,0 +1,66 @@
+/*
+ * 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.app.Activity;
+import android.app.VoiceInteractor;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestInteractionActivity extends Activity {
+ static final String TAG = "TestInteractionActivity";
+
+ VoiceInteractor mInteractor;
+
+ @Override
+ 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;
+ }
+
+ mInteractor = getVoiceInteractor();
+ mInteractor.startConfirmation(new VoiceInteractor.Callback() {
+ @Override
+ public void onConfirmationResult(VoiceInteractor.Request request, boolean confirmed,
+ Bundle result) {
+ Log.i(TAG, "Confirmation result: confirmed=" + confirmed + " result=" + result);
+ finish();
+ }
+
+ @Override
+ public void onCancel(VoiceInteractor.Request request) {
+ Log.i(TAG, "Canceled!");
+ finish();
+ }
+ }, "This is a confirmation", null);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java
new file mode 100644
index 0000000..5d212a4
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java
@@ -0,0 +1,49 @@
+/*
+ * 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.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+public class VoiceInteractionMain extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.main);
+ findViewById(R.id.start).setOnClickListener(mStartListener);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ View.OnClickListener mStartListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ startService(new Intent(VoiceInteractionMain.this, MainInteractionService.class));
+ }
+ };
+}
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index d2eccbe..ebe1bed 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -42,6 +42,15 @@
} Command;
/*
+ * Pseudolocalization methods
+ */
+typedef enum PseudolocalizationMethod {
+ NO_PSEUDOLOCALIZATION = 0,
+ PSEUDO_ACCENTED,
+ PSEUDO_BIDI,
+} PseudolocalizationMethod;
+
+/*
* Bundle of goodies, including everything specified on the command line.
*/
class Bundle {
@@ -50,7 +59,7 @@
: mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false),
mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false),
mUpdate(false), mExtending(false),
- mRequireLocalization(false), mPseudolocalize(false),
+ mRequireLocalization(false), mPseudolocalize(NO_PSEUDOLOCALIZATION),
mWantUTF16(false), mValues(false), mIncludeMetaData(false),
mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL),
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
@@ -95,8 +104,8 @@
void setExtending(bool val) { mExtending = val; }
bool getRequireLocalization(void) const { return mRequireLocalization; }
void setRequireLocalization(bool val) { mRequireLocalization = val; }
- bool getPseudolocalize(void) const { return mPseudolocalize; }
- void setPseudolocalize(bool val) { mPseudolocalize = val; }
+ short getPseudolocalize(void) const { return mPseudolocalize; }
+ void setPseudolocalize(short val) { mPseudolocalize = val; }
void setWantUTF16(bool val) { mWantUTF16 = val; }
bool getValues(void) const { return mValues; }
void setValues(bool val) { mValues = val; }
@@ -259,7 +268,7 @@
bool mUpdate;
bool mExtending;
bool mRequireLocalization;
- bool mPseudolocalize;
+ short mPseudolocalize;
bool mWantUTF16;
bool mValues;
bool mIncludeMetaData;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 44b8340..0af1ce1 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -2048,14 +2048,17 @@
FILE* fp;
String8 dependencyFile;
- // -c zz_ZZ means do pseudolocalization
+ // -c en_XA or/and ar_XB means do pseudolocalization
ResourceFilter filter;
err = filter.parse(bundle->getConfigurations());
if (err != NO_ERROR) {
goto bail;
}
if (filter.containsPseudo()) {
- bundle->setPseudolocalize(true);
+ bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED);
+ }
+ if (filter.containsPseudoBidi()) {
+ bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI);
}
N = bundle->getFileSpecCount();
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 6d9d62e..d0581f6 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -2462,7 +2462,7 @@
status_t
writeProguardForXml(ProguardKeepSet* keep, const sp<AaptFile>& layoutFile,
- const char* startTag, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
+ const Vector<String8>& startTags, const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs)
{
status_t err;
ResXMLTree tree;
@@ -2476,15 +2476,18 @@
tree.restart();
- if (startTag != NULL) {
+ if (!startTags.isEmpty()) {
bool haveStart = false;
while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code != ResXMLTree::START_TAG) {
continue;
}
String8 tag(tree.getElementName(&len));
- if (tag == startTag) {
- haveStart = true;
+ const size_t numStartTags = startTags.size();
+ for (size_t i = 0; i < numStartTags; i++) {
+ if (tag == startTags[i]) {
+ haveStart = true;
+ }
}
break;
}
@@ -2571,15 +2574,17 @@
for (size_t k=0; k<K; k++) {
const sp<AaptDir>& d = dirs.itemAt(k);
const String8& dirName = d->getLeaf();
+ Vector<String8> startTags;
const char* startTag = NULL;
const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
tagAttrPairs = &kLayoutTagAttrPairs;
} else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
- startTag = "PreferenceScreen";
+ startTags.add(String8("PreferenceScreen"));
+ startTags.add(String8("preference-headers"));
tagAttrPairs = &kXmlTagAttrPairs;
} else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
- startTag = "menu";
+ startTags.add(String8("menu"));
tagAttrPairs = NULL;
} else {
continue;
@@ -2592,7 +2597,7 @@
const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& files = group->getFiles();
const size_t M = files.size();
for (size_t j=0; j<M; j++) {
- err = writeProguardForXml(keep, files.valueAt(j), startTag, tagAttrPairs);
+ err = writeProguardForXml(keep, files.valueAt(j), startTags, tagAttrPairs);
if (err < 0) {
return err;
}
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index e8a2be4..8ca852e 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -24,8 +24,10 @@
String8 part(p, q-p);
- if (part == "zz_ZZ") {
- mContainsPseudo = true;
+ if (part == "en_XA") {
+ mContainsPseudoAccented = true;
+ } else if (part == "ar_XB") {
+ mContainsPseudoBidi = true;
}
int axis;
AxisValue value;
diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h
index 0d127ba..c57770e 100644
--- a/tools/aapt/ResourceFilter.h
+++ b/tools/aapt/ResourceFilter.h
@@ -16,19 +16,22 @@
class ResourceFilter
{
public:
- ResourceFilter() : mData(), mContainsPseudo(false) {}
+ ResourceFilter() : mData(), mContainsPseudoAccented(false),
+ mContainsPseudoBidi(false) {}
status_t parse(const char* arg);
bool isEmpty() const;
bool match(int axis, const ResTable_config& config) const;
bool match(const ResTable_config& config) const;
const SortedVector<AxisValue>* configsForAxis(int axis) const;
- inline bool containsPseudo() const { return mContainsPseudo; }
+ inline bool containsPseudo() const { return mContainsPseudoAccented; }
+ inline bool containsPseudoBidi() const { return mContainsPseudoBidi; }
private:
bool match(int axis, const AxisValue& value) const;
KeyedVector<int,SortedVector<AxisValue> > mData;
- bool mContainsPseudo;
+ bool mContainsPseudoAccented;
+ bool mContainsPseudoBidi;
};
#endif
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 0fb2606..25bb26e 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -25,7 +25,7 @@
if (root == NULL) {
return UNKNOWN_ERROR;
}
-
+
return compileXmlFile(assets, root, target, table, options);
}
@@ -577,13 +577,13 @@
int32_t curFormat,
bool isFormatted,
const String16& product,
- bool pseudolocalize,
+ PseudolocalizationMethod pseudolocalize,
const bool overwrite,
ResourceTable* outTable)
{
status_t err;
const String16 item16("item");
-
+
String16 str;
Vector<StringPool::entry_style_span> spans;
err = parseStyledString(bundle, in->getPrintableSource().string(),
@@ -672,7 +672,7 @@
int32_t curFormat,
bool isFormatted,
const String16& product,
- bool pseudolocalize,
+ PseudolocalizationMethod pseudolocalize,
const bool overwrite,
KeyedVector<type_ident_pair_t, bool>* skippedResourceNames,
ResourceTable* outTable)
@@ -854,10 +854,16 @@
ResTable_config curParams(defParams);
ResTable_config pseudoParams(curParams);
- pseudoParams.language[0] = 'z';
- pseudoParams.language[1] = 'z';
- pseudoParams.country[0] = 'Z';
- pseudoParams.country[1] = 'Z';
+ pseudoParams.language[0] = 'e';
+ pseudoParams.language[1] = 'n';
+ pseudoParams.country[0] = 'X';
+ pseudoParams.country[1] = 'A';
+
+ ResTable_config pseudoBidiParams(curParams);
+ pseudoBidiParams.language[0] = 'a';
+ pseudoBidiParams.language[1] = 'r';
+ pseudoBidiParams.country[0] = 'X';
+ pseudoBidiParams.country[1] = 'B';
while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::START_TAG) {
@@ -1334,6 +1340,7 @@
name,
locale,
SourcePos(in->getPrintableSource(), block.getLineNumber()));
+ curIsPseudolocalizable = fileIsTranslatable;
}
if (formatted == false16) {
@@ -1389,6 +1396,7 @@
curTag = &plurals16;
curType = plurals16;
curIsBag = true;
+ curIsPseudolocalizable = fileIsTranslatable;
} else if (strcmp16(block.getElementName(&len), array16.string()) == 0) {
curTag = &array16;
curType = array16;
@@ -1410,26 +1418,24 @@
} else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) {
// Check whether these strings need valid formats.
// (simplified form of what string16 does above)
+ bool isTranslatable = false;
size_t n = block.getAttributeCount();
// Pseudolocalizable by default, unless this string array isn't
// translatable.
- curIsPseudolocalizable = true;
for (size_t i = 0; i < n; i++) {
size_t length;
const uint16_t* attr = block.getAttributeName(i, &length);
- if (strcmp16(attr, translatable16.string()) == 0) {
- const uint16_t* value = block.getAttributeStringValue(i, &length);
- if (strcmp16(value, false16.string()) == 0) {
- curIsPseudolocalizable = false;
- }
- }
-
if (strcmp16(attr, formatted16.string()) == 0) {
const uint16_t* value = block.getAttributeStringValue(i, &length);
if (strcmp16(value, false16.string()) == 0) {
curIsFormatted = false;
}
+ } else if (strcmp16(attr, translatable16.string()) == 0) {
+ const uint16_t* value = block.getAttributeStringValue(i, &length);
+ if (strcmp16(value, false16.string()) == 0) {
+ isTranslatable = false;
+ }
}
}
@@ -1438,6 +1444,7 @@
curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
curIsBag = true;
curIsBagReplaceOnOverwrite = true;
+ curIsPseudolocalizable = isTranslatable && fileIsTranslatable;
} else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) {
curTag = &integer_array16;
curType = array16;
@@ -1559,19 +1566,29 @@
err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType,
ident, parentIdent, itemIdent, curFormat, curIsFormatted,
- product, false, overwrite, outTable);
+ product, NO_PSEUDOLOCALIZATION, overwrite, outTable);
if (err == NO_ERROR) {
if (curIsPseudolocalizable && localeIsDefined(curParams)
- && bundle->getPseudolocalize()) {
+ && bundle->getPseudolocalize() > 0) {
// pseudolocalize here
-#if 1
- block.setPosition(parserPosition);
- err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
- curType, ident, parentIdent, itemIdent, curFormat,
- curIsFormatted, product, true, overwrite, outTable);
-#endif
+ if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) ==
+ PSEUDO_ACCENTED) {
+ block.setPosition(parserPosition);
+ err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage,
+ curType, ident, parentIdent, itemIdent, curFormat,
+ curIsFormatted, product, PSEUDO_ACCENTED,
+ overwrite, outTable);
+ }
+ if ((PSEUDO_BIDI & bundle->getPseudolocalize()) ==
+ PSEUDO_BIDI) {
+ block.setPosition(parserPosition);
+ err = parseAndAddBag(bundle, in, &block, pseudoBidiParams, myPackage,
+ curType, ident, parentIdent, itemIdent, curFormat,
+ curIsFormatted, product, PSEUDO_BIDI,
+ overwrite, outTable);
+ }
}
- }
+ }
if (err != NO_ERROR) {
hasErrors = localHasErrors = true;
}
@@ -1592,20 +1609,31 @@
err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident,
*curTag, curIsStyled, curFormat, curIsFormatted,
- product, false, overwrite, &skippedResourceNames, outTable);
+ product, NO_PSEUDOLOCALIZATION, overwrite, &skippedResourceNames, outTable);
if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR?
hasErrors = localHasErrors = true;
}
else if (err == NO_ERROR) {
if (curIsPseudolocalizable && localeIsDefined(curParams)
- && bundle->getPseudolocalize()) {
+ && bundle->getPseudolocalize() > 0) {
// pseudolocalize here
- block.setPosition(parserPosition);
- err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
- ident, *curTag, curIsStyled, curFormat,
- curIsFormatted, product,
- true, overwrite, &skippedResourceNames, outTable);
+ if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) ==
+ PSEUDO_ACCENTED) {
+ block.setPosition(parserPosition);
+ err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType,
+ ident, *curTag, curIsStyled, curFormat,
+ curIsFormatted, product,
+ PSEUDO_ACCENTED, overwrite, &skippedResourceNames, outTable);
+ }
+ if ((PSEUDO_BIDI & bundle->getPseudolocalize()) ==
+ PSEUDO_BIDI) {
+ block.setPosition(parserPosition);
+ err = parseAndAddEntry(bundle, in, &block, pseudoBidiParams,
+ myPackage, curType, ident, *curTag, curIsStyled, curFormat,
+ curIsFormatted, product,
+ PSEUDO_BIDI, overwrite, &skippedResourceNames, outTable);
+ }
if (err != NO_ERROR) {
hasErrors = localHasErrors = true;
}
@@ -2637,8 +2665,8 @@
continue;
}
- // don't bother with the pseudolocale "zz_ZZ"
- if (config != "zz_ZZ") {
+ // don't bother with the pseudolocale "en_XA" or "ar_XB"
+ if (config != "en_XA" && config != "ar_XB") {
if (configSrcMap.find(config) == configSrcMap.end()) {
// okay, no specific localization found. it's possible that we are
// requiring a specific regional localization [e.g. de_DE] but there is an
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index a663ad5..607d419 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -187,7 +187,7 @@
String16* outString,
Vector<StringPool::entry_style_span>* outSpans,
bool isFormatted,
- bool pseudolocalize)
+ PseudolocalizationMethod pseudolocalize)
{
Vector<StringPool::entry_style_span> spanStack;
String16 curString;
@@ -198,21 +198,30 @@
size_t len;
ResXMLTree::event_code_t code;
+ // Bracketing if pseudolocalization accented method specified.
+ if (pseudolocalize == PSEUDO_ACCENTED) {
+ curString.append(String16(String8("[")));
+ }
while ((code=inXml->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
-
if (code == ResXMLTree::TEXT) {
String16 text(inXml->getText(&len));
if (firstTime && text.size() > 0) {
firstTime = false;
if (text.string()[0] == '@') {
// If this is a resource reference, don't do the pseudoloc.
- pseudolocalize = false;
+ pseudolocalize = NO_PSEUDOLOCALIZATION;
}
}
- if (xliffDepth == 0 && pseudolocalize) {
- std::string orig(String8(text).string());
- std::string pseudo = pseudolocalize_string(orig);
- curString.append(String16(String8(pseudo.c_str())));
+ if (xliffDepth == 0 && pseudolocalize > 0) {
+ String16 pseudo;
+ if (pseudolocalize == PSEUDO_ACCENTED) {
+ pseudo = pseudolocalize_string(text);
+ } else if (pseudolocalize == PSEUDO_BIDI) {
+ pseudo = pseudobidi_string(text);
+ } else {
+ pseudo = text;
+ }
+ curString.append(pseudo);
} else {
if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) {
return UNKNOWN_ERROR;
@@ -352,6 +361,25 @@
}
}
+ // Bracketing if pseudolocalization accented method specified.
+ if (pseudolocalize == PSEUDO_ACCENTED) {
+ const char16_t* str = outString->string();
+ const char16_t* p = str;
+ const char16_t* e = p + outString->size();
+ int words_cnt = 0;
+ while (p < e) {
+ if (isspace(*p)) {
+ words_cnt++;
+ }
+ p++;
+ }
+ unsigned int length = words_cnt > 3 ? outString->size() :
+ outString->size() / 2;
+ curString.append(String16(String8(" ")));
+ curString.append(pseudo_generate_expansion(length));
+ curString.append(String16(String8("]")));
+ }
+
if (code == ResXMLTree::BAD_DOCUMENT) {
SourcePos(String8(fileName), inXml->getLineNumber()).error(
"Error parsing XML\n");
diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h
index 05624b7..ccbf9f4 100644
--- a/tools/aapt/XMLNode.h
+++ b/tools/aapt/XMLNode.h
@@ -26,7 +26,7 @@
String16* outString,
Vector<StringPool::entry_style_span>* outSpans,
bool isFormatted,
- bool isPseudolocalizable);
+ PseudolocalizationMethod isPseudolocalizable);
void printXMLBlock(ResXMLTree* block);
diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp
index 9e50c5a..60aa2b2 100644
--- a/tools/aapt/pseudolocalize.cpp
+++ b/tools/aapt/pseudolocalize.cpp
@@ -2,89 +2,155 @@
using namespace std;
+// String basis to generate expansion
+static const String16 k_expansion_string = String16("one two three "
+ "four five six seven eight nine ten eleven twelve thirteen "
+ "fourteen fiveteen sixteen seventeen nineteen twenty");
+
+// Special unicode characters to override directionality of the words
+static const String16 k_rlm = String16("\xe2\x80\x8f");
+static const String16 k_rlo = String16("\xE2\x80\xae");
+static const String16 k_pdf = String16("\xE2\x80\xac");
+
+// Placeholder marks
+static const String16 k_placeholder_open = String16("\xc2\xbb");
+static const String16 k_placeholder_close = String16("\xc2\xab");
+
static const char*
-pseudolocalize_char(char c)
+pseudolocalize_char(const char16_t c)
{
switch (c) {
- case 'a': return "\xc4\x83";
- case 'b': return "\xcf\x84";
- case 'c': return "\xc4\x8b";
- case 'd': return "\xc4\x8f";
- case 'e': return "\xc4\x99";
+ case 'a': return "\xc3\xa5";
+ case 'b': return "\xc9\x93";
+ case 'c': return "\xc3\xa7";
+ case 'd': return "\xc3\xb0";
+ case 'e': return "\xc3\xa9";
case 'f': return "\xc6\x92";
case 'g': return "\xc4\x9d";
- case 'h': return "\xd1\x9b";
- case 'i': return "\xcf\x8a";
+ case 'h': return "\xc4\xa5";
+ case 'i': return "\xc3\xae";
case 'j': return "\xc4\xb5";
- case 'k': return "\xc4\xb8";
- case 'l': return "\xc4\xba";
+ case 'k': return "\xc4\xb7";
+ case 'l': return "\xc4\xbc";
case 'm': return "\xe1\xb8\xbf";
- case 'n': return "\xd0\xb8";
- case 'o': return "\xcf\x8c";
- case 'p': return "\xcf\x81";
+ case 'n': return "\xc3\xb1";
+ case 'o': return "\xc3\xb6";
+ case 'p': return "\xc3\xbe";
case 'q': return "\x51";
- case 'r': return "\xd2\x91";
+ case 'r': return "\xc5\x95";
case 's': return "\xc5\xa1";
- case 't': return "\xd1\x82";
- case 'u': return "\xce\xb0";
+ case 't': return "\xc5\xa3";
+ case 'u': return "\xc3\xbb";
case 'v': return "\x56";
- case 'w': return "\xe1\xba\x85";
+ case 'w': return "\xc5\xb5";
case 'x': return "\xd1\x85";
- case 'y': return "\xe1\xbb\xb3";
- case 'z': return "\xc5\xba";
+ case 'y': return "\xc3\xbd";
+ case 'z': return "\xc5\xbe";
case 'A': return "\xc3\x85";
case 'B': return "\xce\xb2";
- case 'C': return "\xc4\x88";
- case 'D': return "\xc4\x90";
- case 'E': return "\xd0\x84";
- case 'F': return "\xce\x93";
- case 'G': return "\xc4\x9e";
- case 'H': return "\xc4\xa6";
- case 'I': return "\xd0\x87";
- case 'J': return "\xc4\xb5";
+ case 'C': return "\xc3\x87";
+ case 'D': return "\xc3\x90";
+ case 'E': return "\xc3\x89";
+ case 'G': return "\xc4\x9c";
+ case 'H': return "\xc4\xa4";
+ case 'I': return "\xc3\x8e";
+ case 'J': return "\xc4\xb4";
case 'K': return "\xc4\xb6";
- case 'L': return "\xc5\x81";
+ case 'L': return "\xc4\xbb";
case 'M': return "\xe1\xb8\xbe";
- case 'N': return "\xc5\x83";
- case 'O': return "\xce\x98";
- case 'P': return "\xcf\x81";
+ case 'N': return "\xc3\x91";
+ case 'O': return "\xc3\x96";
+ case 'P': return "\xc3\x9e";
case 'Q': return "\x71";
- case 'R': return "\xd0\xaf";
- case 'S': return "\xc8\x98";
- case 'T': return "\xc5\xa6";
- case 'U': return "\xc5\xa8";
+ case 'R': return "\xc5\x94";
+ case 'S': return "\xc5\xa0";
+ case 'T': return "\xc5\xa2";
+ case 'U': return "\xc3\x9b";
case 'V': return "\xce\xbd";
- case 'W': return "\xe1\xba\x84";
+ case 'W': return "\xc5\xb4";
case 'X': return "\xc3\x97";
- case 'Y': return "\xc2\xa5";
+ case 'Y': return "\xc3\x9d";
case 'Z': return "\xc5\xbd";
+ case '!': return "\xc2\xa1";
+ case '?': return "\xc2\xbf";
+ case '$': return "\xe2\x82\xac";
default: return NULL;
}
}
+static bool
+is_possible_normal_placeholder_end(const char16_t c) {
+ switch (c) {
+ case 's': return true;
+ case 'S': return true;
+ case 'c': return true;
+ case 'C': return true;
+ case 'd': return true;
+ case 'o': return true;
+ case 'x': return true;
+ case 'X': return true;
+ case 'f': return true;
+ case 'e': return true;
+ case 'E': return true;
+ case 'g': return true;
+ case 'G': return true;
+ case 'a': return true;
+ case 'A': return true;
+ case 'b': return true;
+ case 'B': return true;
+ case 'h': return true;
+ case 'H': return true;
+ case '%': return true;
+ case 'n': return true;
+ default: return false;
+ }
+}
+
+String16
+pseudo_generate_expansion(const unsigned int length) {
+ String16 result = k_expansion_string;
+ const char16_t* s = result.string();
+ if (result.size() < length) {
+ result += String16(" ");
+ result += pseudo_generate_expansion(length - result.size());
+ } else {
+ int ext = 0;
+ // Should contain only whole words, so looking for a space
+ for (unsigned int i = length + 1; i < result.size(); ++i) {
+ ++ext;
+ if (s[i] == ' ') {
+ break;
+ }
+ }
+ result.remove(length + ext, 0);
+ }
+ return result;
+}
+
/**
* Converts characters so they look like they've been localized.
*
* Note: This leaves escape sequences untouched so they can later be
* processed by ResTable::collectString in the normal way.
*/
-string
-pseudolocalize_string(const string& source)
+String16
+pseudolocalize_string(const String16& source)
{
- const char* s = source.c_str();
- string result;
- const size_t I = source.length();
+ const char16_t* s = source.string();
+ String16 result;
+ const size_t I = source.size();
for (size_t i=0; i<I; i++) {
- char c = s[i];
+ char16_t c = s[i];
if (c == '\\') {
+ // Escape syntax, no need to pseudolocalize
if (i<I-1) {
- result += '\\';
+ result += String16("\\");
i++;
c = s[i];
switch (c) {
case 'u':
// this one takes up 5 chars
- result += string(s+i, 5);
+ result += String16(s+i, 5);
i += 4;
break;
case 't':
@@ -96,24 +162,107 @@
case '\'':
case '\\':
default:
- result += c;
+ result.append(&c, 1);
break;
}
} else {
- result += c;
+ result.append(&c, 1);
+ }
+ } else if (c == '%') {
+ // Placeholder syntax, no need to pseudolocalize
+ result += k_placeholder_open;
+ bool end = false;
+ result.append(&c, 1);
+ while (!end && i < I) {
+ ++i;
+ c = s[i];
+ result.append(&c, 1);
+ if (is_possible_normal_placeholder_end(c)) {
+ end = true;
+ } else if (c == 't') {
+ ++i;
+ c = s[i];
+ result.append(&c, 1);
+ end = true;
+ }
+ }
+ result += k_placeholder_close;
+ } else if (c == '<' || c == '&') {
+ // html syntax, no need to pseudolocalize
+ bool tag_closed = false;
+ while (!tag_closed && i < I) {
+ if (c == '&') {
+ String16 escape_text;
+ escape_text.append(&c, 1);
+ bool end = false;
+ size_t htmlCodePos = i;
+ while (!end && htmlCodePos < I) {
+ ++htmlCodePos;
+ c = s[htmlCodePos];
+ escape_text.append(&c, 1);
+ // Valid html code
+ if (c == ';') {
+ end = true;
+ i = htmlCodePos;
+ }
+ // Wrong html code
+ else if (!((c == '#' ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9')))) {
+ end = true;
+ }
+ }
+ result += escape_text;
+ if (escape_text != String16("<")) {
+ tag_closed = true;
+ }
+ continue;
+ }
+ if (c == '>') {
+ tag_closed = true;
+ result.append(&c, 1);
+ continue;
+ }
+ result.append(&c, 1);
+ i++;
+ c = s[i];
}
} else {
+ // This is a pure text that should be pseudolocalized
const char* p = pseudolocalize_char(c);
if (p != NULL) {
- result += p;
+ result += String16(p);
} else {
- result += c;
+ result.append(&c, 1);
}
}
}
-
- //printf("result=\'%s\'\n", result.c_str());
return result;
}
+String16
+pseudobidi_string(const String16& source)
+{
+ const char16_t* s = source.string();
+ String16 result;
+ result += k_rlm;
+ result += k_rlo;
+ for (size_t i=0; i<source.size(); i++) {
+ char16_t c = s[i];
+ switch(c) {
+ case ' ': result += k_pdf;
+ result += k_rlm;
+ result.append(&c, 1);
+ result += k_rlm;
+ result += k_rlo;
+ break;
+ default: result.append(&c, 1);
+ break;
+ }
+ }
+ result += k_pdf;
+ result += k_rlm;
+ return result;
+}
diff --git a/tools/aapt/pseudolocalize.h b/tools/aapt/pseudolocalize.h
index 94cb034..e6ab18e 100644
--- a/tools/aapt/pseudolocalize.h
+++ b/tools/aapt/pseudolocalize.h
@@ -1,9 +1,18 @@
#ifndef HOST_PSEUDOLOCALIZE_H
#define HOST_PSEUDOLOCALIZE_H
+#include "StringPool.h"
+
#include <string>
-std::string pseudolocalize_string(const std::string& source);
+String16 pseudolocalize_string(const String16& source);
+// Surrounds every word in the sentance with specific characters that makes
+// the word directionality RTL.
+String16 pseudobidi_string(const String16& source);
+// Generates expansion string based on the specified lenght.
+// Generated string could not be shorter that length, but it could be slightly
+// longer.
+String16 pseudo_generate_expansion(const unsigned int length);
#endif // HOST_PSEUDOLOCALIZE_H
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index ebfe9bc..8862f5b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -355,227 +355,162 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_setConcat(long native_object, long a, long b) {
+ /*package*/ static void native_setConcat(long native_object, long a, long b) {
if (a == native_object) {
- return native_preConcat(native_object, b);
+ native_preConcat(native_object, b);
+ return;
} else if (b == native_object) {
- return native_postConcat(native_object, a);
+ native_postConcat(native_object, a);
+ return;
}
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
- }
-
Matrix_Delegate a_mtx = sManager.getDelegate(a);
- if (a_mtx == null) {
- return false;
- }
-
Matrix_Delegate b_mtx = sManager.getDelegate(b);
- if (b_mtx == null) {
- return false;
+ if (d != null && a_mtx != null && b_mtx != null) {
+ multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
}
-
- multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
-
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preTranslate(long native_object, float dx, float dy) {
+ /*package*/ static void native_preTranslate(long native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getTranslate(dx, dy));
}
-
- d.preTransform(getTranslate(dx, dy));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preScale(long native_object, float sx, float sy,
+ /*package*/ static void native_preScale(long native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getScale(sx, sy, px, py));
}
-
- d.preTransform(getScale(sx, sy, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preScale(long native_object, float sx, float sy) {
+ /*package*/ static void native_preScale(long native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getScale(sx, sy));
}
-
- d.preTransform(getScale(sx, sy));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preRotate(long native_object, float degrees,
+ /*package*/ static void native_preRotate(long native_object, float degrees,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getRotate(degrees, px, py));
}
-
- d.preTransform(getRotate(degrees, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preRotate(long native_object, float degrees) {
+ /*package*/ static void native_preRotate(long native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+
+ double rad = Math.toRadians(degrees);
+ float sin = (float) Math.sin(rad);
+ float cos = (float) Math.cos(rad);
+
+ d.preTransform(getRotate(sin, cos));
}
-
- double rad = Math.toRadians(degrees);
- float sin = (float)Math.sin(rad);
- float cos = (float)Math.cos(rad);
-
- d.preTransform(getRotate(sin, cos));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preSkew(long native_object, float kx, float ky,
+ /*package*/ static void native_preSkew(long native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getSkew(kx, ky, px, py));
}
-
- d.preTransform(getSkew(kx, ky, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preSkew(long native_object, float kx, float ky) {
+ /*package*/ static void native_preSkew(long native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.preTransform(getSkew(kx, ky));
}
-
- d.preTransform(getSkew(kx, ky));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_preConcat(long native_object, long other_matrix) {
+ /*package*/ static void native_preConcat(long native_object, long other_matrix) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
- }
-
Matrix_Delegate other = sManager.getDelegate(other_matrix);
- if (other == null) {
- return false;
+ if (d != null && other != null) {
+ d.preTransform(other.mValues);
}
-
- d.preTransform(other.mValues);
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postTranslate(long native_object, float dx, float dy) {
+ /*package*/ static void native_postTranslate(long native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getTranslate(dx, dy));
}
-
- d.postTransform(getTranslate(dx, dy));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postScale(long native_object, float sx, float sy,
+ /*package*/ static void native_postScale(long native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getScale(sx, sy, px, py));
}
-
- d.postTransform(getScale(sx, sy, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postScale(long native_object, float sx, float sy) {
+ /*package*/ static void native_postScale(long native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getScale(sx, sy));
}
-
- d.postTransform(getScale(sx, sy));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postRotate(long native_object, float degrees,
+ /*package*/ static void native_postRotate(long native_object, float degrees,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getRotate(degrees, px, py));
}
-
- d.postTransform(getRotate(degrees, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postRotate(long native_object, float degrees) {
+ /*package*/ static void native_postRotate(long native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getRotate(degrees));
}
-
- d.postTransform(getRotate(degrees));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postSkew(long native_object, float kx, float ky,
+ /*package*/ static void native_postSkew(long native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getSkew(kx, ky, px, py));
}
-
- d.postTransform(getSkew(kx, ky, px, py));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postSkew(long native_object, float kx, float ky) {
+ /*package*/ static void native_postSkew(long native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
+ if (d != null) {
+ d.postTransform(getSkew(kx, ky));
}
-
- d.postTransform(getSkew(kx, ky));
- return true;
}
@LayoutlibDelegate
- /*package*/ static boolean native_postConcat(long native_object, long other_matrix) {
+ /*package*/ static void native_postConcat(long native_object, long other_matrix) {
Matrix_Delegate d = sManager.getDelegate(native_object);
- if (d == null) {
- return false;
- }
-
Matrix_Delegate other = sManager.getDelegate(other_matrix);
- if (other == null) {
- return false;
+ if (d != null && other != null) {
+ d.postTransform(other.mValues);
}
-
- d.postTransform(other.mValues);
- return true;
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index de2e592..25eaaf5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -428,6 +428,16 @@
}
@LayoutlibDelegate
+ /*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setElegantTextHeight(Paint thisPaint, boolean elegant) {
+ // TODO
+ }
+
+ @LayoutlibDelegate
/*package*/ static float getTextSize(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index cdbe200..af22f44 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -32,10 +32,6 @@
import android.content.Context;
import android.util.AttributeSet;
-import android.view.InflateException;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
import java.io.File;
@@ -155,6 +151,9 @@
@Override
public View inflate(int resource, ViewGroup root) {
Context context = getContext();
+ if (context instanceof ContextThemeWrapper) {
+ context = ((ContextThemeWrapper) context).getBaseContext();
+ }
if (context instanceof BridgeContext) {
BridgeContext bridgeContext = (BridgeContext)context;
@@ -217,43 +216,16 @@
}
private void setupViewInContext(View view, AttributeSet attrs) {
- if (getContext() instanceof BridgeContext) {
- BridgeContext bc = (BridgeContext) getContext();
- if (attrs instanceof BridgeXmlBlockParser) {
- BridgeXmlBlockParser parser = (BridgeXmlBlockParser) attrs;
-
- // get the view key
- Object viewKey = parser.getViewCookie();
-
- if (viewKey == null) {
- int currentDepth = parser.getDepth();
-
- // test whether we are in an included file or in a adapter binding view.
- BridgeXmlBlockParser previousParser = bc.getPreviousParser();
- if (previousParser != null) {
- // looks like we inside an embedded layout.
- // only apply the cookie of the calling node (<include>) if we are at the
- // top level of the embedded layout. If there is a merge tag, then
- // skip it and look for the 2nd level
- int testDepth = mIsInMerge ? 2 : 1;
- if (currentDepth == testDepth) {
- viewKey = previousParser.getViewCookie();
- // if we are in a merge, wrap the cookie in a MergeCookie.
- if (viewKey != null && mIsInMerge) {
- viewKey = new MergeCookie(viewKey);
- }
- }
- } else if (mResourceReference != null && currentDepth == 1) {
- // else if there's a resource reference, this means we are in an adapter
- // binding case. Set the resource ref as the view cookie only for the top
- // level view.
- viewKey = mResourceReference;
- }
- }
-
- if (viewKey != null) {
- bc.addViewKey(view, viewKey);
- }
+ Context context = getContext();
+ if (context instanceof ContextThemeWrapper) {
+ context = ((ContextThemeWrapper) context).getBaseContext();
+ }
+ if (context instanceof BridgeContext) {
+ BridgeContext bc = (BridgeContext) context;
+ // get the view key
+ Object viewKey = getViewKeyFromParser(attrs, bc, mResourceReference, mIsInMerge);
+ if (viewKey != null) {
+ bc.addViewKey(view, viewKey);
}
}
}
@@ -270,4 +242,44 @@
public LayoutInflater cloneInContext(Context newContext) {
return new BridgeInflater(this, newContext);
}
+
+ /*package*/ static Object getViewKeyFromParser(AttributeSet attrs, BridgeContext bc,
+ ResourceReference resourceReference, boolean isInMerge) {
+
+ if (!(attrs instanceof BridgeXmlBlockParser)) {
+ return null;
+ }
+ BridgeXmlBlockParser parser = ((BridgeXmlBlockParser) attrs);
+
+ // get the view key
+ Object viewKey = parser.getViewCookie();
+
+ if (viewKey == null) {
+ int currentDepth = parser.getDepth();
+
+ // test whether we are in an included file or in a adapter binding view.
+ BridgeXmlBlockParser previousParser = bc.getPreviousParser();
+ if (previousParser != null) {
+ // looks like we are inside an embedded layout.
+ // only apply the cookie of the calling node (<include>) if we are at the
+ // top level of the embedded layout. If there is a merge tag, then
+ // skip it and look for the 2nd level
+ int testDepth = isInMerge ? 2 : 1;
+ if (currentDepth == testDepth) {
+ viewKey = previousParser.getViewCookie();
+ // if we are in a merge, wrap the cookie in a MergeCookie.
+ if (viewKey != null && isInMerge) {
+ viewKey = new MergeCookie(viewKey);
+ }
+ }
+ } else if (resourceReference != null && currentDepth == 1) {
+ // else if there's a resource reference, this means we are in an adapter
+ // binding case. Set the resource ref as the view cookie only for the top
+ // level view.
+ viewKey = resourceReference;
+ }
+ }
+
+ return viewKey;
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
new file mode 100644
index 0000000..0dddf3d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
@@ -0,0 +1,74 @@
+/*
+ * 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.view;
+
+import android.content.Context;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.internal.view.menu.BridgeMenuItemImpl;
+import com.android.internal.view.menu.MenuView;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.util.AttributeSet;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link MenuInflater}
+ * <p/>
+ * Through the layoutlib_create tool, the original methods of MenuInflater have been
+ * replaced by calls to methods of the same name in this delegate class.
+ * <p/>
+ * The main purpose of the class is to get the view key from the menu xml parser and add it to
+ * the menu item. The view key is used by the IDE to match the individual view elements to the
+ * corresponding xml tag in the menu/layout file.
+ * <p/>
+ * For Menus, the views may be reused and the {@link MenuItem} is a better object to hold the
+ * view key than the {@link MenuView.ItemView}. At the time of computation of the rest of {@link
+ * ViewInfo}, we check the corresponding view key in the menu item for the view and add it
+ */
+public class MenuInflater_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static void registerMenu(MenuInflater thisInflater, MenuItem menuItem,
+ AttributeSet attrs) {
+ if (menuItem instanceof BridgeMenuItemImpl) {
+ Context context = thisInflater.getContext();
+ if (context instanceof ContextThemeWrapper) {
+ context = ((ContextThemeWrapper) context).getBaseContext();
+ }
+ if (context instanceof BridgeContext) {
+ Object viewKey = BridgeInflater.getViewKeyFromParser(
+ attrs, ((BridgeContext) context), null, false);
+ ((BridgeMenuItemImpl) menuItem).setViewCookie(viewKey);
+ return;
+ }
+ }
+ // This means that Bridge did not take over the instantiation of some object properly.
+ // This is most likely a bug in the LayoutLib code.
+ Bridge.getLog().warning(LayoutLog.TAG_BROKEN,
+ "Action Bar Menu rendering may be incorrect.", null);
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void registerMenu(MenuInflater thisInflater, SubMenu subMenu,
+ AttributeSet parser) {
+ registerMenu(thisInflater, subMenu.getItem(), parser);
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
new file mode 100644
index 0000000..4bef424
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.internal.view.menu;
+
+/**
+ * An extension of the {@link MenuItemImpl} to store the view cookie also.
+ */
+public class BridgeMenuItemImpl extends MenuItemImpl {
+
+ /**
+ * An object returned by the IDE that helps mapping each View to the corresponding XML tag in
+ * the layout. For Menus, we store this cookie here and attach it to the corresponding view
+ * at the time of rendering.
+ */
+ private Object viewCookie;
+
+ /**
+ * Instantiates this menu item.
+ */
+ BridgeMenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
+ CharSequence title, int showAsAction) {
+ super(menu, group, id, categoryOrder, ordering, title, showAsAction);
+ }
+
+
+ public Object getViewCookie() {
+ return viewCookie;
+ }
+
+ public void setViewCookie(Object viewCookie) {
+ this.viewCookie = viewCookie;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilder_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilder_Delegate.java
new file mode 100644
index 0000000..505fb81
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilder_Delegate.java
@@ -0,0 +1,38 @@
+/*
+ * 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.internal.view.menu;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link MenuBuilder}
+ * <p/>
+ * Through the layoutlib_create tool, the original methods of {@code MenuBuilder} have been
+ * replaced by calls to methods of the same name in this delegate class.
+ */
+public class MenuBuilder_Delegate {
+ /**
+ * The method overrides the instantiation of the {@link MenuItemImpl} with an instance of
+ * {@link BridgeMenuItemImpl} so that view cookies may be stored.
+ */
+ @LayoutlibDelegate
+ /*package*/ static MenuItemImpl createNewMenuItem(MenuBuilder thisMenu, int group, int id,
+ int categoryOrder, int ordering, CharSequence title, int defaultShowAsAction) {
+ return new BridgeMenuItemImpl(thisMenu, group, id, categoryOrder, ordering, title,
+ defaultShowAsAction);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 6595ce1..08e9d99 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -58,6 +58,7 @@
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -101,6 +102,7 @@
private final ApplicationInfo mApplicationInfo;
private final IProjectCallback mProjectCallback;
private final WindowManager mWindowManager;
+ private final DisplayManager mDisplayManager;
private Resources.Theme mTheme;
@@ -149,6 +151,7 @@
}
mWindowManager = new WindowManagerImpl(mMetrics);
+ mDisplayManager = new DisplayManager(this);
}
/**
@@ -455,6 +458,10 @@
return new PowerManager(this, new BridgePowerManager(), new Handler());
}
+ if (DISPLAY_SERVICE.equals(service)) {
+ return mDisplayManager;
+ }
+
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index afcadef..9787432 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -28,7 +28,6 @@
import com.android.ide.common.rendering.api.IAnimationListener;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.IProjectCallback;
-import com.android.ide.common.rendering.api.RenderParams;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.RenderSession;
import com.android.ide.common.rendering.api.ResourceReference;
@@ -39,6 +38,12 @@
import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
import com.android.ide.common.rendering.api.ViewInfo;
import com.android.internal.util.XmlUtils;
+import com.android.internal.view.menu.ActionMenuItemView;
+import com.android.internal.view.menu.BridgeMenuItemImpl;
+import com.android.internal.view.menu.IconMenuItemView;
+import com.android.internal.view.menu.ListMenuItemView;
+import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.view.menu.MenuView;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
@@ -101,11 +106,10 @@
/**
* Class implementing the render session.
- *
+ * <p/>
* A session is a stateful representation of a layout file. It is initialized with data coming
* through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
* be done on the layout.
- *
*/
public class RenderSessionImpl extends RenderAction<SessionParams> {
@@ -172,7 +176,7 @@
@Override
public Result init(long timeout) {
Result result = super.init(timeout);
- if (result.isSuccess() == false) {
+ if (!result.isSuccess()) {
return result;
}
@@ -196,6 +200,7 @@
// FIXME: find those out, and possibly add them to the render params
boolean hasNavigationBar = true;
+ //noinspection ConstantConditions
IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
metrics, Surface.ROTATION_0,
hasNavigationBar);
@@ -229,10 +234,9 @@
BridgeContext context = getContext();
boolean isRtl = Bridge.isLocaleRtl(params.getLocale());
int layoutDirection = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
- ActionBarLayout actionBar = null;
// the view group that receives the window background.
- ViewGroup backgroundView = null;
+ ViewGroup backgroundView;
if (mWindowIsFloating || params.isForceNoDecor()) {
backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
@@ -266,7 +270,7 @@
NavigationBar navigationBar = createNavigationBar(context,
hardwareConfig.getDensity(), isRtl, params.isRtlSupported());
topLayout.addView(navigationBar);
- } catch (XmlPullParserException e) {
+ } catch (XmlPullParserException ignored) {
}
}
@@ -322,7 +326,7 @@
StatusBar statusBar = createStatusBar(context, hardwareConfig.getDensity(),
layoutDirection, params.isRtlSupported());
topLayout.addView(statusBar);
- } catch (XmlPullParserException e) {
+ } catch (XmlPullParserException ignored) {
}
}
@@ -339,20 +343,16 @@
// if the theme says no title/action bar, then the size will be 0
if (mActionBarSize > 0) {
- try {
- actionBar = createActionBar(context, params);
- backgroundLayout.addView(actionBar);
- actionBar.createMenuPopup();
- mContentRoot = actionBar.getContentRoot();
- } catch (XmlPullParserException e) {
-
- }
+ ActionBarLayout actionBar = createActionBar(context, params);
+ backgroundLayout.addView(actionBar);
+ actionBar.createMenuPopup();
+ mContentRoot = actionBar.getContentRoot();
} else if (mTitleBarSize > 0) {
try {
TitleBar titleBar = createTitleBar(context,
hardwareConfig.getDensity(), params.getAppLabel());
backgroundLayout.addView(titleBar);
- } catch (XmlPullParserException e) {
+ } catch (XmlPullParserException ignored) {
}
}
@@ -374,7 +374,7 @@
NavigationBar navigationBar = createNavigationBar(context,
hardwareConfig.getDensity(), isRtl, params.isRtlSupported());
topLayout.addView(navigationBar);
- } catch (XmlPullParserException e) {
+ } catch (XmlPullParserException ignored) {
}
}
@@ -399,7 +399,7 @@
postInflateProcess(view, params.getProjectCallback());
// get the background drawable
- if (mWindowBackground != null && backgroundView != null) {
+ if (mWindowBackground != null) {
Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
backgroundView.setBackground(d);
}
@@ -476,6 +476,7 @@
// first measure the full layout, with EXACTLY to get the size of the
// content as it is inside the decor/dialog
+ @SuppressWarnings("deprecation")
Pair<Integer, Integer> exactMeasure = measureView(
mViewRoot, mContentRoot.getChildAt(0),
mMeasuredScreenWidth, MeasureSpec.EXACTLY,
@@ -483,6 +484,7 @@
// now measure the content only using UNSPECIFIED (where applicable, based on
// the rendering mode). This will give us the size the content needs.
+ @SuppressWarnings("deprecation")
Pair<Integer, Integer> result = measureView(
mContentRoot, mContentRoot.getChildAt(0),
mMeasuredScreenWidth, widthMeasureSpecMode,
@@ -558,7 +560,7 @@
mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
}
- if (freshRender && newImage == false) {
+ if (freshRender && !newImage) {
Graphics2D gc = mImage.createGraphics();
gc.setComposite(AlphaComposite.Src);
@@ -573,7 +575,8 @@
mViewRoot.draw(mCanvas);
}
- mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(), false);
+ mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
+ false);
// success!
return SUCCESS.createResult();
@@ -603,6 +606,7 @@
* @param heightMode the MeasureSpec mode to use for the height.
* @return the measured width/height if measuredView is non-null, null otherwise.
*/
+ @SuppressWarnings("deprecation") // For the use of Pair
private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
int width, int widthMode, int height, int heightMode) {
int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
@@ -633,7 +637,7 @@
BridgeContext context = getContext();
// find the animation file.
- ResourceValue animationResource = null;
+ ResourceValue animationResource;
int animationId = 0;
if (isFrameworkAnimation) {
animationResource = context.getRenderResources().getFrameworkResource(
@@ -723,7 +727,7 @@
// add it to the parentView in the correct location
Result result = addView(parentView, child, index);
- if (result.isSuccess() == false) {
+ if (!result.isSuccess()) {
return result;
}
@@ -793,13 +797,13 @@
public void run() {
Result result = moveView(previousParent, newParentView, childView, index,
params);
- if (result.isSuccess() == false) {
+ if (!result.isSuccess()) {
listener.done(result);
}
// ready to do the work, acquire the scene.
result = acquire(250);
- if (result.isSuccess() == false) {
+ if (!result.isSuccess()) {
listener.done(result);
return;
}
@@ -857,7 +861,7 @@
}
Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
- if (result.isSuccess() == false) {
+ if (!result.isSuccess()) {
return result;
}
@@ -991,7 +995,7 @@
}
Result result = removeView(parent, childView);
- if (result.isSuccess() == false) {
+ if (!result.isSuccess()) {
return result;
}
@@ -1019,7 +1023,7 @@
private void findBackground(RenderResources resources) {
- if (getParams().isBgColorOverridden() == false) {
+ if (!getParams().isBgColorOverridden()) {
mWindowBackground = resources.findItemInTheme("windowBackground",
true /*isFrameworkAttr*/);
if (mWindowBackground != null) {
@@ -1036,7 +1040,7 @@
boolean windowFullscreen = getBooleanThemeValue(resources,
"windowFullscreen", false /*defaultValue*/);
- if (windowFullscreen == false && mWindowIsFloating == false) {
+ if (!windowFullscreen && !mWindowIsFloating) {
// default value
mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
@@ -1090,7 +1094,7 @@
boolean windowNoTitle = getBooleanThemeValue(resources,
"windowNoTitle", false /*defaultValue*/);
- if (windowNoTitle == false) {
+ if (!windowNoTitle) {
// default size of the window title bar
mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT;
@@ -1117,7 +1121,7 @@
}
private void findNavigationBar(RenderResources resources, DisplayMetrics metrics) {
- if (hasSoftwareButtons() && mWindowIsFloating == false) {
+ if (hasSoftwareButtons() && !mWindowIsFloating) {
// default value
mNavigationBarSize = 48; // ??
@@ -1131,15 +1135,12 @@
int shortSize = hardwareConfig.getScreenHeight();
// compute in dp
- int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / hardwareConfig.getDensity().getDpiValue();
+ int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT /
+ hardwareConfig.getDensity().getDpiValue();
- if (shortSizeDp < 600) {
- // 0-599dp: "phone" UI with bar on the side
- barOnBottom = false;
- } else {
- // 600+dp: "tablet" UI with bar on the bottom
- barOnBottom = true;
- }
+ // 0-599dp: "phone" UI with bar on the side
+ // 600+dp: "tablet" UI with bar on the bottom
+ barOnBottom = shortSizeDp >= 600;
}
if (barOnBottom) {
@@ -1190,13 +1191,15 @@
}
/**
- * Post process on a view hierachy that was just inflated.
- * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
+ * Post process on a view hierarchy that was just inflated.
+ * <p/>
+ * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the
* {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
* based on the content of the {@link FrameLayout}.
* @param view the root view to process.
* @param projectCallback callback to the project.
*/
+ @SuppressWarnings("deprecation") // For the use of Pair
private void postInflateProcess(View view, IProjectCallback projectCallback)
throws PostInflateException {
if (view instanceof TabHost) {
@@ -1299,7 +1302,7 @@
"TabHost requires a TabWidget with id \"android:id/tabs\".\n");
}
- if ((v instanceof TabWidget) == false) {
+ if (!(v instanceof TabWidget)) {
throw new PostInflateException(String.format(
"TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
"View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
@@ -1308,12 +1311,14 @@
v = tabHost.findViewById(android.R.id.tabcontent);
if (v == null) {
- // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
+ // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty)
+ //noinspection SpellCheckingInspection
throw new PostInflateException(
"TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
}
- if ((v instanceof FrameLayout) == false) {
+ if (!(v instanceof FrameLayout)) {
+ //noinspection SpellCheckingInspection
throw new PostInflateException(String.format(
"TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
"View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
@@ -1321,7 +1326,7 @@
FrameLayout content = (FrameLayout)v;
- // now process the content of the framelayout and dynamically create tabs for it.
+ // now process the content of the frameLayout and dynamically create tabs for it.
final int count = content.getChildCount();
// this must be called before addTab() so that the TabHost searches its TabWidget
@@ -1339,13 +1344,13 @@
}
});
tabHost.addTab(spec);
- return;
} else {
- // for each child of the framelayout, add a new TabSpec
+ // for each child of the frameLayout, add a new TabSpec
for (int i = 0 ; i < count ; i++) {
View child = content.getChildAt(i);
String tabSpec = String.format("tab_spec%d", i+1);
int id = child.getId();
+ @SuppressWarnings("deprecation")
Pair<ResourceType, String> resource = projectCallback.resolveResourceId(id);
String name;
if (resource != null) {
@@ -1468,13 +1473,13 @@
ViewInfo result;
if (isContentFrame) {
result = new ViewInfo(view.getClass().getName(),
- getContext().getViewKey(view),
+ getViewKey(view),
view.getLeft(), view.getTop() + offset, view.getRight(),
view.getBottom() + offset, view, view.getLayoutParams());
} else {
result = new SystemViewInfo(view.getClass().getName(),
- getContext().getViewKey(view),
+ getViewKey(view),
view.getLeft(), view.getTop(), view.getRight(),
view.getBottom(), view, view.getLayoutParams());
}
@@ -1495,6 +1500,32 @@
return result;
}
+ /**
+ * The cookie for menu items are stored in menu item and not in the map from View stored in
+ * BridgeContext.
+ */
+ private Object getViewKey(View view) {
+ BridgeContext context = getContext();
+ if (!(view instanceof MenuView.ItemView)) {
+ return context.getViewKey(view);
+ }
+ MenuItemImpl menuItem;
+ if (view instanceof ActionMenuItemView) {
+ menuItem = ((ActionMenuItemView) view).getItemData();
+ } else if (view instanceof ListMenuItemView) {
+ menuItem = ((ListMenuItemView) view).getItemData();
+ } else if (view instanceof IconMenuItemView) {
+ menuItem = ((IconMenuItemView) view).getItemData();
+ } else {
+ menuItem = null;
+ }
+ if (menuItem instanceof BridgeMenuItemImpl) {
+ return ((BridgeMenuItemImpl) menuItem).getViewCookie();
+ }
+
+ return null;
+ }
+
private void invalidateRenderingSize() {
mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
}
@@ -1545,8 +1576,7 @@
/**
* Creates the action bar. Also queries the project callback for missing information.
*/
- private ActionBarLayout createActionBar(BridgeContext context, SessionParams params)
- throws XmlPullParserException {
+ private ActionBarLayout createActionBar(BridgeContext context, SessionParams params) {
ActionBarLayout actionBar = new ActionBarLayout(context, params);
actionBar.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index b16b4aa..19d249b 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -253,4 +253,14 @@
return true;
}
+
+ @LayoutlibDelegate
+ /*package*/ static void setDefaultLocale(String locale) {
+ ICU.setDefaultLocale(locale);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String getDefaultLocale() {
+ return ICU.getDefaultLocale();
+ }
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index e0c05de..813a895 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -143,6 +143,8 @@
"android.view.ViewRootImpl#isInTouchMode",
"android.view.WindowManagerGlobal#getWindowManagerService",
"android.view.inputmethod.InputMethodManager#getInstance",
+ "android.view.MenuInflater#registerMenu",
+ "com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
"com.android.internal.util.XmlUtils#convertValueToInt",
"com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
};