ActivityState.java revision 11f14dc9e1d4d04b7c21b076445f3cb8c173753b
1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.app;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.app.ActionBar;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.app.Activity;
218e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandlerimport android.content.BroadcastReceiver;
2211f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescuimport android.content.ContentResolver;
238e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandlerimport android.content.Context;
248e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandlerimport android.content.Intent;
258e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandlerimport android.content.IntentFilter;
268e565703e8d482421714383a8ad40a67929ce2daOwen Linimport android.content.res.Configuration;
278e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandlerimport android.os.BatteryManager;
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Bundle;
2911f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescuimport android.provider.Settings;
3011f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescuimport android.provider.Settings.SettingNotFoundException;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.Menu;
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MenuItem;
338e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandlerimport android.view.Window;
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.WindowManager;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
36a9bd72c2efc7f7c26c60083d8f00380e60caf94eRay Chenimport com.android.gallery3d.ui.GLView;
37a9bd72c2efc7f7c26c60083d8f00380e60caf94eRay Chen
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linabstract public class ActivityState {
39d83f5f227315cccfe3c23db90c93b5fd7be20597Yuli Huang    protected static final int FLAG_HIDE_ACTION_BAR = 1;
40d83f5f227315cccfe3c23db90c93b5fd7be20597Yuli Huang    protected static final int FLAG_HIDE_STATUS_BAR = 2;
41afb3d1d8f341620f6b69d47d52b515f53817aa91Yuli Huang    protected static final int FLAG_SCREEN_ON_WHEN_PLUGGED = 4;
42afb3d1d8f341620f6b69d47d52b515f53817aa91Yuli Huang    protected static final int FLAG_SCREEN_ON_ALWAYS = 8;
438e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler
448e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler    private static final int SCREEN_ON_FLAGS = (
458e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler              WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
468e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
478e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
488e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler        );
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected GalleryActivity mActivity;
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected Bundle mData;
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected int mFlags;
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected ResultEntry mReceivedResults;
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected ResultEntry mResult;
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected static class ResultEntry {
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public int requestCode;
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public int resultCode = Activity.RESULT_CANCELED;
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public Intent resultData;
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
6311f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu    protected boolean mHapticsEnabled;
6411f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu    private ContentResolver mContentResolver;
6511f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu
6657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan    private boolean mDestroyed = false;
678e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler    private boolean mPlugged = false;
68616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    boolean mIsFinishing = false;
6957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected ActivityState() {
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void setContentPane(GLView content) {
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActivity.getGLRoot().setContentPane(content);
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    void initialize(GalleryActivity activity, Bundle data) {
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActivity = activity;
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mData = data;
8011f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu        mContentResolver = activity.getAndroidContext().getContentResolver();
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public Bundle getData() {
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mData;
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onBackPressed() {
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActivity.getStateManager().finishState(this);
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void setStateResult(int resultCode, Intent data) {
92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mResult == null) return;
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mResult.resultCode = resultCode;
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mResult.resultData = data;
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
978e565703e8d482421714383a8ad40a67929ce2daOwen Lin    protected void onConfigurationChanged(Configuration config) {
988e565703e8d482421714383a8ad40a67929ce2daOwen Lin    }
998e565703e8d482421714383a8ad40a67929ce2daOwen Lin
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onSaveState(Bundle outState) {
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onStateResult(int requestCode, int resultCode, Intent data) {
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onCreate(Bundle data, Bundle storedState) {
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1098e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler    BroadcastReceiver mPowerIntentReceiver = new BroadcastReceiver() {
1108e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler        @Override
1118e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler        public void onReceive(Context context, Intent intent) {
1128e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            final String action = intent.getAction();
1138e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
1148e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler                boolean plugged = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
1158e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler
1168e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler                if (plugged != mPlugged) {
1178e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler                    mPlugged = plugged;
1180b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang                    setScreenOnFlags();
1198e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler                }
1208e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            }
1218e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler        }
1228e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler    };
1238e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler
1240b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang    void setScreenOnFlags() {
1250b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang        final Window win = ((Activity) mActivity).getWindow();
1260b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang        final WindowManager.LayoutParams params = win.getAttributes();
127afb3d1d8f341620f6b69d47d52b515f53817aa91Yuli Huang        if ((0 != (mFlags & FLAG_SCREEN_ON_ALWAYS)) ||
128afb3d1d8f341620f6b69d47d52b515f53817aa91Yuli Huang                (mPlugged && 0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED))) {
1298e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            params.flags |= SCREEN_ON_FLAGS;
1308e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler        } else {
1318e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            params.flags &= ~SCREEN_ON_FLAGS;
1328e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler        }
1330b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang        win.setAttributes(params);
1348e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler    }
1358e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onPause() {
137afb3d1d8f341620f6b69d47d52b515f53817aa91Yuli Huang        if (0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED)) {
138002a3fece284f713537fad4523ee963d257350e9Chih-Chung Chang            ((Activity) mActivity).unregisterReceiver(mPowerIntentReceiver);
139002a3fece284f713537fad4523ee963d257350e9Chih-Chung Chang        }
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // should only be called by StateManager
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    void resume() {
144b1eb01cd02d1e75e6b9c3e593f6ff34335e2ca8aOwen Lin        AbstractGalleryActivity activity = (AbstractGalleryActivity) mActivity;
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ActionBar actionBar = activity.getActionBar();
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (actionBar != null) {
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if ((mFlags & FLAG_HIDE_ACTION_BAR) != 0) {
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                actionBar.hide();
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                actionBar.show();
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int stateCount = mActivity.getStateManager().getStateCount();
153655f63f04638dfe31045eab1b6b4c39cc2db10dbRay Chen            mActivity.getGalleryActionBar().setDisplayOptions(stateCount > 1, true);
154fe1625c46f8258be4cd5e5e1ba69b584c1fe1a49Ray Chen            // Default behavior, this can be overridden in ActivityState's onResume.
155fe1625c46f8258be4cd5e5e1ba69b584c1fe1a49Ray Chen            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        activity.invalidateOptionsMenu();
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1600b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang        setScreenOnFlags();
1618e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler
1620b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang        boolean lightsOut = ((mFlags & FLAG_HIDE_STATUS_BAR) != 0);
1630b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang        mActivity.getGLRoot().setLightsOutMode(lightsOut);
1648e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ResultEntry entry = mReceivedResults;
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (entry != null) {
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mReceivedResults = null;
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            onStateResult(entry.requestCode, entry.resultCode, entry.resultData);
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
1708e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler
171afb3d1d8f341620f6b69d47d52b515f53817aa91Yuli Huang        if (0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED)) {
1728e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            // we need to know whether the device is plugged in to do this correctly
1738e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            final IntentFilter filter = new IntentFilter();
1748e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
1758e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler            activity.registerReceiver(mPowerIntentReceiver, filter);
1768e6fd7cee5467824cd96b4127ccc755c70bd4ea3Daniel Sandler        }
17711f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu
17811f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu        try {
17911f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu            mHapticsEnabled = Settings.System.getInt(mContentResolver,
18011f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu                    Settings.System.HAPTIC_FEEDBACK_ENABLED) != 0;
18111f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu        } catch (SettingNotFoundException e) {
18211f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu            mHapticsEnabled = false;
18311f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu        }
18411f14dc9e1d4d04b7c21b076445f3cb8c173753bBobby Georgescu
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        onResume();
186616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
187616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        // the transition store should be cleared after resume;
188616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        mActivity.getTransitionStore().clear();
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // a subclass of ActivityState should override the method to resume itself
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onResume() {
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected boolean onCreateActionBar(Menu menu) {
1966cf807453fb58ccd4cc513ff187b306c7090e67cOwen Lin        // TODO: we should return false if there is no menu to show
1976cf807453fb58ccd4cc513ff187b306c7090e67cOwen Lin        //       this is a workaround for a bug in system
1986cf807453fb58ccd4cc513ff187b306c7090e67cOwen Lin        return true;
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected boolean onItemSelected(MenuItem item) {
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return false;
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onDestroy() {
20657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan        mDestroyed = true;
20757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan    }
20857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan
20957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan    boolean isDestroyed() {
21057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan        return mDestroyed;
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
212616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin
213616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    public boolean isFinishing() {
214616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin        return mIsFinishing;
215616a70fdb4473d2fbd7b70772a3a82b908aeae1eOwen Lin    }
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
217