Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2014 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 
     17 package android.app.usage.cts;
     18 
     19 import android.app.Activity;
     20 import android.app.SharedElementCallback;
     21 import android.content.Intent;
     22 import android.os.Bundle;
     23 import android.os.Parcel;
     24 import android.os.Parcelable;
     25 import android.os.ResultReceiver;
     26 import android.os.SystemClock;
     27 import android.transition.ChangeBounds;
     28 import android.transition.Explode;
     29 import android.transition.Fade;
     30 import android.transition.Transition;
     31 import android.transition.Transition.TransitionListener;
     32 import android.transition.TransitionListenerAdapter;
     33 import android.view.View;
     34 
     35 import java.util.List;
     36 import java.util.concurrent.CountDownLatch;
     37 
     38 /**
     39  * A simple activity containing the start state for an Activity Transition
     40  */
     41 public class ActivityTransitionActivity extends Activity {
     42     private static final long DURATION = 50;
     43     private static final long SHARED_ELEMENT_READY_DELAY = 50;
     44     public static final String LAYOUT_ID = "layoutId";
     45     public static final String TEST = "test";
     46     public static final String RESULT_RECEIVER = "resultReceiver";
     47     public static final String PAUSE_ON_RESTART = "pauseOnRestart";
     48     public static final String QUICK_FINISH = "quickFinish";
     49     public static final String ALLOW_OVERLAP = "allowOverlap";
     50     public static final String NO_RETURN_TRANSITION = "noReturnTransition";
     51 
     52     public static final int NO_TEST = 0;
     53     public static final int TEST_ARRIVE = 1;
     54 
     55     public static final String ARRIVE_COUNT = "numArrived";
     56     public static final String ARRIVE_ENTER_START_VISIBILITY = "arriveEnterStartVisibility";
     57     public static final String ARRIVE_ENTER_DELAY_VISIBILITY = "arriveEnterDelayVisibility";
     58     public static final String ARRIVE_ENTER_TIME_READY = "arriveEnterTimeReady";
     59     public static final String ARRIVE_ENTER_TIME = "arriveEnterTime";
     60     public static final String ARRIVE_RETURN_TIME_READY = "arriveReturnTimeReady";
     61     public static final String ARRIVE_RETURN_TIME = "arriveReturnTime";
     62 
     63     public static final String ENTER_VISIBILITY = "enterVisibility";
     64     public static final String RETURN_VISIBILITY = "returnVisibility";
     65 
     66     private int mLayoutId;
     67     private int mTest;
     68     private ResultReceiver mResultReceiver;
     69     private int mNumSharedElementsArrivedCalled = 0;
     70     private boolean mEntering = true;
     71 
     72     public int resultCode = 0;
     73     public Bundle result = new Bundle();
     74     public final OptionalVisibility exitVisibility = new OptionalVisibility();
     75     public final OptionalVisibility reenterVisibility = new OptionalVisibility();
     76 
     77     public boolean mPauseOnRestart;
     78     public boolean mQuickFinish;
     79     public boolean mAllowOverlap;
     80     public boolean mNoReturnTransition;
     81 
     82     public CountDownLatch returnLatch = new CountDownLatch(1);
     83     public CountDownLatch reenterLatch = new CountDownLatch(1);
     84 
     85     @Override
     86     public void onCreate(Bundle icicle) {
     87         super.onCreate(icicle);
     88         mLayoutId = 0;
     89         if (icicle != null) {
     90             mLayoutId =  icicle.getInt(LAYOUT_ID);
     91             mTest = icicle.getInt(TEST);
     92             mResultReceiver = icicle.getParcelable(RESULT_RECEIVER);
     93             mPauseOnRestart = icicle.getBoolean(PAUSE_ON_RESTART);
     94             mQuickFinish = icicle.getBoolean(QUICK_FINISH);
     95             mAllowOverlap = icicle.getBoolean(ALLOW_OVERLAP, true);
     96             mNoReturnTransition = icicle.getBoolean(NO_RETURN_TRANSITION);
     97         }
     98 
     99         if (mLayoutId == 0) {
    100             Intent intent = getIntent();
    101             mLayoutId = intent.getIntExtra(LAYOUT_ID, R.layout.start);
    102             mTest = intent.getIntExtra(TEST, 0);
    103             mResultReceiver = intent.getParcelableExtra(RESULT_RECEIVER);
    104             mPauseOnRestart = intent.getBooleanExtra(PAUSE_ON_RESTART, false);
    105             mQuickFinish = intent.getBooleanExtra(QUICK_FINISH, false);
    106             mAllowOverlap = intent.getBooleanExtra(ALLOW_OVERLAP, true);
    107             mNoReturnTransition = intent.getBooleanExtra(NO_RETURN_TRANSITION, false);
    108         }
    109 
    110         getWindow().setSharedElementEnterTransition(new ChangeBounds().setDuration(DURATION));
    111         getWindow().setSharedElementReturnTransition(new ChangeBounds().setDuration(DURATION));
    112         getWindow().setEnterTransition(createVisibilityTransition(true, ENTER_VISIBILITY));
    113         getWindow().setReturnTransition(createVisibilityTransition(true, RETURN_VISIBILITY));
    114         getWindow().setExitTransition(createVisibilityTransition(false, exitVisibility));
    115         getWindow().setReenterTransition(createVisibilityTransition(false, reenterVisibility));
    116         getWindow().getReenterTransition().addListener(new TransitionListenerAdapter() {
    117             @Override
    118             public void onTransitionEnd(Transition transition) {
    119                 reenterLatch.countDown();
    120             }
    121         });
    122 
    123         setContentView(mLayoutId);
    124         getWindow().setAllowReturnTransitionOverlap(mAllowOverlap);
    125         if (mNoReturnTransition) {
    126             getWindow().setReturnTransition(null);
    127             getWindow().setSharedElementReturnTransition(null);
    128         }
    129 
    130         startTest();
    131     }
    132 
    133     private Transition createVisibilityTransition(boolean isExplode, OptionalVisibility visibility) {
    134         final Transition transition = isExplode ? new Explode() : new Fade();
    135         transition.setDuration(DURATION);
    136         transition.addListener(new VisibilityCheck(R.id.redSquare, visibility));
    137         return transition;
    138     }
    139 
    140     private Transition createVisibilityTransition(boolean isExplode, String propertyName) {
    141         final Transition transition = isExplode ? new Explode() : new Fade();
    142         transition.setDuration(DURATION);
    143         transition.addListener(new VisibilityCheck(R.id.redSquare, propertyName));
    144         return transition;
    145     }
    146 
    147     @Override
    148     protected void onSaveInstanceState(Bundle outState) {
    149         outState.putInt(LAYOUT_ID, mLayoutId);
    150         outState.putInt(TEST, mTest);
    151         outState.putParcelable(RESULT_RECEIVER, mResultReceiver);
    152         outState.putBoolean(PAUSE_ON_RESTART, mPauseOnRestart);
    153     }
    154 
    155     private void startTest() {
    156         if (mTest == TEST_ARRIVE) {
    157             setEnterSharedElementCallback(new SharedElementCallback() {
    158                 @Override
    159                 public void onSharedElementsArrived(List<String> sharedElementNames,
    160                         final List<View> sharedElements,
    161                         final OnSharedElementsReadyListener listener) {
    162                     mNumSharedElementsArrivedCalled++;
    163                     result.putInt(ARRIVE_COUNT, mNumSharedElementsArrivedCalled);
    164                     if (mEntering) {
    165                         result.putInt(ARRIVE_ENTER_START_VISIBILITY, sharedElements.get(0).getVisibility());
    166                         result.putLong(ARRIVE_ENTER_TIME, SystemClock.uptimeMillis());
    167                     } else {
    168                         result.putLong(ARRIVE_RETURN_TIME, SystemClock.uptimeMillis());
    169                     }
    170 
    171                     getWindow().getDecorView().postDelayed(new Runnable() {
    172                         @Override
    173                         public void run() {
    174                             if (mEntering) {
    175                                 result.putInt(ARRIVE_ENTER_DELAY_VISIBILITY,
    176                                         sharedElements.get(0).getVisibility());
    177                                 result.putLong(ARRIVE_ENTER_TIME_READY, SystemClock.uptimeMillis());
    178                             } else {
    179                                 result.putLong(ARRIVE_RETURN_TIME_READY,
    180                                         SystemClock.uptimeMillis());
    181                                 mResultReceiver.send(RESULT_OK, result);
    182                             }
    183                             listener.onSharedElementsReady();
    184                         }
    185                     }, SHARED_ELEMENT_READY_DELAY);
    186                 }
    187             });
    188         }
    189         getWindow().getEnterTransition().addListener(new TransitionListener() {
    190             @Override
    191             public void onTransitionStart(Transition transition) {
    192             }
    193 
    194             @Override
    195             public void onTransitionEnd(Transition transition) {
    196                 mEntering = false;
    197                 Intent intent = new Intent();
    198                 intent.putExtra("Extra", new ExtraData("result"));
    199                 setResult(RESULT_OK, intent);
    200                 getWindow().getDecorView().post(new Runnable() {
    201                     @Override
    202                     public void run() {
    203                         finishAfterTransition();
    204                         if (mQuickFinish) {
    205                             finish();
    206                         }
    207                     }
    208                 });
    209             }
    210 
    211             @Override
    212             public void onTransitionCancel(Transition transition) {
    213             }
    214 
    215             @Override
    216             public void onTransitionPause(Transition transition) {
    217             }
    218 
    219             @Override
    220             public void onTransitionResume(Transition transition) {
    221             }
    222         });
    223     }
    224 
    225     @Override
    226     public void onActivityReenter(int resultCode, Intent data) {
    227         if (resultCode == RESULT_OK) {
    228             ExtraData extraData = data.getParcelableExtra("Extra");
    229             if (!"result".equals(extraData.data)) {
    230                 throw new RuntimeException("Incorrect returned intent data in onActivityReenter");
    231             }
    232         }
    233         super.onActivityReenter(resultCode, data);
    234     }
    235 
    236     @Override
    237     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    238         super.onActivityResult(requestCode, resultCode, data);
    239         this.resultCode = resultCode;
    240         returnLatch.countDown();
    241     }
    242 
    243     @Override
    244     protected void onRestart() {
    245         super.onRestart();
    246         if (mPauseOnRestart) {
    247             postponeEnterTransition();
    248             getWindow().getDecorView().postDelayed(new Runnable() {
    249                 @Override
    250                 public void run() {
    251                     startPostponedEnterTransition();
    252                 }
    253             }, 500);
    254         }
    255     }
    256 
    257     private class VisibilityCheck extends TransitionListenerAdapter {
    258         private final int mViewId;
    259         private final OptionalVisibility mVisibility;
    260         private final String mPropertyName;
    261 
    262         public VisibilityCheck(int viewId, OptionalVisibility visibility) {
    263             mViewId = viewId;
    264             mVisibility = visibility;
    265             mPropertyName = null;
    266         }
    267 
    268         public VisibilityCheck(int viewId, String propertyName) {
    269             mViewId = viewId;
    270             mVisibility = null;
    271             mPropertyName = propertyName;
    272         }
    273 
    274         @Override
    275         public void onTransitionEnd(Transition transition) {
    276             final View view = findViewById(mViewId);
    277             if (mPropertyName != null) {
    278                 if (mResultReceiver != null) {
    279                     Bundle data = new Bundle();
    280                     data.putInt(mPropertyName, view.getVisibility());
    281                     mResultReceiver.send(RESULT_OK, data);
    282                 }
    283             } else {
    284                 mVisibility.set(view.getVisibility());
    285             }
    286         }
    287     }
    288 
    289     public static class OptionalVisibility {
    290         private int mVisibility = -1;
    291 
    292         public void set(int visibility) {
    293             mVisibility = visibility;
    294         }
    295 
    296         public int get() {
    297             return mVisibility;
    298         }
    299 
    300         public boolean isSet() {
    301             return mVisibility != -1;
    302         }
    303     }
    304 
    305     /**
    306      * Used to test the class loader of the returned intent.
    307      */
    308     public static class ExtraData implements Parcelable {
    309         public final String data;
    310 
    311         public ExtraData(String data) {
    312             this.data = data;
    313         }
    314 
    315         protected ExtraData(Parcel in) {
    316             this.data = in.readString();
    317         }
    318 
    319         public static final Creator<ExtraData> CREATOR = new Creator<ExtraData>() {
    320             @Override
    321             public ExtraData createFromParcel(Parcel in) {
    322                 return new ExtraData(in);
    323             }
    324 
    325             @Override
    326             public ExtraData[] newArray(int size) {
    327                 return new ExtraData[size];
    328             }
    329         };
    330 
    331         @Override
    332         public int describeContents() {
    333             return 0;
    334         }
    335 
    336         @Override
    337         public void writeToParcel(Parcel dest, int flags) {
    338             dest.writeString(data);
    339         }
    340     }
    341 }
    342