Hide
Google Play Game Services

Game Gifting in Android

To make gameplay more collaborative and improve social engagement, your game can allow players to send and request gifts of in-game resources or items by using the game gifts API. Your game can display a built-in user interface (UI) provided by Play Game services that makes it easy for players to send and request gifts for in-game items and resources to friends in their Google+ circles. Request recipients receive notifications on all devices on which the recipients are logged in (unless notifications is disabled).

The game gifts API in Play Game services is also flexible enough that your game can use it to allow players to negotiate and trade for items with each other.

Before you begin

Before you start to use the game gifts API:

  • Download and review the game gifts code sample from the Downloads page.
  • You should also familiarize yourself with the recommendations described in Quality Checklist.

Once the player is signed in and the GoogleApiClient is connected, your game can start using the game gifts API.

Game gifts basics

There are two types of requests that players can send using the game gifts feature in Play Game services:

  • A wish request to ask for in-game items or some other tangible form of assistance from their friends.
  • A gift request to send in-game items or some other tangible form of assistance to their friends; for example, players can gift "lives" to each other to extend gameplay.

A player can specify one or more target request recipients from the default request sending UI. A gift or wish can be consumed (that is, accepted by a recipient) or dismissed by a recipient. Each request can be consumed only once. Requests expire after a period of time if they are not consumed.

A request has the following key properties:

Name Description Notes
Type Indicates whether the request is a gift or a wish.
  • Gift. Use this request type if sending an in-game item or other tangible form of assistance to another player.
  • Wish. Use this request type if requesting an in-game item or other tangible form of assistance from another player.
Developer-defined.
Payload A byte array that contains data to send with the request. You can find the maximum size available for the payload by calling getMaxPayloadSize(). Developer-defined.
Request lifetime Indicates how long (in days) the request should persist if the recipient takes no action. This value must be in the range of 1 to 14 days (inclusive). After this time elapses, the request may be deleted by Play Game services at any time. Developer-defined.
Icon A bitmap that is displayed as the request icon. Developer-defined.
Description A string that is displayed in the request sending UI to provide additional context for the request. Developer-defined.
ID A unique ID for the request. Set by Play Game services.
Sender Information about the player that sent the request. Set by Play Game services.
Creation timestamp The server timestamp when the request was created. Set by Play Game services.
Expiration timestamp The server timestamp after which the request is eligible for deletion by Play Game services. Set by Play Game services.
Recipient status Indicates whether the request has been accepted or is pending. Note that if a request is dismissed by a recipient, the sender will only see the recipient status as RECIPIENT_STATUS_PENDING. Set by Play Game services.

Sending a request

To send a gift or wish request, follow these steps:

  1. Call getSendIntent() to bring up the default request sending UI so that the player can select a recipient for the request. In the call, you must specify the request type (TYPE_GIFT or TYPE_WISH). You can use the payload input parameter to provide additional data in byte array format to indicate what game-specific items are being requested or sent. The payload can be empty, as shown in the snippet below.

    Intent intent = Games.Requests.getSendIntent(client, type,
                "".getBytes(), DEFAULT_LIFETIME, icon, description);
    
  2. Next, call startActivityForResult() and pass in the Intent returned by getSendIntent(), along with a developer-defined request code. If the call is successful, the user sees the default request sending UI.

    startActivityForResult(intent, SEND_GIFT_CODE);
    
  3. After the user selects one or more request recipients from the UI, the request is sent by the game gifts API to the Play Game services. Play Game services then creates a GameRequest object to represent the request and routes this request object to the target recipient. To learn how your game can accept an incoming request, see Handling requests. In your game, you can override onActivityResult() to check if any errors occurred during the sending of the request.

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case SEND_REQUEST_CODE:
                if (resultCode == GamesActivityResultCodes.RESULT_SEND_REQUEST_FAILED) {
                   Toast.makeText(this, "FAILED TO SEND REQUEST!", Toast.LENGTH_LONG).show();
                }
                break;
            case SEND_GIFT_CODE:
                if (resultCode == GamesActivityResultCodes.RESULT_SEND_REQUEST_FAILED) {
                   Toast.makeText(this, "FAILED TO SEND GIFT!", Toast.LENGTH_LONG).show();
                }
                break;
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
    

Launching your game from a request notification

By default, request recipients will see a notification appear on their devices when they receive a request from friends in their Google+ circles. If the recipient already has your game installed on the device, the recipient can simply expand and click on the notification to launch a UI to select whether to accept the request. After the recipient makes this selection, the system automatically launches your game.

Next, your game should retrieve the list of requests that the recipient selected. The list of requests are represented as GameRequest objects stored in the connectionHint from the connection bundle that your game receives from the onConnected() callback.

ArrayList <GameRequest> mRequests
        = Games.Requests.getGameRequestsFromBundle(connectionHint);

Your game should programmatically accept requests that are returned in the connectionHint. To learn how to automatically accept requests, see step 2 in Handling a request programatically.

Handling requests

You can register an OnRequestReceivedListener in your game if you want your game activity to be notified when inbound requests arrive. If your game uses OnRequestReceivedListener, users will not receive the standard requests notification on their devices. Instead, your game can provide an option to launch an inbox UI for users to view requests they have received and select whether to accept the requests. You can also have your game handle the inbound request programmatically.

To register the OnRequestReceivedListener, call registerRequestListener() and pass in the GoogleApiClient for your game and the instance of the request listener.

private OnRequestReceivedListener mRequestListener
        = new OnRequestReceivedListener() {
    @Override
    public void onRequestReceived(GameRequest request) {
        int requestStringResource;
        switch (request.getType()) {
            case GameRequest.TYPE_GIFT:
                requestStringResource = R.string.new_gift_received;
                break;
            case GameRequest.TYPE_WISH:
                requestStringResource = R.string.new_request_received;
                break;
            default:
                return;
        }
        Toast.makeText(MainActivity.this, requestStringResource,
                Toast.LENGTH_LONG).show();
        updateRequestCounts();
    }

    @Override
    public void onRequestRemoved(String requestId) {
        // Handle removal of incoming request; for example, if the sending
        // user cancelled the request.
    }
};

@Override
public void onConnected(Bundle connectionHint) {
    // Sign-in worked!
    // Show sign-out button or other UI

    // This is *NOT* required; if you do not register a handler for
    // request events, you will get standard notifications instead.
    Games.Requests.registerRequestListener(mGoogleApiClient,
            mRequestListener);

    // Our sample displays the request counts.
    updateRequestCounts();
}

Handling requests using the default inbox UI

Your game can bring up the default inbox UI provided by the SDK to let request recipients view a list of all the inbound requests that are waiting to be accepted. Recipients can then select whether to accept a request. To display the inbox UI, call getInboxIntent() to retrieve an Intent for launching the inbox UI, then call startActivityForResult() and pass in that Intent.

startActivityForResult(Games.Requests.getInboxIntent(mGoogleApiClient), SHOW_INBOX);

If the call is successful, the game displays the default inbox UI and prompts recipients to select the inbound requests that they want to accept. The recipient's selection is then returned as an Intent that your game can retrieve from the onActivityResult() callback.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case SHOW_INBOX:
            if (resultCode == Activity.RESULT_OK && data != null) {
                handleInboxResult(Games.Requests
                        .getGameRequestsFromInboxResponse(data));
            } else {
                // handle failure to process inbox result
                ...
            }
            break;
    }
    super.onActivityResult(requestCode, resultCode, data);
}

Handling requests programmatically

Your game can also accept requests programmatically. You might use this approach, for example, to display a custom request UI in your game after the user signs in. If your game uses a custom UI, make sure that it presents users with an option to accept the request and a separate option to dismiss the request.

To accept requests programmatically, follow these steps:

  1. In the onConnected() callback, retrieve the list of pending requests from the Bundle argument:

    @Override
    public void onConnected(Bundle connectionHint) {
        // ...
    
        ArrayList <GameRequest> mRequests
                = Games.Requests.getGameRequestsFromBundle(connectionHint);
    }
    
  2. Call the acceptRequests() and pass in the list of request IDs from the GameRequest objects in the ArrayList. Alternatively, your game can call the dismissRequests() method to dismiss the requests instead of accepting them. If there is only one request to act on, your game should call acceptRequest() or dismissRequest() instead.

    private void handleRequests(ArrayList<GameRequest> requests) {
        if (requests == null) {
            return;
        }
    
        // Attempt to accept these requests.
        ArrayList<String> requestIds = new ArrayList<String>();
    
        /**
         * Map of cached game request ID to its corresponding game request
         * object.
         */
         final HashMap<String, GameRequest> gameRequestMap
                 = new HashMap<String, GameRequest>();
    
        // Cache the requests.
        for (GameRequest request : requests) {
            String requestId = request.getRequestId();
            requestIds.add(requestId);
            gameRequestMap.put(requestId, request);
        }
    
        // Accept the requests.
        Games.Requests.acceptRequests(mGoogleApiClient, requestIds).setResultCallback(
                new ResultCallback<UpdateRequestsResult>() {
            @Override
            public void onResult(UpdateRequestsResult result) {
                // Scan each result outcome and process accordingly.
                for (String requestId : result.getRequestIds()) {
                    // We must have a local cached copy of the request
                    // and the request needs to be a
                    // success in order to continue.
                    if (!gameRequestMap.containsKey(requestId)
                            || result.getRequestOutcome(requestId)
                            != Requests.REQUEST_UPDATE_OUTCOME_SUCCESS) {
                        continue;
                    }
                    // Update succeeded here. Find the type of request
                    // and act accordingly. For wishes, a
                    // responding gift will be automatically sent.
                    switch (gameRequestMap.get(requestId).getType()) {
                        case GameRequest.TYPE_GIFT:
                            // Process the game gifts request
                            ...
                            break;
                        case GameRequest.TYPE_WISH:
                            // Process the wish request
                            ...
                            break;
                    }
                }
            }
        });
    }