TIF: Do not log non-searchable channel watch history

Bug: 16798476
Change-Id: Ic131009ad65a661331e4f8f0820c5c183a9f4986
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 5a0ea0d..a826957 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentUris;
+import android.media.tv.TvContract.Programs;
 import android.net.Uri;
 import android.provider.BaseColumns;
 import android.util.ArraySet;
@@ -684,10 +685,11 @@
          * The flag indicating whether this TV channel is searchable or not.
          * <p>
          * In some regions, it is not allowed to surface search results for a given channel without
-         * broadcaster's consent. This is used to impose such restriction. A value of 1 indicates
-         * the channel is searchable and can be included in search results, a value of 0 indicates
-         * the channel and its TV programs are hidden from search. If not specified, this value is
-         * set to 1 (searchable) by default.
+         * broadcaster's consent. This is used to impose such restriction. Channels marked with
+         * "not searchable" cannot be used by other services except for the system service that
+         * shows the TV content. A value of 1 indicates the channel is searchable and can be
+         * included in search results, a value of 0 indicates the channel and its TV programs are
+         * hidden from search. If not specified, this value is set to 1 (searchable) by default.
          * </p><p>
          * Type: INTEGER (boolean)
          * </p>
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index c095905..14d1ec4 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -35,7 +35,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Rect;
 import android.hardware.hdmi.HdmiDeviceInfo;
@@ -283,7 +282,6 @@
         userState.inputMap.clear();
         userState.inputMap = inputMap;
 
-        Resources r = Resources.getSystem();
         userState.ratingSystemXmlUriSet.clear();
         userState.ratingSystemXmlUriSet.add(TvContentRating.SYSTEM_CONTENT_RATING_SYSTEM_XML);
         for (TvInputState state : userState.inputMap.values()) {
@@ -1262,6 +1260,7 @@
                         args.arg1 = sessionState.mLogUri;
                         args.arg2 = ContentUris.parseId(channelUri);
                         args.arg3 = currentTime;
+                        args.arg4 = sessionState;
                         mLogHandler.obtainMessage(LogHandler.MSG_OPEN_ENTRY, args).sendToTarget();
                     } catch (RemoteException e) {
                         Slog.e(TAG, "error in tune", e);
@@ -2076,7 +2075,8 @@
                     Uri uri = (Uri) args.arg1;
                     long channelId = (long) args.arg2;
                     long time = (long) args.arg3;
-                    onOpenEntry(uri, channelId, time);
+                    SessionState sessionState = (SessionState) args.arg4;
+                    onOpenEntry(uri, channelId, time, sessionState);
                     args.recycle();
                     return;
                 }
@@ -2085,7 +2085,8 @@
                     Uri uri = (Uri) args.arg1;
                     long channelId = (long) args.arg2;
                     long time = (long) args.arg3;
-                    onUpdateEntry(uri, channelId, time);
+                    SessionState sessionState = (SessionState) args.arg4;
+                    onUpdateEntry(uri, channelId, time, sessionState);
                     args.recycle();
                     return;
                 }
@@ -2104,7 +2105,17 @@
             }
         }
 
-        private void onOpenEntry(Uri uri, long channelId, long watchStarttime) {
+        private void onOpenEntry(Uri logUri, long channelId, long watchStarttime,
+                SessionState sessionState) {
+            if (!isChannelSearchable(channelId)) {
+                // Do not log anything about non-searchable channels.
+                synchronized (mLock) {
+                    sessionState.mLogUri = null;
+                }
+                mContentResolver.delete(logUri, null, null);
+                return;
+            }
+
             String[] projection = {
                     TvContract.Programs.COLUMN_TITLE,
                     TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
@@ -2132,11 +2143,11 @@
                     long endTime = cursor.getLong(2);
                     values.put(TvContract.WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
                     values.put(TvContract.WatchedPrograms.COLUMN_DESCRIPTION, cursor.getString(3));
-                    mContentResolver.update(uri, values, null, null);
+                    mContentResolver.update(logUri, values, null, null);
 
                     // Schedule an update when the current program ends.
                     SomeArgs args = SomeArgs.obtain();
-                    args.arg1 = uri;
+                    args.arg1 = logUri;
                     args.arg2 = channelId;
                     args.arg3 = endTime;
                     Message msg = obtainMessage(LogHandler.MSG_UPDATE_ENTRY, args);
@@ -2149,7 +2160,7 @@
             }
         }
 
-        private void onUpdateEntry(Uri uri, long channelId, long time) {
+        private void onUpdateEntry(Uri uri, long channelId, long time, SessionState sessionState) {
             String[] projection = {
                     TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
                     TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS,
@@ -2193,7 +2204,7 @@
                 }
             }
             // Re-open the current log entry with the next program information.
-            onOpenEntry(uri, channelId, time);
+            onOpenEntry(uri, channelId, time, sessionState);
         }
 
         private void onCloseEntry(Uri uri, long watchEndTime) {
@@ -2201,6 +2212,26 @@
             values.put(TvContract.WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, watchEndTime);
             mContentResolver.update(uri, values, null, null);
         }
+
+        private boolean isChannelSearchable(long channelId) {
+            String[] projection = { TvContract.Channels.COLUMN_SEARCHABLE };
+            String selection = TvContract.Channels._ID + "=?";
+            String[] selectionArgs = { String.valueOf(channelId) };
+            Cursor cursor = null;
+            try {
+                cursor = mContentResolver.query(TvContract.Channels.CONTENT_URI, projection,
+                        selection, selectionArgs, null);
+                if (cursor != null && cursor.moveToNext()) {
+                    return cursor.getLong(0) == 1 ? true : false;
+                }
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+            // Unless explicitly specified non-searchable, by default the channel is searchable.
+            return true;
+        }
     }
 
     final class HardwareListener implements TvInputHardwareManager.Listener {