Update News

***TOP NEWS * How to delete google search? Give the offer GOOGLE

Monday 16 March 2015

Recommending TV Content

Recommending TV Content


When interacting with TVs, users generally prefer to give minimal input before watching content. An ideal scenario for many TV users is: sit down, turn on, and watch. The fewest steps to get users to content they enjoy is generally the path they prefer.
The Android framework assists with minimum-input interaction by providing a recommendations row on the home screen. Content recommendations appear as the first row of the TV home screen after the first use of the device. Contributing recommendations from your app's content catalog can help bring users back to your app.
Figure 1. An example of the recommendations row.
This lesson teaches you how to create recommendations and provide them to the Android framework so users can easily discover and enjoy your app content. This discussion describes some code from the Android Leanback sample app.

Create a Recommendations Service


Content recommendations are created with background processing. In order for your application to contribute to recommendations, create a service that periodically adds listings from your app's catalog to the system's list of recommendations.
The following code example illustrates how to extend IntentService to create a recommendation service for your application:
public class UpdateRecommendationsService extends IntentService {
    private static final String TAG = "UpdateRecommendationsService";
    private static final int MAX_RECOMMENDATIONS = 3;

    public UpdateRecommendationsService() {
        super("RecommendationService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "Updating recommendation cards");
        HashMap<String, List<Movie>> recommendations = VideoProvider.getMovieList();
        if (recommendations == null) return;

        int count = 0;

        try {
            RecommendationBuilder builder = new RecommendationBuilder()
                    .setContext(getApplicationContext())
                    .setSmallIcon(R.drawable.videos_by_google_icon);

            for (Map.Entry<String, List<Movie>> entry : recommendations.entrySet()) {
                for (Movie movie : entry.getValue()) {
                    Log.d(TAG, "Recommendation - " + movie.getTitle());

                    builder.setBackground(movie.getCardImageUrl())
                            .setId(count + 1)
                            .setPriority(MAX_RECOMMENDATIONS - count)
                            .setTitle(movie.getTitle())
                            .setDescription(getString(R.string.popular_header))
                            .setImage(movie.getCardImageUrl())
                            .setIntent(buildPendingIntent(movie))
                            .build();

                    if (++count >= MAX_RECOMMENDATIONS) {
                        break;
                    }
                }
                if (++count >= MAX_RECOMMENDATIONS) {
                    break;
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "Unable to update recommendation", e);
        }
    }

    private PendingIntent buildPendingIntent(Movie movie) {
        Intent detailsIntent = new Intent(this, DetailsActivity.class);
        detailsIntent.putExtra("Movie", movie);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(DetailsActivity.class);
        stackBuilder.addNextIntent(detailsIntent);
        // Ensure a unique PendingIntents, otherwise all recommendations end up with the same
        // PendingIntent
        detailsIntent.setAction(Long.toString(movie.getId()));

        PendingIntent intent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        return intent;
    }
}
In order for this service to be recognized by the system and run, register it using your app manifest. The following code snippet illustrates how to declare this class as a service:
<manifest ... >
  <application ... >
    ...

    <service
            android:name="com.example.android.tvleanback.UpdateRecommendationsService"
            android:enabled="true" />
  </application>
</manifest>

Refreshing Recommendations

Base your recommendations on user behavior and data such as play lists, wish lists, and associated content. When refreshing recommendations, don't just remove and repost them, because doing so causes the recommendations to appear at the end of the recommendations row. Once a content item, such as a movie, has been played, remove it from the recommendations.
The order of an app's recommendations is preserved according to the order in which the app provides them. The framework interleaves app recommendations based on recommendation quality, as measured by user behavior. Better recommendations make an app's recommendations more likely to appear near the front of the list.

Build Recommendations


Once your recommendation service starts running, it must create recommendations and pass them to the Android framework. The framework receives the recommendations as Notification objects that use a specific template and are marked with a specific category.

Setting the Values

To set the UI element values for the recommendation card, you create a builder class that follows the builder pattern described as follows. First, you set the values of the recommendation card elements.
public class RecommendationBuilder {
    ...

    public RecommendationBuilder setTitle(String title) {
            mTitle = title;
            return this;
        }

        public RecommendationBuilder setDescription(String description) {
            mDescription = description;
            return this;
        }

        public RecommendationBuilder setImage(String uri) {
            mImageUri = uri;
            return this;
        }

        public RecommendationBuilder setBackground(String uri) {
            mBackgroundUri = uri;
            return this;
        }
...

Creating the Notification

Once you've set the values, you then build the notification, assigning the values from the builder class to the notification, and calling NotificationCompat.Builder.build().
Also, be sure to call setLocalOnly() so the NotificationCompat.BigPictureStyle notification won't show up on other devices.
The following code example demonstrates how to build a recommendation.
public class RecommendationBuilder {
    ...

    public Notification build() throws IOException {
        ...

        Notification notification = new NotificationCompat.BigPictureStyle(
                new NotificationCompat.Builder(mContext)
                        .setContentTitle(mTitle)
                        .setContentText(mDescription)
                        .setPriority(mPriority)
                        .setLocalOnly(true)
                        .setOngoing(true)
                        .setColor(mContext.getResources().getColor(R.color.fastlane_background))
                        .setCategory(Notification.CATEGORY_RECOMMENDATION)
                        .setLargeIcon(image)
                        .setSmallIcon(mSmallIcon)
                        .setContentIntent(mIntent)
                        .setExtras(extras))
                .build();

        return notification;
    }
}

Run Recommendations Service


Your app's recommendation service must run periodically in order to create current recommendations. To run your service, create a class that runs a timer and invokes it at regular intervals. The following code example extends the BroadcastReceiver class to start periodic execution of a recommendation service every half hour:
public class BootupActivity extends BroadcastReceiver {
    private static final String TAG = "BootupActivity";

    private static final long INITIAL_DELAY = 5000;

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "BootupActivity initiated");
        if (intent.getAction().endsWith(Intent.ACTION_BOOT_COMPLETED)) {
            scheduleRecommendationUpdate(context);
        }
    }

    private void scheduleRecommendationUpdate(Context context) {
        Log.d(TAG, "Scheduling recommendations update");

        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent recommendationIntent = new Intent(context, UpdateRecommendationsService.class);
        PendingIntent alarmIntent = PendingIntent.getService(context, 0, recommendationIntent, 0);

        alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                INITIAL_DELAY,
                AlarmManager.INTERVAL_HALF_HOUR,
                alarmIntent);
    }
}
This implementation of the BroadcastReceiver class must run after start up of the TV device where it is installed. To accomplish this, register this class in your app manifest with an intent filter that listens for the completion of the device boot process. The following sample code demonstrates how to add this configuration to the manifest:
<manifest ... >
  <application ... >
    <receiver android:name="com.example.android.tvleanback.BootupActivity"
              android:enabled="true"
              android:exported="false">
      <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
      </intent-filter>
    </receiver>
  </application>
</manifest>
Important: Receiving a boot completed notification requires that your app requests theRECEIVE_BOOT_COMPLETED permission. For more information, see ACTION_BOOT_COMPLETED.
In your recommendation service class' onHandleIntent() method, post the recommendation to the manager as follows:
Notification notification = notificationBuilder.build();
mNotificationManager.notify(id, notification);

Making TV Apps Searchable

Android TV uses the Android search interface to retrieve content data from installed apps and deliver search results to the user. Your app's content data can be included with these results, to give the user instant access to the content in your app.
Your app must provide Android TV with the data fields from which it generates suggested search results as the user enters characters in the search dialog. To do that, your app must implement a Content Provider that serves up the suggestions along with a searchable.xml configuration file that describes the content provider and other vital information for Android TV. You also need an activity that handles the intent that fires when the user selects a suggested search result. All of this is described in more detail in Adding Custom Suggestions. Here are described the main points for Android TV apps.
This lesson builds on your knowledge of using search in Android to show you how to make your app searchable in Android TV. Be sure you are familiar with the concepts explained in the Search API guide before following this lesson. See also the trainingAdding Search Functionality.
This discussion describes some code from the Android Leanback sample app, available on GitHub.

Identify Columns


The SearchManager describes the data fields it expects by representing them as columns of an SQLite database. Regardless of your data's format, you must map your data fields to these columns, usually in the class that accessess your content data. For information about building a class that maps your existing data to the required fields, see Building a suggestion table.
The SearchManager class includes several columns for Android TV. Some of the more important columns are described below.
ValueDescription
SUGGEST_COLUMN_TEXT_1The name of your content (required)
SUGGEST_COLUMN_TEXT_2A text description of your content
SUGGEST_COLUMN_RESULT_CARD_IMAGEAn image/poster/cover for your content
SUGGEST_COLUMN_CONTENT_TYPEThe MIME type of your media (required)
SUGGEST_COLUMN_VIDEO_WIDTHThe resolution width of your media
SUGGEST_COLUMN_VIDEO_HEIGHTThe resolution height of your media
SUGGEST_COLUMN_PRODUCTION_YEARThe production year of your content (required)
SUGGEST_COLUMN_DURATIONThe duration in milliseconds of your media
The search framework requires the following columns:
When the values of these columns for your content match the values for the same content from other providers found by Google servers, the system provides a deep link to your app in the details view for the content, along with links to the apps of other providers. This is discussed more in Display Content in the Details Screen, below.
Your application's database class might define the columns as follows:
public class VideoDatabase {
  //The columns we'll include in the video database table
  public static final String KEY_NAME = SearchManager.SUGGEST_COLUMN_TEXT_1;
  public static final String KEY_DESCRIPTION = SearchManager.SUGGEST_COLUMN_TEXT_2;
  public static final String KEY_ICON = SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE;
  public static final String KEY_DATA_TYPE = SearchManager.SUGGEST_COLUMN_CONTENT_TYPE;
  public static final String KEY_IS_LIVE = SearchManager.SUGGEST_COLUMN_IS_LIVE;
  public static final String KEY_VIDEO_WIDTH = SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH;
  public static final String KEY_VIDEO_HEIGHT = SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT;
  public static final String KEY_AUDIO_CHANNEL_CONFIG =
          SearchManager.SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG;
  public static final String KEY_PURCHASE_PRICE = SearchManager.SUGGEST_COLUMN_PURCHASE_PRICE;
  public static final String KEY_RENTAL_PRICE = SearchManager.SUGGEST_COLUMN_RENTAL_PRICE;
  public static final String KEY_RATING_STYLE = SearchManager.SUGGEST_COLUMN_RATING_STYLE;
  public static final String KEY_RATING_SCORE = SearchManager.SUGGEST_COLUMN_RATING_SCORE;
  public static final String KEY_PRODUCTION_YEAR = SearchManager.SUGGEST_COLUMN_PRODUCTION_YEAR;
  public static final String KEY_COLUMN_DURATION = SearchManager.SUGGEST_COLUMN_DURATION;
  public static final String KEY_ACTION = SearchManager.SUGGEST_COLUMN_INTENT_ACTION;
...
When you build the map from the SearchManager columns to your data fields, you must also specify the _ID to give each row a unique ID.
...
  private static HashMap buildColumnMap() {
    HashMap map = new HashMap();
    map.put(KEY_NAME, KEY_NAME);
    map.put(KEY_DESCRIPTION, KEY_DESCRIPTION);
    map.put(KEY_ICON, KEY_ICON);
    map.put(KEY_DATA_TYPE, KEY_DATA_TYPE);
    map.put(KEY_IS_LIVE, KEY_IS_LIVE);
    map.put(KEY_VIDEO_WIDTH, KEY_VIDEO_WIDTH);
    map.put(KEY_VIDEO_HEIGHT, KEY_VIDEO_HEIGHT);
    map.put(KEY_AUDIO_CHANNEL_CONFIG, KEY_AUDIO_CHANNEL_CONFIG);
    map.put(KEY_PURCHASE_PRICE, KEY_PURCHASE_PRICE);
    map.put(KEY_RENTAL_PRICE, KEY_RENTAL_PRICE);
    map.put(KEY_RATING_STYLE, KEY_RATING_STYLE);
    map.put(KEY_RATING_SCORE, KEY_RATING_SCORE);
    map.put(KEY_PRODUCTION_YEAR, KEY_PRODUCTION_YEAR);
    map.put(KEY_COLUMN_DURATION, KEY_COLUMN_DURATION);
    map.put(KEY_ACTION, KEY_ACTION);
    map.put(BaseColumns._ID, "rowid AS " +
            BaseColumns._ID);
    map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " +
            SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
    map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, "rowid AS " +
            SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
    return map;
  }
...
In the example above, notice the mapping to the SUGGEST_COLUMN_INTENT_DATA_ID field. This is the portion of the URI that points to the content unique to the data in this row — that is, the last part of the URI describing where the content is stored. The first part of the URI, when it is common to all of the rows in the table, is set in thesearchable.xml file as the android:searchSuggestIntentData attribute, as described in Handle Search Suggestions, below.
If the first part of the URI is different for each row in the table, you map that value with theSUGGEST_COLUMN_INTENT_DATA field. When the user selects this content, the intent that fires provides the intent data from the combination of the SUGGEST_COLUMN_INTENT_DATA_ID and either theandroid:searchSuggestIntentData attribute or the SUGGEST_COLUMN_INTENT_DATA field value.

Provide Search Suggestion Data


Implement a Content Provider to return search term suggestions to the Android TV search dialog. The system queries your content provider for suggestions by calling the query() method each time a letter is typed. In your implementation of query(), your content provider searches your suggestion data and returns a Cursor that points to the rows you have designated for suggestions.
@Override
  public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                      String sortOrder) {
    // Use the UriMatcher to see what kind of query we have and format the db query accordingly
    switch (URI_MATCHER.match(uri)) {
      case SEARCH_SUGGEST:
          Log.d(TAG, "search suggest: " + selectionArgs[0] + " URI: " + uri);
          if (selectionArgs == null) {
              throw new IllegalArgumentException(
                      "selectionArgs must be provided for the Uri: " + uri);
          }
          return getSuggestions(selectionArgs[0]);
      default:
          throw new IllegalArgumentException("Unknown Uri: " + uri);
    }
  }

  private Cursor getSuggestions(String query) {
    query = query.toLowerCase();
    String[] columns = new String[]{
      BaseColumns._ID,
      VideoDatabase.KEY_NAME,
      VideoDatabase.KEY_DESCRIPTION,
      VideoDatabase.KEY_ICON,
      VideoDatabase.KEY_DATA_TYPE,
      VideoDatabase.KEY_IS_LIVE,
      VideoDatabase.KEY_VIDEO_WIDTH,
      VideoDatabase.KEY_VIDEO_HEIGHT,
      VideoDatabase.KEY_AUDIO_CHANNEL_CONFIG,
      VideoDatabase.KEY_PURCHASE_PRICE,
      VideoDatabase.KEY_RENTAL_PRICE,
      VideoDatabase.KEY_RATING_STYLE,
      VideoDatabase.KEY_RATING_SCORE,
      VideoDatabase.KEY_PRODUCTION_YEAR,
      VideoDatabase.KEY_COLUMN_DURATION,
      VideoDatabase.KEY_ACTION,
      SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID
    };
    return mVideoDatabase.getWordMatch(query, columns);
  }
...
In your manifest file, the content provider receives special treatment. Rather than getting tagged as an activity, it is described as a <provider>. The provider includes the android:searchSuggestAuthority attribute to tell the system the namespace of your content provider. Also, you must set its android:exported attribute to "true" so that the Android global search can use the results returned from it.
<provider android:name="com.example.android.tvleanback.VideoContentProvider"
    android:authorities="com.example.android.tvleanback"
    android:exported="true" />

Handle Search Suggestions


Your app must include a res/xml/searchable.xml file to configure the search suggestions settings. It inlcudes the android:searchSuggestAuthority attribute to tell the system the namespace of your content provider. This must match the string value you specify in the android:authorities attribute of the <provider> element in yourAndroidManifest.xml file.
The searchable.xml file must also include the android:searchSuggestIntentAction with the value"android.intent.action.VIEW" to define the intent action for providing a custom suggestion. This is different from the intent action for providing a search term, explained below. See also, Declaring the intent action for other ways to declare the intent action for suggestions.
Along with the intent action, your app must provide the intent data, which you specify with theandroid:searchSuggestIntentData attribute. This is the first part of the URI that points to the content. It describes the portion of the URI common to all rows in the mapping table for that content. The portion of the URI that is unique to each row is established with the SUGGEST_COLUMN_INTENT_DATA_ID field, as described above inIdentify Columns. See also, Declaring the intent data for other ways to declare the intent data for suggestions.
Also, note the android:searchSuggestSelection=" ?" attribute which specifies the value passed as theselection parameter of the query() method where the question mark (?) value is replaced with the query text.
Finally, you must also include the android:includeInGlobalSearch attribute with the value "true". Here is an example searchable.xml file:
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search_label"
        android:hint="@string/search_hint"
        android:searchSettingsDescription="@string/settings_description"
        android:searchSuggestAuthority="com.example.android.tvleanback"
        android:searchSuggestIntentAction="android.intent.action.VIEW"
        android:searchSuggestIntentData="content://com.example.android.tvleanback/video_database_leanback"
        android:searchSuggestSelection=" ?"
        android:searchSuggestThreshold="1"
        android:includeInGlobalSearch="true"
    >
</searchable>

Handle Search Terms


As soon as the search dialog has a word which matches the value in one of your app's columns (described inIdentifying Columns, above), the system fires the ACTION_SEARCH intent. The activity in your app which handles that intent searches the repository for columns with the given word in their values, and returns a list of content items with those columns. In your AndroidManifest.xml file, you designate the activity which handles theACTION_SEARCH intent like this:
...
  <activity
      android:name="com.example.android.tvleanback.DetailsActivity"
      android:exported="true">

      <!-- Receives the search request. -->
      <intent-filter>
          <action android:name="android.intent.action.SEARCH" />
          <!-- No category needed, because the Intent will specify this class component -->
      </intent-filter>

      <!-- Points to searchable meta data. -->
      <meta-data android:name="android.app.searchable"
          android:resource="@xml/searchable" />
  </activity>
...
  <!-- Provides search suggestions for keywords against video meta data. -->
  <provider android:name="com.example.android.tvleanback.VideoContentProvider"
      android:authorities="com.example.android.tvleanback"
      android:exported="true" />
...
The activity must also describe the searchable configuration with a reference to the searchable.xml file. To use the global search dialog, the manifest must describe which activity should receive search queries. The manifest must also describe the <provider> element, exactly as it is described in the searchable.xml file.

Deep Link to Your App in the Details Screen


If you have set up the search configuration as described in Handle Search Suggestions and mapped theSUGGEST_COLUMN_TEXT_1SUGGEST_COLUMN_CONTENT_TYPE, and SUGGEST_COLUMN_PRODUCTION_YEAR fields as described in Identify Columns, a deep link to a watch action for your content appears in the details screen that launches when the user selects a search result, as shown in figure 1.
Deep link in the details screen
Figure 1. The details screen displays a deep link for the Videos by Google (Leanback) sample app. Sintel: © copyright Blender Foundation, www.sintel.org.
When the user selects the link for your app, identified by the "Available On" button in the details screen, the system launches the activity which handles the ACTION_VIEW (set as android:searchSuggestIntentAction with the value "android.intent.action.VIEW" in the searchable.xml file).
You can also set up a custom intent to launch your activity, and this is demonstrated in the Android Leanback sample app. Note that the sample app launches its own LeanbackDetailsFragment to show the details for the selected media, but you should launch the activity that plays the media immediately to save the user another click or two.

Searching within TV Apps

Users frequently have specific content in mind when using a media app on TV. If your app contains a large catalog of content, browsing for a specific title may not be the most efficient way for users to find what they are looking for. A search interface can help your users get to the content they want faster than browsing.
The Leanback support library provides a set of classes to enable a standard search interface within your app that is consistent with other search functions on TV and provides features such as voice input.
This lesson discusses how to provide a search interface in your app using Leanback support library classes.

Add a Search Action


When you use the BrowseFragment class for a media browsing interface, you can enable a search interface as a standard part of the user interface. The search interface is an icon that appears in the layout when you setView.OnClickListener on the BrowseFragment object. The following sample code demonstrates this technique.
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.browse_activity);

    mBrowseFragment = (BrowseFragment)
            getFragmentManager().findFragmentById(R.id.browse_fragment);

    ...

    mBrowseFragment.setOnSearchClickedListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(BrowseActivity.this, SearchActivity.class);
            startActivity(intent);
        }
    });

    mBrowseFragment.setAdapter(buildAdapter());
}
Note: You can set the color of the search icon using the setSearchAffordanceColor(int).

Add a Search Input and Results


When a user selects the search icon, the system invokes a search activity via the defined intent. Your search activity should use a linear layout containing a SearchFragment. This fragment must also implement theSearchFragment.SearchResultProvider interface in order to display the results of a search.
The following code sample shows how to extend the SearchFragment class to provide a search interface and results:
public class MySearchFragment extends SearchFragment
        implements SearchFragment.SearchResultProvider {

    private static final int SEARCH_DELAY_MS = 300;
    private ArrayObjectAdapter mRowsAdapter;
    private Handler mHandler = new Handler();
    private SearchRunnable mDelayedLoad;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
        setSearchResultProvider(this);
        setOnItemClickedListener(getDefaultItemClickedListener());
        mDelayedLoad = new SearchRunnable();
    }

    @Override
    public ObjectAdapter getResultsAdapter() {
        return mRowsAdapter;
    }

    @Override
    public boolean onQueryTextChange(String newQuery) {
        mRowsAdapter.clear();
        if (!TextUtils.isEmpty(newQuery)) {
            mDelayedLoad.setSearchQuery(newQuery);
            mHandler.removeCallbacks(mDelayedLoad);
            mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
        }
        return true;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        mRowsAdapter.clear();
        if (!TextUtils.isEmpty(query)) {
            mDelayedLoad.setSearchQuery(query);
            mHandler.removeCallbacks(mDelayedLoad);
            mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS);
        }
        return true;
    }
}
The example code shown above is meant to be used with a separate SearchRunnable class that runs the search query on a separate thread. This technique keeps potentially slow-running queries from blocking the main user interface thread.

Building TV Games

The television screen presents a number of considerations that may be new to mobile game developers. These areas include its large size, its control scheme, and the fact that all players are viewing it simultaneously.

Display


The two main things to keep in mind when developing games for the TV screen are its nature as a shared display and the need to design your game for a landscape orientation.

Consider the shared display

A living-room TV poses design challenges for multiplayer games, in that all players can see everything. This issue is especially relevant to games (such as card games or strategy games) that rely on each player’s possession of hidden information.
Some mechanisms you can implement to address the problem of one player’s eavesdropping on another’s information are:
  • A blinder on the screen to help conceal information. For example, in a turn-based game like a word or card game, one player at a time might view the display. When the player finishes a move, the game allows him or her to cover the screen with a blinder that blocks anyone from viewing secret information. When the next player begins a turn, the blinder opens to reveal his or her own information.
  • A companion app, running on a phone or tablet, can enable a player to conceal information by serving as a second screen.

Support landscape display

A TV is always sideways: You can’t turn it, and there is no portrait orientation. Always design your TV games to be displayed in landscape mode.

Input Devices


TVs don't have touch interfaces, so it's even more important to get your controls right and make sure players find them intuitive and fun to use. Handling controllers also introduces some other issues to pay attention to, like keeping track of multiple controllers, and handling disconnects gracefully.

Support D-pad controls

Plan your control scheme around a directional pad (D-pad) control, since this control set is the default for Android TV devices. The player needs to be able to use a D-Pad in all aspects of the game—not just controlling core gameplay, but also navigating menus and ads. For this reason, you should also ensure that your Android TV game does not refer to a touch interface. For example, an Android TV game should not tell a player to "Tap here to continue."
How you shape the player's interaction with the controller can be key to achieving a great user experience:
  • Communicate Controller Requirements up Front. Use your Google Play description to communicate to the player any expectations about controllers. If a game is better suited to a gamepad with a joystick than one with only a D-pad, make this fact clear. A player who uses an ill-suited controller for a game is likely to have a subpar experience and penalize your game in the ratings.
  • Use Consistent Button Mapping. Intuitive and flexible button mapping is key to a good user experience. For example, you should adhere to accepted customs by using the A button to Accept, and the B button to Cancel. You can also offer flexibility in the form of remappability. For more information about button mapping, seeHandling Controller Actions.
  • Detect Controller Capabilities and Adjust Accordingly. Query the controller about its capabilities in order to optimize the match between controller and game. For example, you may intend for a player to steer an object by waving the controller in the air. If a player's controller lacks accelerometer and gyroscope hardware, however, waving will not work. So, your game should query the controller and if motion detection is not supported, switch over to an alternative, available control scheme. For more information about querying controller capabilities, see Supporting Controllers Across Android Versions.

Provide appropriate Back-button behavior

The Back button should never act as a toggle. For example, do not use it to both open and close a menu. It should only navigate backward, breadcrumb-style, through the previous screens the player has been on, for example: Game play > Game pause screen > Game main screen > Android home screen.
Since the Back button should only perform linear (backward) navigation, you may use the back button to leave an in-game menu (opened by a different button) and return to gameplay. For more information about design for navigation, see Navigation with Back and Up. To learn about implementation, refer to Providing Proper Back Navigation.

Use appropriate buttons

Not all game controllers provide Start, Search, or Menu buttons. Be sure your UI does not depend upon the use of these buttons.

Handle multiple controllers

When multiple players are playing a game, each with his or her own controller, it is important to map each player-controller pair. For information about how to implement controller-number identification, see Input Devices.

Handle controller disconnects

When a controller is disconnected in the middle of gameplay, the game should pause, and a dialog should appear prompting the disconnected player to reconnect his or her controller.
The dialog should also offer troubleshooting tips (for example, a pop-up dialog telling the player to "Check your Bluetooth connection"). For more information about implementing input-device support, see Handling Controller Actions. Specific information about Bluetooth connections is at Bluetooth.

Show controller instructions

If your game provides visual game control instructions, the controller image should be free of branding and include only buttons compatible with Android.
For sample images of an Android-compatible controller, download the Android TV Gamepad Template (ZIP). It includes a white controller on black background and a black controller on white background (shown in figure 1), as a PNG file and an Adobe® Illustrator® file.
Figure 1. Example controller instructions using the Android TV Gamepad Template (ZIP).

Manifest


There are a some special things games should include in the Android manifest.

Show your game on the home screen

The Android TV home screen displays games in a separate row from regular apps. To make your game appear in the list of games, set the android:isGame attribute to "true" in your app manifest's <application> tag. For example:
<application
    ...
    android:isGame="true"
    ...>

Declare support for game controllers

Games controllers may not be available or active for users of a TV device. In order to properly inform users that your game requires (or just supports) a game controller, you must include entries in the app manifest. If your game requires a game controller, you must include the following entry in your app manifest:
  <uses-feature android:name="android.hardware.gamepad"/>
If your game uses, but does not require, a game controller, include the following feature entry in your app manifest:
  <uses-feature android:name="android.hardware.gamepad" android:required="false"/>
For more information about manifest entries, see App Manifest.

Google Play Game Services


If your game integrates Google Play Game services, you should keep in mind a number of considerations pertaining to achievements, sign-in, saving games, and multiplayer play.

Achievements

Your game should include at least five (earnable) achievements. Only a user controlling gameplay from a supported input device should be able to earn achievements. For more information about achievements and how to implement them, see Achievements in Android.

Sign-in

Your game should attempt to sign the user in on launch. If the player declines sign-in several times in a row, your game should stop asking. Learn more about sign-in at Implementing Sign-in on Android.

Saving

Use Google Play Services Saved Games to store your game save. Your game should bind game saves to a specific Google account, so as to be uniquely identifiable even across devices: Whether the player is using a handset or a TV, the game should be able to pull the game-save information from the same user account.
You should also provide an option in your game's UI to allow the player to delete locally and cloud-stored data. You might put the option in the game's Settings screen. For specifics on implementing saved games using Play Services, see Saved Games in Android.

Multiplayer experience

A game offering a multiplayer experience must allow at least two players to enter a room. For further information about multiplayer games in Android, see the Real-time Multiplayer and Turn-based Multiplayer documentation on the Android developer site.

Exit

Provide a consistent and obvious UI element that lets the user exit the game gracefully. This element should be accessible with the D-pad navigation buttons. Do this instead of relying on the Home button to provide an exit, as that is not consistent nor reliable across different controllers.

Web


Do not enable web browsing in games for Android TV. Android TV does not support a web browser.
Note: You can use the WebView class for logins to services like Google+ and Facebook.

Networking


Games frequently need greater bandwidth to provide optimum performance, and many users prefer ethernet to WiFi to provide that performance. Your app should check for both WiFi and ethernet connections. If your app is for TV only, you do not need to check for 3G/LTE service as you would for a mobile app.

No comments:

Post a Comment