1/*
2 * Copyright (C) 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
17package com.android.providers.tv;
18
19import android.content.Context;
20import android.content.SharedPreferences;
21import android.database.sqlite.SQLiteDatabase;
22import android.media.tv.TvContract.Channels;
23import android.media.tv.TvContract.PreviewPrograms;
24import android.media.tv.TvContract.WatchNextPrograms;
25import android.preference.PreferenceManager;
26import android.provider.Settings;
27
28import com.android.internal.annotations.VisibleForTesting;
29import com.android.providers.tv.TvProvider.DatabaseHelper;
30
31/**
32 * Convenient class for deleting transient rows. This ensures that the clean up job is done only
33 * once after boot.
34 */
35public class TransientRowHelper {
36    private static final String PREF_KEY_LAST_DELETION_BOOT_COUNT =
37            "pref_key_last_deletion_boot_count";
38    private static TransientRowHelper sInstance;
39
40    private Context mContext;
41    private DatabaseHelper mDatabaseHelper;
42    @VisibleForTesting
43    protected boolean mTransientRowsDeleted;
44
45    /**
46     * Returns the singleton TransientRowHelper instance.
47     *
48     * @param context The application context.
49     */
50    public static TransientRowHelper getInstance(Context context) {
51        synchronized (TransientRowHelper.class) {
52            if (sInstance == null) {
53                sInstance = new TransientRowHelper(context);
54            }
55        }
56        return sInstance;
57    }
58
59    @VisibleForTesting
60    TransientRowHelper(Context context) {
61        mContext = context;
62        mDatabaseHelper = DatabaseHelper.getInstance(context);
63    }
64
65    /**
66     * Ensures that transient rows, inserted previously before current boot, are deleted.
67     */
68    public synchronized void ensureOldTransientRowsDeleted() {
69        if (mTransientRowsDeleted) {
70            return;
71        }
72        mTransientRowsDeleted = true;
73        if (getLastDeletionBootCount() >= getBootCount()) {
74            // This can be the second execution of TvProvider after boot since system kills
75            // TvProvider in low memory conditions. If this is the case, we shouldn't delete
76            // transient rows.
77            return;
78        }
79        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
80        // Delete all the transient programs and channels.
81        db.delete(TvProvider.PREVIEW_PROGRAMS_TABLE, PreviewPrograms.COLUMN_TRANSIENT + "=1", null);
82        db.delete(TvProvider.CHANNELS_TABLE, Channels.COLUMN_TRANSIENT + "=1", null);
83        db.delete(TvProvider.WATCH_NEXT_PROGRAMS_TABLE, WatchNextPrograms.COLUMN_TRANSIENT + "=1",
84                null);
85        setLastDeletionBootCount();
86    }
87
88    @VisibleForTesting
89    protected int getBootCount() {
90        return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT,
91                -1);
92    }
93
94    @VisibleForTesting
95    protected int getLastDeletionBootCount() {
96        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
97        return prefs.getInt(PREF_KEY_LAST_DELETION_BOOT_COUNT, -1);
98    }
99
100    @VisibleForTesting
101    protected void setLastDeletionBootCount() {
102        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(mContext)
103                .edit();
104        editor.putInt(PREF_KEY_LAST_DELETION_BOOT_COUNT, getBootCount());
105        editor.apply();
106    }
107}
108