1 /*
2  * Copyright 2017 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.servertransaction;
18 
19 import static android.app.ActivityThread.DEBUG_ORDER;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.app.ActivityThread.ActivityClientRecord;
24 import android.app.ClientTransactionHandler;
25 import android.app.ResultInfo;
26 import android.content.res.CompatibilityInfo;
27 import android.os.IBinder;
28 import android.os.Parcel;
29 import android.os.Trace;
30 import android.util.MergedConfiguration;
31 import android.util.Slog;
32 
33 import com.android.internal.content.ReferrerIntent;
34 
35 import java.util.List;
36 import java.util.Objects;
37 
38 /**
39  * Activity relaunch callback.
40  * @hide
41  */
42 public class ActivityRelaunchItem extends ActivityTransactionItem {
43 
44     private static final String TAG = "ActivityRelaunchItem";
45 
46     private List<ResultInfo> mPendingResults;
47     private List<ReferrerIntent> mPendingNewIntents;
48     private int mConfigChanges;
49     private MergedConfiguration mConfig;
50     private boolean mPreserveWindow;
51 
52     /**
53      * A record that was properly configured for relaunch. Execution will be cancelled if not
54      * initialized after {@link #preExecute(ClientTransactionHandler, IBinder)}.
55      */
56     private ActivityClientRecord mActivityClientRecord;
57 
58     @Override
preExecute(ClientTransactionHandler client, IBinder token)59     public void preExecute(ClientTransactionHandler client, IBinder token) {
60         // The local config is already scaled so only apply if this item is from server side.
61         if (!client.isExecutingLocalTransaction()) {
62             CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig);
63         }
64         mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults,
65                 mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
66     }
67 
68     @Override
execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions)69     public void execute(ClientTransactionHandler client, ActivityClientRecord r,
70             PendingTransactionActions pendingActions) {
71         if (mActivityClientRecord == null) {
72             if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled");
73             return;
74         }
75         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
76         client.handleRelaunchActivity(mActivityClientRecord, pendingActions);
77         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
78     }
79 
80     @Override
postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions)81     public void postExecute(ClientTransactionHandler client, IBinder token,
82             PendingTransactionActions pendingActions) {
83         final ActivityClientRecord r = getActivityClientRecord(client, token);
84         client.reportRelaunch(r);
85     }
86 
87     // ObjectPoolItem implementation
88 
ActivityRelaunchItem()89     private ActivityRelaunchItem() {}
90 
91     /** Obtain an instance initialized with provided params. */
obtain(List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config, boolean preserveWindow)92     public static ActivityRelaunchItem obtain(List<ResultInfo> pendingResults,
93             List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config,
94             boolean preserveWindow) {
95         ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class);
96         if (instance == null) {
97             instance = new ActivityRelaunchItem();
98         }
99         instance.mPendingResults = pendingResults;
100         instance.mPendingNewIntents = pendingNewIntents;
101         instance.mConfigChanges = configChanges;
102         instance.mConfig = config;
103         instance.mPreserveWindow = preserveWindow;
104 
105         return instance;
106     }
107 
108     @Override
recycle()109     public void recycle() {
110         mPendingResults = null;
111         mPendingNewIntents = null;
112         mConfigChanges = 0;
113         mConfig = null;
114         mPreserveWindow = false;
115         mActivityClientRecord = null;
116         ObjectPool.recycle(this);
117     }
118 
119 
120     // Parcelable implementation
121 
122     /** Write to Parcel. */
123     @Override
writeToParcel(Parcel dest, int flags)124     public void writeToParcel(Parcel dest, int flags) {
125         dest.writeTypedList(mPendingResults, flags);
126         dest.writeTypedList(mPendingNewIntents, flags);
127         dest.writeInt(mConfigChanges);
128         dest.writeTypedObject(mConfig, flags);
129         dest.writeBoolean(mPreserveWindow);
130     }
131 
132     /** Read from Parcel. */
ActivityRelaunchItem(Parcel in)133     private ActivityRelaunchItem(Parcel in) {
134         mPendingResults = in.createTypedArrayList(ResultInfo.CREATOR);
135         mPendingNewIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
136         mConfigChanges = in.readInt();
137         mConfig = in.readTypedObject(MergedConfiguration.CREATOR);
138         mPreserveWindow = in.readBoolean();
139     }
140 
141     public static final @NonNull Creator<ActivityRelaunchItem> CREATOR =
142             new Creator<ActivityRelaunchItem>() {
143         public ActivityRelaunchItem createFromParcel(Parcel in) {
144             return new ActivityRelaunchItem(in);
145         }
146 
147         public ActivityRelaunchItem[] newArray(int size) {
148             return new ActivityRelaunchItem[size];
149         }
150     };
151 
152     @Override
equals(@ullable Object o)153     public boolean equals(@Nullable Object o) {
154         if (this == o) {
155             return true;
156         }
157         if (o == null || getClass() != o.getClass()) {
158             return false;
159         }
160         final ActivityRelaunchItem other = (ActivityRelaunchItem) o;
161         return Objects.equals(mPendingResults, other.mPendingResults)
162                 && Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
163                 && mConfigChanges == other.mConfigChanges && Objects.equals(mConfig, other.mConfig)
164                 && mPreserveWindow == other.mPreserveWindow;
165     }
166 
167     @Override
hashCode()168     public int hashCode() {
169         int result = 17;
170         result = 31 * result + Objects.hashCode(mPendingResults);
171         result = 31 * result + Objects.hashCode(mPendingNewIntents);
172         result = 31 * result + mConfigChanges;
173         result = 31 * result + Objects.hashCode(mConfig);
174         result = 31 * result + (mPreserveWindow ? 1 : 0);
175         return result;
176     }
177 
178     @Override
toString()179     public String toString() {
180         return "ActivityRelaunchItem{pendingResults=" + mPendingResults
181                 + ",pendingNewIntents=" + mPendingNewIntents + ",configChanges="  + mConfigChanges
182                 + ",config=" + mConfig + ",preserveWindow" + mPreserveWindow + "}";
183     }
184 }
185