OSDN Git Service

Updated Gallery2 with Pano.
authorJustin Koh <justinkoh@google.com>
Wed, 27 Feb 2013 23:31:29 +0000 (15:31 -0800)
committerJustin Koh <justinkoh@google.com>
Wed, 27 Feb 2013 23:31:29 +0000 (15:31 -0800)
Updated Gallery2 with Pano.
Bug: 8263808

Change-Id: Iedaba9dc478fb20480f3b37e9708bc8d67cf6003

src/com/android/photos/canvas/CanvasActivity.java
src/com/android/photos/canvas/CanvasProvider.java
src/com/android/photos/canvas/CanvasProviderBase.java
src/com/google/android/pano/data/Cluster.java [moved from src/com/google/android/canvas/data/Cluster.java with 53% similarity]
src/com/google/android/pano/data/util/UriUtils.java [moved from src/com/google/android/canvas/data/util/UriUtils.java with 90% similarity]
src/com/google/android/pano/provider/PanoContract.java [moved from src/com/google/android/canvas/provider/CanvasContract.java with 75% similarity]

index 17afdb8..ad3cb63 100644 (file)
@@ -20,14 +20,14 @@ import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
 
-import com.google.android.canvas.provider.CanvasContract;
+import com.google.android.pano.provider.PanoContract;
 
 
 public class CanvasActivity extends Activity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Intent intent = CanvasContract.getBrowseIntent(
+        Intent intent = PanoContract.getBrowseIntent(
                 CanvasProvider.BROWSER_ROOT_URI, 0);
         startActivity(intent);
         finish();
index 1ed6cd4..1bc5566 100644 (file)
@@ -42,8 +42,8 @@ import com.android.gallery3d.util.Future;
 import com.android.gallery3d.util.ThreadPool.CancelListener;
 import com.android.gallery3d.util.ThreadPool.Job;
 import com.android.gallery3d.util.ThreadPool.JobContext;
-import com.google.android.canvas.data.Cluster;
-import com.google.android.canvas.provider.CanvasContract;
+import com.google.android.pano.data.Cluster;
+import com.google.android.pano.provider.PanoContract;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -142,7 +142,7 @@ public class CanvasProvider extends CanvasProviderBase {
             Cluster.Builder bob = new Cluster.Builder();
             bob.id(i);
             bob.displayName(set.getName());
-            Intent intent = CanvasContract.getBrowseIntent(BROWSER_ROOT_URI, i);
+            Intent intent = PanoContract.getBrowseIntent(BROWSER_ROOT_URI, i);
             bob.intent(intent);
             bob.imageCropAllowed(true);
             bob.cacheTimeMs(CACHE_TIME_MS);
index 4438c53..a38aae5 100644 (file)
@@ -26,8 +26,8 @@ import android.net.Uri;
 import android.os.Binder;
 import android.provider.BaseColumns;
 
-import com.google.android.canvas.data.Cluster;
-import com.google.android.canvas.provider.CanvasContract;
+import com.google.android.pano.data.Cluster;
+import com.google.android.pano.provider.PanoContract;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -45,10 +45,10 @@ public abstract class CanvasProviderBase extends ContentProvider {
     protected static final String PATH_IMAGE = "image";
     protected static final String PATH_LAUNCHER = "launcher";
     protected static final String PATH_LAUNCHER_ITEM = PATH_LAUNCHER + "/"
-            + CanvasContract.PATH_LAUNCHER_ITEM;
+            + PanoContract.PATH_LAUNCHER_ITEM;
     protected static final String PATH_BROWSE = "browse";
     protected static final String PATH_BROWSE_HEADERS = PATH_BROWSE + "/"
-            + CanvasContract.PATH_BROWSE_HEADERS;
+            + PanoContract.PATH_BROWSE_HEADERS;
 
     public static final Uri BROWSER_ROOT_URI = Uri.parse("content://"
             + AUTHORITY + "/" + PATH_BROWSE);
@@ -91,19 +91,19 @@ public abstract class CanvasProviderBase extends ContentProvider {
     static {
         LAUNCHER_COLUMN_CASES.put(BaseColumns._ID, LAUNCHER_CASE_ID);
         LAUNCHER_COLUMN_CASES.put(BaseColumns._COUNT, LAUNCHER_CASE_COUNT);
-        LAUNCHER_COLUMN_CASES.put(CanvasContract.Launcher.NAME,
+        LAUNCHER_COLUMN_CASES.put(PanoContract.Launcher.NAME,
                 LAUNCHER_CASE_NAME);
-        LAUNCHER_COLUMN_CASES.put(CanvasContract.Launcher.IMPORTANCE,
+        LAUNCHER_COLUMN_CASES.put(PanoContract.Launcher.IMPORTANCE,
                 LAUNCHER_CASE_IMPORTANCE);
-        LAUNCHER_COLUMN_CASES.put(CanvasContract.Launcher.DISPLAY_NAME,
+        LAUNCHER_COLUMN_CASES.put(PanoContract.Launcher.DISPLAY_NAME,
                 LAUNCHER_CASE_DISPLAY_NAME);
-        LAUNCHER_COLUMN_CASES.put(CanvasContract.Launcher.VISIBLE_COUNT,
+        LAUNCHER_COLUMN_CASES.put(PanoContract.Launcher.VISIBLE_COUNT,
                 LAUNCHER_CASE_VISIBLE_COUNT);
-        LAUNCHER_COLUMN_CASES.put(CanvasContract.Launcher.IMAGE_CROP_ALLOWED,
+        LAUNCHER_COLUMN_CASES.put(PanoContract.Launcher.IMAGE_CROP_ALLOWED,
                 LAUNCHER_CASE_CROP_ALLOWED);
-        LAUNCHER_COLUMN_CASES.put(CanvasContract.Launcher.CACHE_TIME_MS,
+        LAUNCHER_COLUMN_CASES.put(PanoContract.Launcher.CACHE_TIME_MS,
                 LAUNCHER_CASE_CACHE_TIME);
-        LAUNCHER_COLUMN_CASES.put(CanvasContract.Launcher.INTENT_URI,
+        LAUNCHER_COLUMN_CASES.put(PanoContract.Launcher.INTENT_URI,
                 LAUNCHER_CASE_INTENT_URI);
 
         LAUNCHER_PROJECTION_ALL = LAUNCHER_COLUMN_CASES.keySet().toArray(
@@ -120,9 +120,9 @@ public abstract class CanvasProviderBase extends ContentProvider {
     static {
         CLUSTER_COLUMN_CASES.put(BaseColumns._ID, CLUSTER_CASE_ID);
         CLUSTER_COLUMN_CASES.put(BaseColumns._COUNT, CLUSTER_CASE_COUNT);
-        CLUSTER_COLUMN_CASES.put(CanvasContract.LauncherItem.PARENT_ID,
+        CLUSTER_COLUMN_CASES.put(PanoContract.LauncherItem.PARENT_ID,
                 CLUSTER_CASE_PARENT_ID);
-        CLUSTER_COLUMN_CASES.put(CanvasContract.LauncherItem.IMAGE_URI,
+        CLUSTER_COLUMN_CASES.put(PanoContract.LauncherItem.IMAGE_URI,
                 CLUSTER_CASE_IMAGE_URI);
 
         CLUSTER_PROJECTION_ALL = CLUSTER_COLUMN_CASES.keySet().toArray(
@@ -149,33 +149,33 @@ public abstract class CanvasProviderBase extends ContentProvider {
         BROWSE_HEADER_COLUMN_CASES.put(BaseColumns._ID, BROWSE_HEADER_CASE_ID);
         BROWSE_HEADER_COLUMN_CASES.put(BaseColumns._COUNT,
                 BROWSE_HEADER_CASE_COUNT);
-        BROWSE_HEADER_COLUMN_CASES.put(CanvasContract.BrowseHeaders.NAME,
+        BROWSE_HEADER_COLUMN_CASES.put(PanoContract.BrowseHeaders.NAME,
                 BROWSE_HEADER_CASE_NAME);
         BROWSE_HEADER_COLUMN_CASES.put(
-                CanvasContract.BrowseHeaders.DISPLAY_NAME,
+                PanoContract.BrowseHeaders.DISPLAY_NAME,
                 BROWSE_HEADER_CASE_DISPLAY_NAME);
-        BROWSE_HEADER_COLUMN_CASES.put(CanvasContract.BrowseHeaders.ICON_URI,
+        BROWSE_HEADER_COLUMN_CASES.put(PanoContract.BrowseHeaders.ICON_URI,
                 BROWSE_HEADER_CASE_ICON_URI);
-        BROWSE_HEADER_COLUMN_CASES.put(CanvasContract.BrowseHeaders.BADGE_URI,
+        BROWSE_HEADER_COLUMN_CASES.put(PanoContract.BrowseHeaders.BADGE_URI,
                 BROWSE_HEADER_CASE_BADGE_URI);
-        BROWSE_HEADER_COLUMN_CASES.put(CanvasContract.BrowseHeaders.COLOR_HINT,
+        BROWSE_HEADER_COLUMN_CASES.put(PanoContract.BrowseHeaders.COLOR_HINT,
                 BROWSE_HEADER_CASE_COLOR_HINT);
         BROWSE_HEADER_COLUMN_CASES.put(
-                CanvasContract.BrowseHeaders.TEXT_COLOR_HINT,
+                PanoContract.BrowseHeaders.TEXT_COLOR_HINT,
                 BROWSE_HEADER_CASE_TEXT_COLOR_HINT);
         BROWSE_HEADER_COLUMN_CASES.put(
-                CanvasContract.BrowseHeaders.BG_IMAGE_URI,
+                PanoContract.BrowseHeaders.BG_IMAGE_URI,
                 BROWSE_HEADER_CASE_BG_IMAGE_URI);
         BROWSE_HEADER_COLUMN_CASES.put(
-                CanvasContract.BrowseHeaders.EXPAND_GROUP,
+                PanoContract.BrowseHeaders.EXPAND_GROUP,
                 BROWSE_HEADER_CASE_EXPAND_GROUP);
-        BROWSE_HEADER_COLUMN_CASES.put(CanvasContract.BrowseHeaders.WRAP_ITEMS,
+        BROWSE_HEADER_COLUMN_CASES.put(PanoContract.BrowseHeaders.WRAP_ITEMS,
                 BROWSE_HEADER_CASE_WRAP);
         BROWSE_HEADER_COLUMN_CASES.put(
-                CanvasContract.BrowseHeaders.DEFAULT_ITEM_WIDTH,
+                PanoContract.BrowseHeaders.DEFAULT_ITEM_WIDTH,
                 BROWSE_HEADER_CASE_DEFAULT_ITEM_WIDTH);
         BROWSE_HEADER_COLUMN_CASES.put(
-                CanvasContract.BrowseHeaders.DEFAULT_ITEM_HEIGHT,
+                PanoContract.BrowseHeaders.DEFAULT_ITEM_HEIGHT,
                 BROWSE_HEADER_CASE_DEFAULT_ITEM_HEIGHT);
 
         BROWSE_HEADER_PROJECTION_ALL = BROWSE_HEADER_COLUMN_CASES.keySet()
@@ -197,19 +197,19 @@ public abstract class CanvasProviderBase extends ContentProvider {
     static {
         BROWSE_COLUMN_CASES.put(BaseColumns._ID, BROWSE_CASE_ID);
         BROWSE_COLUMN_CASES.put(BaseColumns._COUNT, BROWSE_CASE_COUNT);
-        BROWSE_COLUMN_CASES.put(CanvasContract.BrowseItems.PARENT_ID,
+        BROWSE_COLUMN_CASES.put(PanoContract.BrowseItems.PARENT_ID,
                 BROWSE_CASE_PARENT_ID);
-        BROWSE_COLUMN_CASES.put(CanvasContract.BrowseItems.DISPLAY_NAME,
+        BROWSE_COLUMN_CASES.put(PanoContract.BrowseItems.DISPLAY_NAME,
                 BROWSE_CASE_DISPLAY_NAME);
-        BROWSE_COLUMN_CASES.put(CanvasContract.BrowseItems.DISPLAY_DESCRIPTION,
+        BROWSE_COLUMN_CASES.put(PanoContract.BrowseItems.DISPLAY_DESCRIPTION,
                 BROWSE_CASE_DISPLAY_DESCRIPTION);
-        BROWSE_COLUMN_CASES.put(CanvasContract.BrowseItems.IMAGE_URI,
+        BROWSE_COLUMN_CASES.put(PanoContract.BrowseItems.IMAGE_URI,
                 BROWSE_CASE_IMAGE_URI);
-        BROWSE_COLUMN_CASES.put(CanvasContract.BrowseItems.WIDTH,
+        BROWSE_COLUMN_CASES.put(PanoContract.BrowseItems.WIDTH,
                 BROWSE_CASE_WIDTH);
-        BROWSE_COLUMN_CASES.put(CanvasContract.BrowseItems.HEIGHT,
+        BROWSE_COLUMN_CASES.put(PanoContract.BrowseItems.HEIGHT,
                 BROWSE_CASE_HEIGHT);
-        BROWSE_COLUMN_CASES.put(CanvasContract.BrowseItems.INTENT_URI,
+        BROWSE_COLUMN_CASES.put(PanoContract.BrowseItems.INTENT_URI,
                 BROWSE_CASE_INTENT_URI);
 
         BROWSE_PROJECTION_ALL = BROWSE_COLUMN_CASES.keySet().toArray(
@@ -1,6 +1,6 @@
 // Copyright 2012 Google Inc. All Rights Reserved.
 
-package com.google.android.canvas.data;
+package com.google.android.pano.data;
 
 import android.content.Intent;
 import android.net.Uri;
@@ -21,6 +21,7 @@ public class Cluster {
     private boolean mImageCropAllowed;
     private long mCacheTimeMs;
     private Intent mIntent;
+    private Uri mBrowseItemsUri;
 
     private List<ClusterItem> mClusterItems;
 
@@ -30,7 +31,7 @@ public class Cluster {
     public static class ClusterItem {
         private Uri mImageUri;
 
-        ClusterItem(Uri imageUri) {
+        public ClusterItem(Uri imageUri) {
             mImageUri = imageUri;
         }
 
@@ -44,6 +45,31 @@ public class Cluster {
             builder.append("imageUri: ").append(mImageUri);
             return builder.toString();
         }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((mImageUri == null) ? 0 : mImageUri.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            ClusterItem other = (ClusterItem) obj;
+            if (mImageUri == null) {
+                if (other.mImageUri != null)
+                    return false;
+            } else if (!mImageUri.equals(other.mImageUri))
+                return false;
+            return true;
+        }
     }
 
     public Cluster() {
@@ -83,6 +109,10 @@ public class Cluster {
         return mIntent;
     }
 
+    public Uri getBrowseItemsUri() {
+        return mBrowseItemsUri;
+    }
+
     public int getItemCount() {
         return mClusterItems.size();
     }
@@ -94,10 +124,85 @@ public class Cluster {
         return null;
     }
 
-    void addClusterItem(ClusterItem item) {
+    public void addClusterItem(ClusterItem item) {
         mClusterItems.add(item);
     }
 
+    public void clearItems() {
+        mClusterItems.clear();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (int) (mCacheTimeMs ^ (mCacheTimeMs >>> 32));
+        if (mClusterItems == null) {
+            result = prime * result;
+        } else {
+            for (ClusterItem ci : mClusterItems) {
+                result = prime * result + ci.hashCode();
+            }
+        }
+        result = prime * result + ((mDisplayName == null) ? 0 : mDisplayName.toString().hashCode());
+        result = prime * result + (int) (mId ^ (mId >>> 32));
+        result = prime * result + (mImageCropAllowed ? 1231 : 1237);
+        result = prime * result + mImportance;
+        result = prime * result + ((mIntent == null) ? 0 : mIntent.hashCode());
+        result = prime * result + ((mName == null) ? 0 : mName.hashCode());
+        result = prime * result + mVisibleCount;
+        result = prime * result + ((mBrowseItemsUri == null) ? 0 : mBrowseItemsUri.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Cluster other = (Cluster) obj;
+        if (mCacheTimeMs != other.mCacheTimeMs)
+            return false;
+        if (mClusterItems == null) {
+            if (other.mClusterItems != null)
+                return false;
+        } else if (!mClusterItems.equals(other.mClusterItems))
+            return false;
+        if (mDisplayName == null) {
+            if (other.mDisplayName != null)
+                return false;
+        } else if (!mDisplayName.equals(other.mDisplayName))
+            return false;
+        if (mId != other.mId)
+            return false;
+        if (mImageCropAllowed != other.mImageCropAllowed)
+            return false;
+        if (mImportance != other.mImportance)
+            return false;
+        if (mIntent == null) {
+            if (other.mIntent != null)
+                return false;
+        } else if (!mIntent.equals(other.mIntent))
+            return false;
+        if (mName == null) {
+            if (other.mName != null)
+                return false;
+        } else if (!mName.equals(other.mName))
+            return false;
+        if (mVisibleCount != other.mVisibleCount)
+            return false;
+        if (mBrowseItemsUri == null) {
+            if (other.mBrowseItemsUri != null)
+                return false;
+        } else if (!mBrowseItemsUri.equals(other.mBrowseItemsUri)) {
+            return false;
+        }
+        return true;
+    }
+
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
@@ -108,7 +213,9 @@ public class Cluster {
                 .append(", visibleCount: ").append(mVisibleCount)
                 .append(", imageCropAllowed: ").append(mImageCropAllowed)
                 .append(", cacheTimeMs: ").append(mCacheTimeMs)
-                .append(", intent: ").append(mIntent.toUri(0));
+                .append(", clusterItems: ").append(mClusterItems)
+                .append(", intent: ").append(mIntent != null ? mIntent.toUri(0) : "")
+                .append(", browseItems: ").append(mBrowseItemsUri != null ? mBrowseItemsUri : "");
         return builder.toString();
     }
 
@@ -124,6 +231,7 @@ public class Cluster {
         private boolean mImageCropAllowed;
         private long mCacheTimeMs;
         private Intent mIntent;
+        private Uri mBrowseItemsUri;
 
         private List<ClusterItem> mClusterItems;
 
@@ -138,6 +246,7 @@ public class Cluster {
             cluster.mIntent = mIntent;
             cluster.mCacheTimeMs = mCacheTimeMs;
             cluster.mClusterItems.addAll(mClusterItems);
+            cluster.mBrowseItemsUri = mBrowseItemsUri;
             return cluster;
         }
 
@@ -186,6 +295,11 @@ public class Cluster {
             return this;
         }
 
+        public Builder browseItemsUri(Uri uri) {
+            mBrowseItemsUri = uri;
+            return this;
+        }
+
         public Builder addItem(Uri imageUri) {
             ClusterItem item = new ClusterItem(imageUri);
             mClusterItems.add(item);
@@ -1,6 +1,6 @@
 // Copyright 2012 Google Inc. All Rights Reserved.
 
-package com.google.android.canvas.data.util;
+package com.google.android.pano.data.util;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -83,6 +83,15 @@ public final class UriUtils {
     }
 
     /**
+     * Returns {@code true} if the URI refers to a content URI which can be opened via
+     * {@link ContentResolver#openInputStream(Uri)}.
+     */
+    public static boolean isContentUri(Uri uri) {
+        return ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()) ||
+                ContentResolver.SCHEME_FILE.equals(uri.getScheme());
+    }
+
+    /**
      * Checks if the URI refers to an shortcut icon resource.
      */
     public static boolean isShortcutIconResourceUri(Uri uri) {
@@ -118,7 +127,8 @@ public final class UriUtils {
      * Returns {@code true} if this is a web URI.
      */
     public static boolean isWebUri(Uri resourceUri) {
-        String scheme = resourceUri.getScheme().toLowerCase();
+        String scheme = resourceUri.getScheme() == null ? null
+                : resourceUri.getScheme().toLowerCase();
         return HTTP_PREFIX.equals(scheme) || HTTPS_PREFIX.equals(scheme);
     }
 }
@@ -1,4 +1,4 @@
-package com.google.android.canvas.provider;
+package com.google.android.pano.provider;
 
 import android.content.ContentUris;
 import android.content.Intent;
@@ -6,13 +6,13 @@ import android.net.Uri;
 import android.provider.BaseColumns;
 
 /**
- * The contract between Canvas and ContentProviders that allow access to Canvas
- * browsing data. All apps that wish to interact with Canvas should use these
+ * The contract between Pano and ContentProviders that allow access to Pano
+ * browsing data. All apps that wish to interact with Pano should use these
  * definitions.
  *
  * TODO add more details
  */
-public final class CanvasContract {
+public final class PanoContract {
 
     // Base for content uris
     public static final String CONTENT = "content://";
@@ -30,37 +30,50 @@ public final class CanvasContract {
     public static final String PATH_BROWSE_HEADERS = "headers";
 
     /**
-     * This tag is used to identify the authority to be used for a canvas
-     * launcher app.
-     *
-     * TODO: this is obsolete: remove.
+     * Pano will search for activities with the action {@link Intent#ACTION_MAIN} and this
+     * category in order to find the activities for the home screen.
      */
-    public static final String METADATA_TAG = "com.google.android.canvas.data.launcher";
+    public static final String CATEGORY_BROWSE_LAUNCHER =
+            "com.google.android.pano.category.BROWSE_LAUNCHER";
 
     /**
-     * This tag is used to identify the launcher info data file to be used for a canvas
+     * This tag is used to identify the launcher info data file to be used for a Pano
      * launcher app.
      */
     public static final String METADATA_LAUNCHER_INFO_TAG =
-            "com.google.android.canvas.data.launcher_info";
+            "com.google.android.pano.data.launcher_info";
+
+    /**
+     * An intent action for browsing app content in Pano. Apps receiving this
+     * intent should call {@link Intent#getData()} to retrieve the base Uri and
+     * {@link #EXTRA_START_INDEX} or {@link #EXTRA_START_ID} to find which header
+     * to start at (default 0).
+     */
+    public static final String ACTION_BROWSE = "com.google.android.pano.action.BROWSE";
 
     /**
-     * This tag is used to denote a background color hint for the activity.
+     * An intent action for picking app content in Pano.
      * <p>
-     * This can either be a reference to an @color or else a string (e.g. #ff001100).
-     *
-     * TODO: this is obsolete: remove.
+     * Any intents launched from here will be returned to the calling activity instead of being
+     * directly launched.
+     * <p>
+     * This can be used to select an item.
      */
-    public static final String METADATA_COLOR_HINT =
-            "com.google.android.canvas.ui.launcher_color_hint";
+    public static final String ACTION_BROWSE_PICKER =
+            "com.google.android.pano.action.BROWSE_PICKER";
 
     /**
-     * An intent action for browsing app content in Canvas. Apps receiving this
-     * intent should call {@link Intent#getData()} to retrieve the base Uri and
-     * {@link #EXTRA_START_INDEX} or {@link #EXTRA_START_ID} to find which header
-     * to start at (default 0).
+     * An intent action for picking app content while keeping the launching app running.
+     * <p>
+     * Pano Browse will appear over the app.
+     * <p>
+     * Any intents launched from here will be returned to the calling activity instead of being
+     * directly launched.
+     * <p>
+     * This can be used to select an item.
      */
-    public static final String ACTION_BROWSE = "com.google.android.canvas.action.BROWSE";
+    public static final String ACTION_BROWSE_PICKER_TRANSLUCENT =
+            "com.google.android.pano.action.BROWSE_PICKER_TRANSLUCENT";
 
     /**
      * The index of the header to focus on initially when the browse is launched.
@@ -76,10 +89,25 @@ public final class CanvasContract {
     public static final String EXTRA_START_ID = "start_id";
 
     /**
-     * An intent action for viewing detail content in Canvas. Apps receiving this
+     * An intent action for viewing detail content in Pano. Apps receiving this
      * intent should call {@link Intent#getData()} to retrieve the base Uri.
      */
-    public static final String ACTION_DETAIL = "com.google.android.canvas.action.DETAIL";
+    public static final String ACTION_DETAIL = "com.google.android.pano.action.DETAIL";
+
+    /**
+     * The name of the section to focus on initially when {@link #ACTION_DETAIL} is launched.
+     * <p>
+     * Using name allows targeting a sub section.
+     */
+    public static final String EXTRA_START_NAME = "start_name";
+
+    /**
+     * Index of a child to focus on initially when {@link #ACTION_DETAIL} is launched.
+     * <p>
+     * Requires a start section to be specified using {@link #EXTRA_START_INDEX} or
+     * {@link #EXTRA_START_NAME}.
+     */
+    public static final String EXTRA_START_CHILD_INDEX = "start_child_index";
 
     /**
      * Path for querying details for an item.
@@ -99,11 +127,33 @@ public final class CanvasContract {
     public static final String PATH_DETAIL_ACTIONS = "actions";
 
     /**
-     * Action for searching a Canvas provider. Apps receiving this
+     * Action for searching a Pano provider. Apps receiving this
      * intent should call {@link Intent#getData()} to retrieve the base Uri and
      * {@link #EXTRA_QUERY} to find query.
      */
-    public static final String ACTION_SEARCH = "com.google.android.canvas.action.SEARCH";
+    public static final String ACTION_SEARCH = "com.google.android.pano.action.SEARCH";
+
+    /**
+     * Action for searching a Pano provider.
+     * <p>
+     * Any intent selected off this activity will be returned to the calling activity instead of
+     * being launched directly.
+     */
+    public static final String ACTION_SEARCH_PICKER =
+            "com.google.android.pano.action.SEARCH_PICKER";
+
+    /**
+     * An intent action for searching app content while keeping the launching app running.
+     * <p>
+     * Pano Search will appear over the app.
+     * <p>
+     * Any intents launched from here will be returned to the calling activity instead of being
+     * directly launched.
+     * <p>
+     * This can be used to select an item.
+     */
+    public static final String ACTION_SEARCH_PICKER_TRANSLUCENT =
+            "com.google.android.pano.action.SEARCH_PICKER_TRANSLUCENT";
 
     /**
      * The query to be executed when search activity is launched
@@ -112,6 +162,13 @@ public final class CanvasContract {
     public static final String EXTRA_QUERY = "query";
 
     /**
+     * Optional String extra for meta information. This must be supplied as a string, but must be a valid URI.
+     * <p>
+     * Used with {@link #ACTION_SEARCH}.
+     */
+    public static final String EXTRA_META_URI = "meta_uri";
+
+    /**
      * Optional int extra for setting the display mode of the search activity.
      *
      * @see #DISPLAY_MODE_ROW
@@ -121,9 +178,10 @@ public final class CanvasContract {
 
     public static final int DISPLAY_MODE_ROW = 0;
     public static final int DISPLAY_MODE_GRID = 1;
+    public static final int DISPLAY_MODE_BROWSE = 2;
 
     /**
-     * Value for the root Canvas URI when this activity should be excluded from the Canvas top level
+     * Value for the root Pano URI when this activity should be excluded from the Pano top level
      * and the legacy apps area.
      *
      * TODO: this is obsolete: remove.
@@ -187,10 +245,27 @@ public final class CanvasContract {
         public static final String CACHE_TIME_MS = "cache_time_ms";
 
         /**
+         * Content URI pointing to a list of items in the {@link PanoContract.BrowseItemsColumns}
+         * schema.
+         * <p>
+         * This is optional but highly recommended if the cluster represents a browse row.
+         * <p>
+         * In this case, the cluster items will be read from this URI instead of from the cluster
+         * items.
+         * <p>
+         * If this is filled in, the intent_uri must have the action
+         * {@link PanoContract#ACTION_BROWSE}. The row with this URI will automatically be
+         * selected when the activity starts up.
+         *
+         * <P>Type: String (Uri)</P>
+         */
+        public static final String BROWSE_ITEMS_URI = "browse_items_uri";
+
+        /**
          * A standard Intent Uri to be launched when this cluster is selected.
-         * This may be a {@link CanvasContract#ACTION_BROWSE} intent or an
+         * This may be a {@link PanoContract#ACTION_BROWSE} intent or an
          * intent to launch directly into an app. You can also use
-         * {@link CanvasContract#getBrowseIntent(Uri, int)} to generate a
+         * {@link PanoContract#getBrowseIntent(Uri, int)} to generate a
          * browse intent for a given root Uri. Use {@link Intent#toUri(int)}
          * with a flag of {@link Intent#URI_INTENT_SCHEME}.
          *
@@ -208,7 +283,7 @@ public final class CanvasContract {
         public static final String NOTIFICATION_TEXT = "notification_text";
 
         /**
-         * An optional Uri for querying progresss for any ongoing actions, such
+         * An optional Uri for querying progress for any ongoing actions, such
          * as an active download.
          *
          * <P>Type: String (Uri)</P>
@@ -232,6 +307,16 @@ public final class CanvasContract {
          * <P>Type: INTEGER</P>
          */
         public static final String PROGRESS = "progress";
+
+        /**
+         * The smallest value that is a valid {@link #PROGRESS}.
+         */
+        public static final int PROGRESS_MIN = 0;
+
+        /**
+         * The largest value that is a valid {@link #PROGRESS}.
+         */
+        public static final int PROGRESS_MAX = 100;
     }
 
     public static final class Progress implements BaseColumns, ProgressColumns {
@@ -305,6 +390,16 @@ public final class CanvasContract {
         public static final String DISPLAY_NAME = "display_name";
 
         /**
+         * Optional Uri pointing to the data for the items for this header.
+         * <p>
+         * If this is not provided, a Uri will be constructed using
+         * {@link BrowseItems#getBrowseItemsUri(Uri, long)}.
+         *
+         * <P>Type: String</P>
+         */
+        public static final String ITEMS_URI = "items_uri";
+
+        /**
          * Uri pointing to an icon to be used as part of the header. This
          * String should be generated using {@link Uri#toString()}
          *
@@ -346,6 +441,20 @@ public final class CanvasContract {
          *
          * <P>Type: String (Uri)</P>
          */
+        public static final String BACKGROUND_IMAGE_URI = "background_image_uri";
+
+        /**
+         * Uri pointing to an image to display in the background when on this
+         * tab. Be sure the image contrasts enough with the text color hint and
+         * is of high enough quality to be displayed at 1080p. This String
+         * should be generated using {@link Uri#toString()}.  The URI will be either
+         * a resource uri in format of android:resource:// or an external URL
+         * like file://, http://, https://.
+         *
+         * <P>Type: String (Uri)</P>
+         * <P>This is the obsolete version of {@link #BACKGROUND_IMAGE_URI}</P>
+         * TODO: remove obsolete version when all clients have upgraded.
+         */
         public static final String BG_IMAGE_URI = "bg_image_uri";
 
         /**
@@ -481,22 +590,30 @@ public final class CanvasContract {
 
     protected interface UserRatingColumns {
         /**
-         * The average rating for this item. (Optional)
-         *
-         * <P>Type: Double</P>
+         * A custom rating String for this item, such as "78 points" or
+         * "20/100". (Optional)
+         * <p>
+         * A null or the absence of this column indicates there is no custom
+         * rating available.
+         * <P>Type: String</P>
          */
-        public static final String USER_RATING_AVERAGE = "user_rating_average";
+        public static final String USER_RATING_CUSTOM = "user_rating_custom";
 
         /**
-         * A simple rating for this item as an integer in the range
-         * [0-10] inclusive. (Optional)
-         *
-         * <P>Type: INTEGER</P>
+         * A scaled rating for this item as a float in the range [0-10]
+         * inclusive. Pano will be responsible for visualizing this
+         * value.(Optional)
+         * <p>
+         * A -1 or the absence of this column indicates there is no rating
+         * available.
+         * <P>Type: FLOAT</P>
          */
-        public static final String USER_RATING_SIMPLE = "user_rating_simple";
+        public static final String USER_RATING = "user_rating";
 
         /**
          * The number of reviews included in the average rating. (Optional)
+         * <p>
+         * A value of 0 indicates the count is not available.
          *
          * <P>Type: INTEGER</P>
          */
@@ -568,6 +685,13 @@ public final class CanvasContract {
     protected interface DetailSectionsColumns {
 
         /**
+         * Text ID for a section. Can be used to target the section
+         *
+         * <P>Type: String</P>
+         */
+        public static final String NAME = "name";
+
+        /**
          * Text that will be shown to the user for navigating between sections.
          *
          * <P>Type: String</P>
@@ -776,6 +900,23 @@ public final class CanvasContract {
         public static final String DISPLAY_NUMBER = "display_number";
 
         /**
+         * Hint for how to display the item. This is either {@link #ITEM_DISPLAY_TYPE_NORMAL} or
+         * {@link #ITEM_DISPLAY_TYPE_SINGLE_LINE}.
+         */
+        public static final String ITEM_DISPLAY_TYPE = "item_display_type";
+
+        /**
+         * Value for {@link #ITEM_DISPLAY_TYPE} which allows for multiple lines.
+         */
+        public static final int ITEM_DISPLAY_TYPE_NORMAL = 0;
+
+        /**
+         * Value for {@link #ITEM_DISPLAY_TYPE} which hints that the content should be displayed
+         * on a single line.
+         */
+        public static final int ITEM_DISPLAY_TYPE_SINGLE_LINE = 1;
+
+        /**
          * The uri for retrieving the image to show for this item. This string
          * should be created using {@link Uri#toString()}. (Optional)
          *
@@ -795,6 +936,23 @@ public final class CanvasContract {
         public static final String ACTION_URI = "action_uri";
     }
 
+    protected interface SearchBrowseResult {
+        public static final String RESULTS_URI = "results_uri";
+        /**
+         * The default width of the expanded image
+         *
+         * <P>Type: INTEGER</P>
+         */
+        public static final String DEFAULT_ITEM_WIDTH = "default_item_width";
+
+        /**
+         * The default height of the expanded image
+         *
+         * <P>Type: INTEGER</P>
+         */
+        public static final String DEFAULT_ITEM_HEIGHT = "default_item_height";
+    }
+
     public static final class DetailChildren
             implements BaseColumns, ItemChildrenColumns, UserRatingColumns {
 
@@ -805,7 +963,7 @@ public final class CanvasContract {
     }
 
     public static final class SearchResults
-            implements BaseColumns, ItemChildrenColumns, UserRatingColumns {
+            implements BaseColumns, ItemChildrenColumns, UserRatingColumns, SearchBrowseResult {
 
         /**
          * Non instantiable.
@@ -813,6 +971,40 @@ public final class CanvasContract {
         private SearchResults() {}
     }
 
+    protected interface MetaColumns {
+
+        /**
+         * The uri for retrieving the background image to show for this item. This string
+         * should be created using {@link Uri#toString()}.
+         *
+         * <P>Type: String (Uri)</P>
+         */
+        public static final String BACKGROUND_IMAGE_URI = "background_image_uri";
+        /**
+         * Uri pointing to an icon to be used for app branding on this tab.
+         * This String should be generated using {@link Uri#toString()}
+         *
+         * <P>Type: String (Uri)</P>
+         */
+        public static final String BADGE_URI = "badge_uri";
+
+        /**
+         * A 0xAARRGGBB color that should be applied to the background when on
+         * this tab.
+         *
+         * <P>Type: INTEGER</P>
+         */
+        public static final String COLOR_HINT = "color_hint";
+    }
+
+    public static final class MetaSchema implements BaseColumns, MetaColumns {
+
+        /**
+         * Non instantiable.
+         */
+        private MetaSchema() {}
+    }
+
     protected interface DetailActionsColumns {
 
         /**
@@ -892,4 +1084,4 @@ public final class CanvasContract {
         intent.setData(root);
         return intent;
     }
-}
\ No newline at end of file
+}