Home | History | Annotate | Download | only in tv
      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 
     17 package com.android.providers.tv;
     18 
     19 import com.google.android.collect.Sets;
     20 
     21 import android.content.ContentUris;
     22 import android.content.ContentValues;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.pm.ProviderInfo;
     26 import android.database.Cursor;
     27 import android.media.tv.TvContract;
     28 import android.media.tv.TvContract.Channels;
     29 import android.media.tv.TvContract.PreviewPrograms;
     30 import android.net.Uri;
     31 import android.os.Bundle;
     32 import android.provider.Settings;
     33 import android.test.AndroidTestCase;
     34 import android.test.mock.MockContentProvider;
     35 import android.test.mock.MockContentResolver;
     36 import android.util.Log;
     37 
     38 import java.util.ArrayList;
     39 import java.util.Arrays;
     40 import java.util.Collection;
     41 import java.util.HashSet;
     42 import java.util.Objects;
     43 import java.util.Set;
     44 
     45 public class TransientRowHelperTests extends AndroidTestCase {
     46     private static final String FAKE_INPUT_ID = "TransientRowHelperTests";
     47 
     48     private MockContentResolver mResolver;
     49     private TvProviderForTesting mProvider;
     50     private RebootSimulatingTransientRowHelper mTransientRowHelper;
     51 
     52     @Override
     53     protected void setUp() throws Exception {
     54         super.setUp();
     55 
     56         mResolver = new MockContentResolver();
     57         mResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() {
     58             @Override
     59             public Bundle call(String method, String request, Bundle args) {
     60                 return new Bundle();
     61             }
     62         });
     63 
     64         mProvider = new TvProviderForTesting();
     65         mResolver.addProvider(TvContract.AUTHORITY, mProvider);
     66 
     67         setContext(new MockTvProviderContext(mResolver, getContext()));
     68 
     69         final ProviderInfo info = new ProviderInfo();
     70         info.authority = TvContract.AUTHORITY;
     71         mProvider.attachInfoForTesting(getContext(), info);
     72         mTransientRowHelper = new RebootSimulatingTransientRowHelper(getContext());
     73         mProvider.setTransientRowHelper(mTransientRowHelper);
     74         Utils.clearTvProvider(mResolver);
     75     }
     76 
     77     @Override
     78     protected void tearDown() throws Exception {
     79         Utils.clearTvProvider(mResolver);
     80         mProvider.shutdown();
     81         super.tearDown();
     82     }
     83 
     84     private static class PreviewProgram {
     85         long id;
     86         final boolean isTransient;
     87 
     88         PreviewProgram(boolean isTransient) {
     89             this(-1, isTransient);
     90         }
     91 
     92         PreviewProgram(long id, boolean isTransient) {
     93             this.id = id;
     94             this.isTransient = isTransient;
     95         }
     96 
     97         @Override
     98         public boolean equals(Object obj) {
     99             if (!(obj instanceof PreviewProgram)) {
    100                 return false;
    101             }
    102             PreviewProgram that = (PreviewProgram) obj;
    103             return Objects.equals(id, that.id)
    104                     && Objects.equals(isTransient, that.isTransient);
    105         }
    106 
    107         @Override
    108         public int hashCode() {
    109             return Objects.hash(id, isTransient);
    110         }
    111 
    112         @Override
    113         public String toString() {
    114             return "PreviewProgram(id=" + id + ",isTransient=" + isTransient + ")";
    115         }
    116     }
    117 
    118     private long insertChannel(boolean isTransient) {
    119         ContentValues values = new ContentValues();
    120         values.put(Channels.COLUMN_INPUT_ID, FAKE_INPUT_ID);
    121         values.put(Channels.COLUMN_TRANSIENT, isTransient ? 1 : 0);
    122         Uri uri = mResolver.insert(Channels.CONTENT_URI, values);
    123         assertNotNull(uri);
    124         return ContentUris.parseId(uri);
    125     }
    126 
    127     private void insertPreviewPrograms(long channelId, PreviewProgram... programs) {
    128         insertPreviewPrograms(channelId, Arrays.asList(programs));
    129     }
    130 
    131     private void insertPreviewPrograms(long channelId, Collection<PreviewProgram> programs) {
    132         ContentValues values = new ContentValues();
    133         values.put(PreviewPrograms.COLUMN_CHANNEL_ID, channelId);
    134         for (PreviewProgram program : programs) {
    135             values.put(PreviewPrograms.COLUMN_TYPE, PreviewPrograms.TYPE_MOVIE);
    136             values.put(PreviewPrograms.COLUMN_TRANSIENT, program.isTransient ? 1 : 0);
    137             Uri uri = mResolver.insert(PreviewPrograms.CONTENT_URI, values);
    138             assertNotNull(uri);
    139             program.id = ContentUris.parseId(uri);
    140         }
    141     }
    142 
    143     private Set<PreviewProgram> queryPreviewPrograms() {
    144         String[] projection = new String[] {
    145             PreviewPrograms._ID,
    146             PreviewPrograms.COLUMN_TRANSIENT,
    147         };
    148 
    149         Cursor cursor = mResolver.query(PreviewPrograms.CONTENT_URI, projection, null, null, null);
    150         assertNotNull(cursor);
    151         try {
    152             Set<PreviewProgram> programs = Sets.newHashSet();
    153             while (cursor.moveToNext()) {
    154                 programs.add(new PreviewProgram(cursor.getLong(0), cursor.getInt(1) == 1));
    155             }
    156             return programs;
    157         } finally {
    158             cursor.close();
    159         }
    160     }
    161 
    162     private long getChannelCount() {
    163         String[] projection = new String[] {
    164             Channels._ID,
    165         };
    166 
    167         Cursor cursor = mResolver.query(Channels.CONTENT_URI, projection, null, null, null);
    168         assertNotNull(cursor);
    169         try {
    170             return cursor.getCount();
    171         } finally {
    172             cursor.close();
    173         }
    174     }
    175 
    176     public void testTransientRowsAreDeletedAfterReboot() {
    177         PreviewProgram transientProgramInTransientChannel =
    178                 new PreviewProgram(true /* transient */);
    179         PreviewProgram permanentProgramInTransientChannel =
    180                 new PreviewProgram(false /* transient */);
    181         PreviewProgram transientProgramInPermanentChannel =
    182                 new PreviewProgram(true /* transient */);
    183         PreviewProgram permanentProgramInPermanentChannel =
    184                 new PreviewProgram(false /* transient */);
    185         long transientChannelId = insertChannel(true /* transient */);
    186         long permanentChannelId = insertChannel(false /* transient */);
    187         insertPreviewPrograms(transientChannelId, transientProgramInTransientChannel);
    188         insertPreviewPrograms(transientChannelId, permanentProgramInTransientChannel);
    189         insertPreviewPrograms(permanentChannelId, transientProgramInPermanentChannel);
    190         insertPreviewPrograms(permanentChannelId, permanentProgramInPermanentChannel);
    191 
    192         assertEquals("Before reboot all the programs inserted should exist.",
    193                 Sets.newHashSet(transientProgramInTransientChannel,
    194                         permanentProgramInTransientChannel, transientProgramInPermanentChannel,
    195                         permanentProgramInPermanentChannel),
    196                 queryPreviewPrograms());
    197         assertEquals("Before reboot the channels inserted should exist.",
    198                 2, getChannelCount());
    199 
    200         mTransientRowHelper.simulateReboot();
    201         assertEquals("Transient program and programs in transient channel should be removed.",
    202                 Sets.newHashSet(permanentProgramInPermanentChannel), queryPreviewPrograms());
    203         assertEquals("Transient channel should not be removed.",
    204                 1, getChannelCount());
    205     }
    206 
    207     private class RebootSimulatingTransientRowHelper extends TransientRowHelper {
    208         private int mLastDeletionBootCount;
    209         private int mBootCount = 1;
    210 
    211         private RebootSimulatingTransientRowHelper(Context context) {
    212             super(context);
    213         }
    214 
    215         @Override
    216         protected int getBootCount() {
    217             return mBootCount;
    218         }
    219 
    220         @Override
    221         protected int getLastDeletionBootCount() {
    222             return mLastDeletionBootCount;
    223         }
    224 
    225         @Override
    226         protected void setLastDeletionBootCount() {
    227             mLastDeletionBootCount = mBootCount;
    228         }
    229 
    230         private void simulateReboot() {
    231             mTransientRowsDeleted = false;
    232             mBootCount++;
    233         }
    234     }
    235 }
    236