1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v4.app; 18 19import android.app.Activity; 20import android.app.ActivityOptions; 21import android.app.PendingIntent; 22import android.content.Context; 23import android.graphics.Bitmap; 24import android.graphics.Rect; 25import android.os.Build; 26import android.os.Bundle; 27import android.support.annotation.Nullable; 28import android.support.annotation.RequiresApi; 29import android.support.v4.util.Pair; 30import android.view.View; 31 32/** 33 * Helper for accessing features in {@link android.app.ActivityOptions} in a backwards compatible 34 * fashion. 35 */ 36public class ActivityOptionsCompat { 37 /** 38 * A long in the extras delivered by {@link #requestUsageTimeReport} that contains 39 * the total time (in ms) the user spent in the app flow. 40 */ 41 public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; 42 43 /** 44 * A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains 45 * detailed information about the time spent in each package associated with the app; 46 * each key is a package name, whose value is a long containing the time (in ms). 47 */ 48 public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages"; 49 50 /** 51 * Create an ActivityOptions specifying a custom animation to run when the 52 * activity is displayed. 53 * 54 * @param context Who is defining this. This is the application that the 55 * animation resources will be loaded from. 56 * @param enterResId A resource ID of the animation resource to use for the 57 * incoming activity. Use 0 for no animation. 58 * @param exitResId A resource ID of the animation resource to use for the 59 * outgoing activity. Use 0 for no animation. 60 * @return Returns a new ActivityOptions object that you can use to supply 61 * these options as the options Bundle when starting an activity. 62 */ 63 public static ActivityOptionsCompat makeCustomAnimation(Context context, 64 int enterResId, int exitResId) { 65 if (Build.VERSION.SDK_INT >= 16) { 66 return createImpl(ActivityOptions.makeCustomAnimation(context, enterResId, exitResId)); 67 } 68 return new ActivityOptionsCompat(); 69 } 70 71 /** 72 * Create an ActivityOptions specifying an animation where the new activity is 73 * scaled from a small originating area of the screen to its final full 74 * representation. 75 * <p/> 76 * If the Intent this is being used with has not set its 77 * {@link android.content.Intent#setSourceBounds(android.graphics.Rect)}, 78 * those bounds will be filled in for you based on the initial bounds passed 79 * in here. 80 * 81 * @param source The View that the new activity is animating from. This 82 * defines the coordinate space for startX and startY. 83 * @param startX The x starting location of the new activity, relative to 84 * source. 85 * @param startY The y starting location of the activity, relative to source. 86 * @param startWidth The initial width of the new activity. 87 * @param startHeight The initial height of the new activity. 88 * @return Returns a new ActivityOptions object that you can use to supply 89 * these options as the options Bundle when starting an activity. 90 */ 91 public static ActivityOptionsCompat makeScaleUpAnimation(View source, 92 int startX, int startY, int startWidth, int startHeight) { 93 if (Build.VERSION.SDK_INT >= 16) { 94 return createImpl(ActivityOptions.makeScaleUpAnimation( 95 source, startX, startY, startWidth, startHeight)); 96 } 97 return new ActivityOptionsCompat(); 98 } 99 100 /** 101 * Create an ActivityOptions specifying an animation where the new 102 * activity is revealed from a small originating area of the screen to 103 * its final full representation. 104 * 105 * @param source The View that the new activity is animating from. This 106 * defines the coordinate space for <var>startX</var> and <var>startY</var>. 107 * @param startX The x starting location of the new activity, relative to <var>source</var>. 108 * @param startY The y starting location of the activity, relative to <var>source</var>. 109 * @param width The initial width of the new activity. 110 * @param height The initial height of the new activity. 111 * @return Returns a new ActivityOptions object that you can use to 112 * supply these options as the options Bundle when starting an activity. 113 */ 114 public static ActivityOptionsCompat makeClipRevealAnimation(View source, 115 int startX, int startY, int width, int height) { 116 if (Build.VERSION.SDK_INT >= 23) { 117 return createImpl(ActivityOptions.makeClipRevealAnimation( 118 source, startX, startY, width, height)); 119 } 120 return new ActivityOptionsCompat(); 121 } 122 123 /** 124 * Create an ActivityOptions specifying an animation where a thumbnail is 125 * scaled from a given position to the new activity window that is being 126 * started. 127 * <p/> 128 * If the Intent this is being used with has not set its 129 * {@link android.content.Intent#setSourceBounds(android.graphics.Rect)}, 130 * those bounds will be filled in for you based on the initial thumbnail 131 * location and size provided here. 132 * 133 * @param source The View that this thumbnail is animating from. This 134 * defines the coordinate space for startX and startY. 135 * @param thumbnail The bitmap that will be shown as the initial thumbnail 136 * of the animation. 137 * @param startX The x starting location of the bitmap, relative to source. 138 * @param startY The y starting location of the bitmap, relative to source. 139 * @return Returns a new ActivityOptions object that you can use to supply 140 * these options as the options Bundle when starting an activity. 141 */ 142 public static ActivityOptionsCompat makeThumbnailScaleUpAnimation(View source, 143 Bitmap thumbnail, int startX, int startY) { 144 if (Build.VERSION.SDK_INT >= 16) { 145 return createImpl(ActivityOptions.makeThumbnailScaleUpAnimation( 146 source, thumbnail, startX, startY)); 147 } 148 return new ActivityOptionsCompat(); 149 } 150 151 /** 152 * Create an ActivityOptions to transition between Activities using cross-Activity scene 153 * animations. This method carries the position of one shared element to the started Activity. 154 * The position of <code>sharedElement</code> will be used as the epicenter for the 155 * exit Transition. The position of the shared element in the launched Activity will be the 156 * epicenter of its entering Transition. 157 * 158 * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be 159 * enabled on the calling Activity to cause an exit transition. The same must be in 160 * the called Activity to get an entering transition.</p> 161 * @param activity The Activity whose window contains the shared elements. 162 * @param sharedElement The View to transition to the started Activity. sharedElement must 163 * have a non-null sharedElementName. 164 * @param sharedElementName The shared element name as used in the target Activity. This may 165 * be null if it has the same name as sharedElement. 166 * @return Returns a new ActivityOptions object that you can use to 167 * supply these options as the options Bundle when starting an activity. 168 */ 169 public static ActivityOptionsCompat makeSceneTransitionAnimation(Activity activity, 170 View sharedElement, String sharedElementName) { 171 if (Build.VERSION.SDK_INT >= 21) { 172 return createImpl(ActivityOptions.makeSceneTransitionAnimation( 173 activity, sharedElement, sharedElementName)); 174 } 175 return new ActivityOptionsCompat(); 176 } 177 178 /** 179 * Create an ActivityOptions to transition between Activities using cross-Activity scene 180 * animations. This method carries the position of multiple shared elements to the started 181 * Activity. The position of the first element in sharedElements 182 * will be used as the epicenter for the exit Transition. The position of the associated 183 * shared element in the launched Activity will be the epicenter of its entering Transition. 184 * 185 * <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be 186 * enabled on the calling Activity to cause an exit transition. The same must be in 187 * the called Activity to get an entering transition.</p> 188 * @param activity The Activity whose window contains the shared elements. 189 * @param sharedElements The names of the shared elements to transfer to the called 190 * Activity and their associated Views. The Views must each have 191 * a unique shared element name. 192 * @return Returns a new ActivityOptions object that you can use to 193 * supply these options as the options Bundle when starting an activity. 194 */ 195 @SuppressWarnings("unchecked") 196 public static ActivityOptionsCompat makeSceneTransitionAnimation(Activity activity, 197 Pair<View, String>... sharedElements) { 198 if (Build.VERSION.SDK_INT >= 21) { 199 android.util.Pair<View, String>[] pairs = null; 200 if (sharedElements != null) { 201 pairs = new android.util.Pair[sharedElements.length]; 202 for (int i = 0; i < sharedElements.length; i++) { 203 pairs[i] = android.util.Pair.create( 204 sharedElements[i].first, sharedElements[i].second); 205 } 206 } 207 return createImpl(ActivityOptions.makeSceneTransitionAnimation(activity, pairs)); 208 } 209 return new ActivityOptionsCompat(); 210 } 211 212 /** 213 * If set along with Intent.FLAG_ACTIVITY_NEW_DOCUMENT then the task being launched will not be 214 * presented to the user but will instead be only available through the recents task list. 215 * In addition, the new task wil be affiliated with the launching activity's task. 216 * Affiliated tasks are grouped together in the recents task list. 217 * 218 * <p>This behavior is not supported for activities with 219 * {@link android.R.attr#launchMode launchMode} values of 220 * <code>singleInstance</code> or <code>singleTask</code>. 221 */ 222 public static ActivityOptionsCompat makeTaskLaunchBehind() { 223 if (Build.VERSION.SDK_INT >= 21) { 224 return createImpl(ActivityOptions.makeTaskLaunchBehind()); 225 } 226 return new ActivityOptionsCompat(); 227 } 228 229 /** 230 * Create a basic ActivityOptions that has no special animation associated with it. 231 * Other options can still be set. 232 */ 233 public static ActivityOptionsCompat makeBasic() { 234 if (Build.VERSION.SDK_INT >= 23) { 235 return createImpl(ActivityOptions.makeBasic()); 236 } 237 return new ActivityOptionsCompat(); 238 } 239 240 @RequiresApi(16) 241 private static ActivityOptionsCompat createImpl(ActivityOptions options) { 242 if (Build.VERSION.SDK_INT >= 24) { 243 return new ActivityOptionsCompatApi24Impl(options); 244 } else if (Build.VERSION.SDK_INT >= 23) { 245 return new ActivityOptionsCompatApi23Impl(options); 246 } else { 247 return new ActivityOptionsCompatApi16Impl(options); 248 } 249 } 250 251 @RequiresApi(16) 252 private static class ActivityOptionsCompatApi16Impl extends ActivityOptionsCompat { 253 protected final ActivityOptions mActivityOptions; 254 255 ActivityOptionsCompatApi16Impl(ActivityOptions activityOptions) { 256 mActivityOptions = activityOptions; 257 } 258 259 @Override 260 public Bundle toBundle() { 261 return mActivityOptions.toBundle(); 262 } 263 264 @Override 265 public void update(ActivityOptionsCompat otherOptions) { 266 if (otherOptions instanceof ActivityOptionsCompatApi16Impl) { 267 ActivityOptionsCompatApi16Impl otherImpl = 268 (ActivityOptionsCompatApi16Impl) otherOptions; 269 mActivityOptions.update(otherImpl.mActivityOptions); 270 } 271 } 272 } 273 274 @RequiresApi(23) 275 private static class ActivityOptionsCompatApi23Impl extends ActivityOptionsCompatApi16Impl { 276 ActivityOptionsCompatApi23Impl(ActivityOptions activityOptions) { 277 super(activityOptions); 278 } 279 280 @Override 281 public void requestUsageTimeReport(PendingIntent receiver) { 282 mActivityOptions.requestUsageTimeReport(receiver); 283 } 284 } 285 286 @RequiresApi(24) 287 private static class ActivityOptionsCompatApi24Impl extends ActivityOptionsCompatApi23Impl { 288 ActivityOptionsCompatApi24Impl(ActivityOptions activityOptions) { 289 super(activityOptions); 290 } 291 292 @Override 293 public ActivityOptionsCompat setLaunchBounds(@Nullable Rect screenSpacePixelRect) { 294 return new ActivityOptionsCompatApi24Impl( 295 mActivityOptions.setLaunchBounds(screenSpacePixelRect)); 296 } 297 298 @Override 299 public Rect getLaunchBounds() { 300 return mActivityOptions.getLaunchBounds(); 301 } 302 } 303 304 protected ActivityOptionsCompat() { 305 } 306 307 /** 308 * Sets the bounds (window size) that the activity should be launched in. 309 * Rect position should be provided in pixels and in screen coordinates. 310 * Set to null explicitly for fullscreen. 311 * <p> 312 * <strong>NOTE:<strong/> This value is ignored on devices that don't have 313 * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or 314 * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled. 315 * @param screenSpacePixelRect Launch bounds to use for the activity or null for fullscreen. 316 */ 317 public ActivityOptionsCompat setLaunchBounds(@Nullable Rect screenSpacePixelRect) { 318 return null; 319 } 320 321 /** 322 * Returns the bounds that should be used to launch the activity. 323 * @see #setLaunchBounds(Rect) 324 * @return Bounds used to launch the activity. 325 */ 326 @Nullable 327 public Rect getLaunchBounds() { 328 return null; 329 } 330 331 /** 332 * Returns the created options as a Bundle, which can be passed to 333 * {@link android.support.v4.content.ContextCompat#startActivity(Context, android.content.Intent, Bundle)}. 334 * Note that the returned Bundle is still owned by the ActivityOptions 335 * object; you must not modify it, but can supply it to the startActivity 336 * methods that take an options Bundle. 337 */ 338 public Bundle toBundle() { 339 return null; 340 } 341 342 /** 343 * Update the current values in this ActivityOptions from those supplied in 344 * otherOptions. Any values defined in otherOptions replace those in the 345 * base options. 346 */ 347 public void update(ActivityOptionsCompat otherOptions) { 348 // Do nothing. 349 } 350 351 /** 352 * Ask the the system track that time the user spends in the app being launched, and 353 * report it back once done. The report will be sent to the given receiver, with 354 * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES} 355 * filled in. 356 * 357 * <p>The time interval tracked is from launching this activity until the user leaves 358 * that activity's flow. They are considered to stay in the flow as long as 359 * new activities are being launched or returned to from the original flow, 360 * even if this crosses package or task boundaries. For example, if the originator 361 * starts an activity to view an image, and while there the user selects to share, 362 * which launches their email app in a new task, and they complete the share, the 363 * time during that entire operation will be included until they finally hit back from 364 * the original image viewer activity.</p> 365 * 366 * <p>The user is considered to complete a flow once they switch to another 367 * activity that is not part of the tracked flow. This may happen, for example, by 368 * using the notification shade, launcher, or recents to launch or switch to another 369 * app. Simply going in to these navigation elements does not break the flow (although 370 * the launcher and recents stops time tracking of the session); it is the act of 371 * going somewhere else that completes the tracking.</p> 372 * 373 * @param receiver A broadcast receiver that will receive the report. 374 */ 375 public void requestUsageTimeReport(PendingIntent receiver) { 376 // Do nothing. 377 } 378} 379