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
17package com.android.launcher3.compat;
18
19import android.content.Context;
20import android.content.SharedPreferences;
21import android.text.TextUtils;
22import android.util.Log;
23
24import com.android.launcher3.LauncherAppState;
25
26import org.json.JSONException;
27import org.json.JSONObject;
28import org.json.JSONStringer;
29import org.json.JSONTokener;
30
31import java.util.ArrayList;
32import java.util.HashSet;
33
34public class PackageInstallerCompatV16 extends PackageInstallerCompat {
35
36    private static final String TAG = "PackageInstallerCompatV16";
37    private static final boolean DEBUG = false;
38
39    private static final String KEY_PROGRESS = "progress";
40    private static final String KEY_STATE = "state";
41
42    private static final String PREFS =
43            "com.android.launcher3.compat.PackageInstallerCompatV16.queue";
44
45    protected final SharedPreferences mPrefs;
46
47    boolean mUseQueue;
48    boolean mFinishedBind;
49    boolean mReplayPending;
50
51    PackageInstallerCompatV16(Context context) {
52        mPrefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
53    }
54
55    @Override
56    public void onPause() {
57        mUseQueue = true;
58        if (DEBUG) Log.d(TAG, "updates paused");
59    }
60
61    @Override
62    public void onResume() {
63        mUseQueue = false;
64        if (mFinishedBind) {
65            replayUpdates();
66        }
67    }
68
69    @Override
70    public void onFinishBind() {
71        mFinishedBind = true;
72        if (!mUseQueue) {
73            replayUpdates();
74        }
75    }
76
77    @Override
78    public void onStop() { }
79
80    private void replayUpdates() {
81        if (DEBUG) Log.d(TAG, "updates resumed");
82        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
83        if (app == null) {
84            mReplayPending = true; // try again later
85            if (DEBUG) Log.d(TAG, "app is null, delaying send");
86            return;
87        }
88        mReplayPending = false;
89        ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>();
90        for (String packageName: mPrefs.getAll().keySet()) {
91            final String json = mPrefs.getString(packageName, null);
92            if (!TextUtils.isEmpty(json)) {
93                updates.add(infoFromJson(packageName, json));
94            }
95        }
96        if (!updates.isEmpty()) {
97            sendUpdate(app, updates);
98        }
99    }
100
101    /**
102     * This should be called by the implementations to register a package update.
103     */
104    @Override
105    public synchronized void recordPackageUpdate(String packageName, int state, int progress) {
106        SharedPreferences.Editor editor = mPrefs.edit();
107        PackageInstallInfo installInfo = new PackageInstallInfo(packageName);
108        installInfo.progress = progress;
109        installInfo.state = state;
110        if (state == STATUS_INSTALLED) {
111            // no longer necessary to track this package
112            editor.remove(packageName);
113            if (DEBUG) Log.d(TAG, "no longer tracking " + packageName);
114        } else {
115            editor.putString(packageName, infoToJson(installInfo));
116            if (DEBUG)
117                Log.d(TAG, "saved state: " + infoToJson(installInfo)
118                        + " for package: " + packageName);
119
120        }
121        editor.commit();
122
123        if (!mUseQueue) {
124            if (mReplayPending) {
125                replayUpdates();
126            } else if (state != STATUS_INSTALLED) {
127                LauncherAppState app = LauncherAppState.getInstanceNoCreate();
128                ArrayList<PackageInstallInfo> update = new ArrayList<PackageInstallInfo>();
129                update.add(installInfo);
130                sendUpdate(app, update);
131            }
132        }
133    }
134
135    private void sendUpdate(LauncherAppState app, ArrayList<PackageInstallInfo> updates) {
136        if (app == null) {
137            mReplayPending = true; // try again later
138            if (DEBUG) Log.d(TAG, "app is null, delaying send");
139        } else {
140            app.setPackageState(updates);
141        }
142    }
143
144    private static PackageInstallInfo infoFromJson(String packageName, String json) {
145        PackageInstallInfo info = new PackageInstallInfo(packageName);
146        try {
147            JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
148            info.state = object.getInt(KEY_STATE);
149            info.progress = object.getInt(KEY_PROGRESS);
150        } catch (JSONException e) {
151            Log.e(TAG, "failed to deserialize app state update", e);
152        }
153        return info;
154    }
155
156    private static String infoToJson(PackageInstallInfo info) {
157        String value = null;
158        try {
159            JSONStringer json = new JSONStringer()
160                    .object()
161                    .key(KEY_STATE).value(info.state)
162                    .key(KEY_PROGRESS).value(info.progress)
163                    .endObject();
164            value = json.toString();
165        } catch (JSONException e) {
166            Log.e(TAG, "failed to serialize app state update", e);
167        }
168        return value;
169    }
170
171    @Override
172    public HashSet<String> updateAndGetActiveSessionCache() {
173        return new HashSet<String>();
174    }
175}
176