1446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian/*
2446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * Copyright 2017 The Android Open Source Project
3446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian *
4446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * Licensed under the Apache License, Version 2.0 (the "License");
5446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * you may not use this file except in compliance with the License.
6446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * You may obtain a copy of the License at
7446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian *
8446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian *      http://www.apache.org/licenses/LICENSE-2.0
9446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian *
10446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * Unless required by applicable law or agreed to in writing, software
11446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * distributed under the License is distributed on an "AS IS" BASIS,
12446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * See the License for the specific language governing permissions and
14446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * limitations under the License.
15446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian */
16446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
17446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulianpackage android.app.servertransaction;
18446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
1988e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulianimport android.annotation.Nullable;
206b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulianimport android.app.ClientTransactionHandler;
21446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulianimport android.app.IApplicationThread;
22446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulianimport android.os.IBinder;
23446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulianimport android.os.Parcel;
24446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulianimport android.os.Parcelable;
25446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulianimport android.os.RemoteException;
26446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
270bd8d42c0a2e28d99d4ed29a93fa2443b7b1bbccBryce Leeimport com.android.internal.annotations.VisibleForTesting;
280bd8d42c0a2e28d99d4ed29a93fa2443b7b1bbccBryce Lee
29446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulianimport java.util.ArrayList;
30446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulianimport java.util.List;
316b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulianimport java.util.Objects;
32446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
33446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian/**
34446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * A container that holds a sequence of messages, which may be sent to a client.
35446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * This includes a list of callbacks and a final lifecycle state.
36446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian *
37446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * @see com.android.server.am.ClientLifecycleManager
38446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * @see ClientTransactionItem
39446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * @see ActivityLifecycleItem
40446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian * @hide
41446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian */
429c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulianpublic class ClientTransaction implements Parcelable, ObjectPoolItem {
43446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
44446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /** A list of individual callbacks to a client. */
45446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    private List<ClientTransactionItem> mActivityCallbacks;
46446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
47446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /**
48446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * Final lifecycle state in which the client activity should be after the transaction is
49446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * executed.
50446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     */
51446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    private ActivityLifecycleItem mLifecycleStateRequest;
52446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
53446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /** Target client. */
54446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    private IApplicationThread mClient;
55446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
56446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /** Target client activity. Might be null if the entire transaction is targeting an app. */
57446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    private IBinder mActivityToken;
58446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
590447068f27f4d8c44052026878740cbcd7d598faAndrii Kulian    /** Get the target client of the transaction. */
600447068f27f4d8c44052026878740cbcd7d598faAndrii Kulian    public IApplicationThread getClient() {
610447068f27f4d8c44052026878740cbcd7d598faAndrii Kulian        return mClient;
620447068f27f4d8c44052026878740cbcd7d598faAndrii Kulian    }
630447068f27f4d8c44052026878740cbcd7d598faAndrii Kulian
64446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /**
65446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * Add a message to the end of the sequence of callbacks.
66446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * @param activityCallback A single message that can contain a lifecycle request/callback.
67446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     */
68446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    public void addCallback(ClientTransactionItem activityCallback) {
69446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        if (mActivityCallbacks == null) {
70446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            mActivityCallbacks = new ArrayList<>();
71446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
72446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        mActivityCallbacks.add(activityCallback);
73446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    }
74446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
7588e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    /** Get the list of callbacks. */
7688e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    @Nullable
7788e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    List<ClientTransactionItem> getCallbacks() {
7888e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian        return mActivityCallbacks;
7988e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    }
8088e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian
8188e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    /** Get the target activity. */
8288e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    @Nullable
8388e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    public IBinder getActivityToken() {
8488e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian        return mActivityToken;
8588e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    }
8688e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian
8788e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    /** Get the target state lifecycle request. */
880bd8d42c0a2e28d99d4ed29a93fa2443b7b1bbccBryce Lee    @VisibleForTesting
890bd8d42c0a2e28d99d4ed29a93fa2443b7b1bbccBryce Lee    public ActivityLifecycleItem getLifecycleStateRequest() {
9088e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian        return mLifecycleStateRequest;
9188e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    }
9288e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian
93446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /**
94446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * Set the lifecycle state in which the client should be after executing the transaction.
95446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * @param stateRequest A lifecycle request initialized with right parameters.
96446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     */
97446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    public void setLifecycleStateRequest(ActivityLifecycleItem stateRequest) {
98446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        mLifecycleStateRequest = stateRequest;
99446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    }
100446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
101446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /**
102446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * Do what needs to be done while the transaction is being scheduled on the client side.
103446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * @param clientTransactionHandler Handler on the client side that will executed all operations
104446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     *                                 requested by transaction items.
105446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     */
10688e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian    public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) {
107446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        if (mActivityCallbacks != null) {
108446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            final int size = mActivityCallbacks.size();
109446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            for (int i = 0; i < size; ++i) {
11088e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian                mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken);
111446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            }
112446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
113446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        if (mLifecycleStateRequest != null) {
11488e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian            mLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken);
115446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
116446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    }
117446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
118446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /**
119446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * Schedule the transaction after it was initialized. It will be send to client and all its
120446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * individual parts will be applied in the following sequence:
12188e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian     * 1. The client calls {@link #preExecute(ClientTransactionHandler)}, which triggers all work
12288e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian     *    that needs to be done before actually scheduling the transaction for callbacks and
12388e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian     *    lifecycle state request.
124446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     * 2. The transaction message is scheduled.
12588e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian     * 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes
12688e05cb84427c23bb2e23626968f2e8431b6f273Andrii Kulian     *    all callbacks and necessary lifecycle transitions.
127446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian     */
128446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    public void schedule() throws RemoteException {
129446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        mClient.scheduleTransaction(this);
130446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    }
131446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
132446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
1339c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian    // ObjectPoolItem implementation
1349c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian
1359c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian    private ClientTransaction() {}
1369c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian
1379c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian    /** Obtain an instance initialized with provided params. */
1389c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian    public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
1399c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
1409c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        if (instance == null) {
1419c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian            instance = new ClientTransaction();
1429c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        }
1439c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        instance.mClient = client;
1449c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        instance.mActivityToken = activityToken;
1459c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian
1469c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        return instance;
1479c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian    }
1489c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian
1499c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian    @Override
1509c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian    public void recycle() {
1519c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        if (mActivityCallbacks != null) {
1529c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian            int size = mActivityCallbacks.size();
1539c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian            for (int i = 0; i < size; i++) {
1549c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian                mActivityCallbacks.get(i).recycle();
1559c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian            }
1569c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian            mActivityCallbacks.clear();
1579c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        }
1589c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        if (mLifecycleStateRequest != null) {
1599c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian            mLifecycleStateRequest.recycle();
1609c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian            mLifecycleStateRequest = null;
1619c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        }
1629c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        mClient = null;
1639c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        mActivityToken = null;
1649c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian        ObjectPool.recycle(this);
1659c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian    }
1669c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian
1679c5ea9c153fcc1f0fd2cfd35a77f26bf2849c48eAndrii Kulian
168446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    // Parcelable implementation
169446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
170446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /** Write to Parcel. */
171446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    @Override
172446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    public void writeToParcel(Parcel dest, int flags) {
173446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        dest.writeStrongBinder(mClient.asBinder());
174446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        final boolean writeActivityToken = mActivityToken != null;
175446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        dest.writeBoolean(writeActivityToken);
176446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        if (writeActivityToken) {
177446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            dest.writeStrongBinder(mActivityToken);
178446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
179446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        dest.writeParcelable(mLifecycleStateRequest, flags);
180446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        final boolean writeActivityCallbacks = mActivityCallbacks != null;
181446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        dest.writeBoolean(writeActivityCallbacks);
182446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        if (writeActivityCallbacks) {
183446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            dest.writeParcelableList(mActivityCallbacks, flags);
184446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
185446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    }
186446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
187446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    /** Read from Parcel. */
188446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    private ClientTransaction(Parcel in) {
189446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        mClient = (IApplicationThread) in.readStrongBinder();
190446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        final boolean readActivityToken = in.readBoolean();
191446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        if (readActivityToken) {
192446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            mActivityToken = in.readStrongBinder();
193446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
194446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        mLifecycleStateRequest = in.readParcelable(getClass().getClassLoader());
195446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        final boolean readActivityCallbacks = in.readBoolean();
196446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        if (readActivityCallbacks) {
197446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            mActivityCallbacks = new ArrayList<>();
198446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            in.readParcelableList(mActivityCallbacks, getClass().getClassLoader());
199446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
200446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    }
201446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
202446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    public static final Creator<ClientTransaction> CREATOR =
203446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            new Creator<ClientTransaction>() {
204446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        public ClientTransaction createFromParcel(Parcel in) {
205446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            return new ClientTransaction(in);
206446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
207446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
208446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        public ClientTransaction[] newArray(int size) {
209446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian            return new ClientTransaction[size];
210446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        }
211446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    };
212446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian
213446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    @Override
214446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    public int describeContents() {
215446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian        return 0;
216446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian    }
2176b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian
2186b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian    @Override
2196b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian    public boolean equals(Object o) {
2206b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        if (this == o) {
2216b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian            return true;
2226b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        }
2236b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        if (o == null || getClass() != o.getClass()) {
2246b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian            return false;
2256b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        }
2266b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        final ClientTransaction other = (ClientTransaction) o;
2276b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        return Objects.equals(mActivityCallbacks, other.mActivityCallbacks)
2286b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian                && Objects.equals(mLifecycleStateRequest, other.mLifecycleStateRequest)
2296b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian                && mClient == other.mClient
2306b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian                && mActivityToken == other.mActivityToken;
2316b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian    }
2326b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian
2336b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian    @Override
2346b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian    public int hashCode() {
2356b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        int result = 17;
2366b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        result = 31 * result + Objects.hashCode(mActivityCallbacks);
2376b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        result = 31 * result + Objects.hashCode(mLifecycleStateRequest);
2386b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian        return result;
2396b9d3a1400fea76f7c6be535b332a27cb21522b3Andrii Kulian    }
240446e824e22692ee217b5b15e4f0de6add6e83d2aAndrii Kulian}
241