com.groundupworks.wings.gcp.GoogleCloudPrintEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for com.groundupworks.wings.gcp.GoogleCloudPrintEndpoint.java

Source

/*
 * Copyright (C) 2014 David Marques
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.groundupworks.wings.gcp;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.widget.Toast;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.groundupworks.android.print.GoogleCloudPrint;
import com.groundupworks.wings.WingsEndpoint;
import com.groundupworks.wings.core.Destination;
import com.groundupworks.wings.core.ShareRequest;
import com.jayway.jsonpath.JsonPath;
import com.squareup.otto.Produce;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

import retrofit.client.Response;
import retrofit.mime.TypedFile;

import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_ACCOUNT;
import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_COPIES;
import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_MEDIA_HEIGHT_MICRONS;
import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_MEDIA_IS_CONTINUOUS_FEED;
import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_MEDIA_VENDOR_ID;
import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_MEDIA_WIDTH_MICRONS;
import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_PRINTER;
import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_PRINTER_NAME;
import static com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.EXTRA_TOKEN;

/**
 * The Wings endpoint for Google Cloud Print.
 *
 * @author David Marques
 */
public class GoogleCloudPrintEndpoint extends WingsEndpoint {

    private static final String TICKET_WITH_MEDIA = "{\n" + "  \"version\": \"1.0\",\n" + "  \"print\": {\n"
            + "    \"vendor_ticket_item\": [],\n" + "    \"copies\": {\"copies\": %s},\n"
            + "    \"media_size\": {\n" + "      \"vendor_id\" : \"%s\",\n" + "      \"width_microns\": %s,\n"
            + "      \"height_microns\": %s,\n" + "      \"is_continuous_feed\": %s,\n" + "    }\n" + "  }\n" + "}";

    private static final String TICKET = "{\n" + "  \"version\": \"1.0\",\n" + "  \"print\": {\n"
            + "    \"vendor_ticket_item\": [],\n" + "    \"copies\": {\"copies\": %s}\n" + "  }\n" + "}";

    /**
     * Google Cloud Print endpoint id.
     */
    private static final int ENDPOINT_ID = 2;

    private static final int REQUEST_CODE = ENDPOINT_ID;

    private static final String MIME_TYPE = "image/jpeg";

    private final GoogleCloudPrint mGoogleCloudPrint = new GoogleCloudPrint();

    @Override
    public int getEndpointId() {
        return ENDPOINT_ID;
    }

    @Override
    public void startLinkRequest(final Activity activity, final Fragment fragment) {
        if (fragment != null) {
            fragment.startActivityForResult(new Intent(activity, GoogleCloudPrintSettingsActivity.class),
                    REQUEST_CODE);
        } else {
            activity.startActivityForResult(new Intent(activity, GoogleCloudPrintSettingsActivity.class),
                    REQUEST_CODE);
        }
    }

    @Override
    public void unlink() {
        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
        editor.putBoolean(mContext.getString(R.string.wings_gcp__link_key), false);
        editor.remove(mContext.getString(R.string.wings_gcp__account_name_key));
        editor.remove(mContext.getString(R.string.wings_gcp__printer_identifier_key));
        editor.remove(mContext.getString(R.string.wings_gcp__token));
        editor.remove(mContext.getString(R.string.wings_gcp__copies));
        editor.remove(mContext.getString(R.string.wings_gcp__media_vendor_id));
        editor.remove(mContext.getString(R.string.wings_gcp__media_width_microns));
        editor.remove(mContext.getString(R.string.wings_gcp__media_height_microns));
        editor.remove(mContext.getString(R.string.wings_gcp__media_is_continuous_feed));
        editor.apply();

        // Emit link state change event.
        notifyLinkStateChanged(new LinkEvent(false));

        // Remove existing share requests in a background thread.
        mHandler.post(new Runnable() {

            @Override
            public void run() {
                mDatabase.deleteShareRequests(new Destination(DestinationId.PRINT_QUEUE, ENDPOINT_ID));
            }
        });
    }

    @Override
    public boolean isLinked() {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        return preferences.getBoolean(mContext.getString(R.string.wings_gcp__link_key), false);
    }

    @Override
    public void onResumeImpl() {
        // Do nothing.
    }

    @Override
    public void onActivityResultImpl(final Activity activity, final Fragment fragment, final int requestCode,
            final int resultCode, final Intent data) {
        if (requestCode == REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                String accountName = data.getStringExtra(EXTRA_ACCOUNT);
                String printerIdentifier = data.getStringExtra(EXTRA_PRINTER);
                String printerName = data.getStringExtra(EXTRA_PRINTER_NAME);
                String token = data.getStringExtra(EXTRA_TOKEN);
                String copies = data.getStringExtra(EXTRA_COPIES);
                String mediaVendorId = data.getStringExtra(EXTRA_MEDIA_VENDOR_ID);
                String mediaWidthMicrons = data.getStringExtra(EXTRA_MEDIA_WIDTH_MICRONS);
                String mediaHeightMicrons = data.getStringExtra(EXTRA_MEDIA_HEIGHT_MICRONS);
                String mediaIsContinuousFeed = data.getStringExtra(EXTRA_MEDIA_IS_CONTINUOUS_FEED);

                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(printerIdentifier)
                        && !TextUtils.isEmpty(token)) {
                    SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(mContext)
                            .edit();
                    editor.putBoolean(mContext.getString(R.string.wings_gcp__link_key), true);
                    editor.putString(mContext.getString(R.string.wings_gcp__account_name_key), accountName);
                    editor.putString(mContext.getString(R.string.wings_gcp__printer_identifier_key),
                            printerIdentifier);
                    editor.putString(mContext.getString(R.string.wings_gcp__printer_name_key), printerName);
                    editor.putString(mContext.getString(R.string.wings_gcp__token), token);
                    editor.putString(mContext.getString(R.string.wings_gcp__copies), copies);
                    editor.putString(mContext.getString(R.string.wings_gcp__media_vendor_id), mediaVendorId);
                    editor.putString(mContext.getString(R.string.wings_gcp__media_width_microns),
                            mediaWidthMicrons);
                    editor.putString(mContext.getString(R.string.wings_gcp__media_height_microns),
                            mediaHeightMicrons);
                    editor.putString(mContext.getString(R.string.wings_gcp__media_is_continuous_feed),
                            mediaIsContinuousFeed);
                    editor.apply();

                    // Emit link state change event.
                    notifyLinkStateChanged(new LinkEvent(true));
                } else {
                    Toast.makeText(mContext, mContext.getString(R.string.wings_gcp__error_link), Toast.LENGTH_SHORT)
                            .show();
                    unlink();
                }
            } else {
                Toast.makeText(mContext, mContext.getString(R.string.wings_gcp__error_link), Toast.LENGTH_SHORT)
                        .show();
                unlink();
            }
        }
    }

    @Override
    public LinkInfo getLinkInfo() {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        String accountName = preferences.getString(mContext.getString(R.string.wings_gcp__account_name_key), null);
        String printerIdentifier = preferences.getString(mContext.getString(R.string.wings_gcp__printer_name_key),
                null);
        if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(printerIdentifier)) {
            String destinationDescription = mContext.getString(R.string.wings_gcp__destination_description,
                    accountName, printerIdentifier);
            return new LinkInfo(accountName, DestinationId.PRINT_QUEUE, destinationDescription);
        }
        return null;
    }

    @Override
    public Set<ShareNotification> processShareRequests() {
        final Set<ShareNotification> notifications = new HashSet<ShareNotification>();
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext);
        int shareCount = 0;

        final boolean isLinked = preferences.getBoolean(mContext.getString(R.string.wings_gcp__link_key), false);
        final String accountName = preferences.getString(mContext.getString(R.string.wings_gcp__account_name_key),
                null);
        final String printerIdentifier = preferences
                .getString(mContext.getString(R.string.wings_gcp__printer_identifier_key), null);
        final String token = preferences.getString(mContext.getString(R.string.wings_gcp__token), null);
        final String copies = preferences.getString(mContext.getString(R.string.wings_gcp__copies), null);
        final String mediaVendorId = preferences.getString(mContext.getString(R.string.wings_gcp__media_vendor_id),
                null);
        final String mediaWidthMicrons = preferences
                .getString(mContext.getString(R.string.wings_gcp__media_width_microns), null);
        final String mediaHeightMicrons = preferences
                .getString(mContext.getString(R.string.wings_gcp__media_height_microns), null);
        final String mediaIsContinuousFeed = preferences
                .getString(mContext.getString(R.string.wings_gcp__media_is_continuous_feed), null);
        if (isLinked && !TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(printerIdentifier)
                && !TextUtils.isEmpty(token)) {
            final String ticket = !TextUtils.isEmpty(mediaVendorId) ? String.format(TICKET_WITH_MEDIA, copies,
                    mediaVendorId, mediaWidthMicrons, mediaHeightMicrons, mediaIsContinuousFeed)
                    : String.format(TICKET, copies);
            final Destination destination = new Destination(DestinationId.PRINT_QUEUE, ENDPOINT_ID);
            List<ShareRequest> shareRequests = mDatabase.checkoutShareRequests(destination);
            for (ShareRequest shareRequest : shareRequests) {
                File file = new File(shareRequest.getFilePath());
                if (file.exists()) {
                    try {
                        Response response = mGoogleCloudPrint.submitPrintJob(token, printerIdentifier,
                                file.getName(), ticket, new TypedFile(MIME_TYPE, file), MIME_TYPE).toBlocking()
                                .first();
                        final HashMap<String, String> parameters = new HashMap<>();
                        if (response.getStatus() == HttpURLConnection.HTTP_OK) {
                            try {
                                final GcpResponse gcpResponse = JsonPath.parse(response.getBody().in()).read("$",
                                        GcpResponse.class);
                                if (gcpResponse != null) {
                                    parameters.put("message", gcpResponse.message);
                                    if (gcpResponse.hasSucceeded) {
                                        mDatabase.markSuccessful(shareRequest.getId());
                                        shareCount++;
                                        sLogger.log("gcp_queue_success", parameters);
                                    } else {
                                        mDatabase.markFailed(shareRequest.getId());
                                        sLogger.log("gcp_queue_failed", parameters);
                                    }
                                } else {
                                    mDatabase.markFailed(shareRequest.getId());
                                    sLogger.log("gcp_response_parsing_failed", parameters);
                                }
                            } catch (IOException e) {
                                mDatabase.markFailed(shareRequest.getId());
                                parameters.put("error", e.getMessage());
                                sLogger.log("gcp_queue_failed", parameters);
                            }
                        } else {
                            mDatabase.markFailed(shareRequest.getId());
                            parameters.put("code", String.valueOf(response.getStatus()));
                            sLogger.log("gcp_queue_failed", parameters);
                        }
                    } catch (NoSuchElementException e) {
                        mDatabase.markFailed(shareRequest.getId());
                    }
                } else {
                    mDatabase.markFailed(shareRequest.getId());
                }
            }

            final HashMap<String, String> parameters = new HashMap<>();
            parameters.put("count", String.valueOf(shareCount));
            sLogger.log("gcp_shared", parameters);

            // Create and add notification.
            if (shareCount > 0) {
                final int count = shareCount;
                ShareNotification notification = new ShareNotification() {

                    @Override
                    public int getId() {
                        return destination.getHash();
                    }

                    @Override
                    public String getTitle() {
                        return mContext.getString(R.string.wings_gcp__notification_shared_title);
                    }

                    @Override
                    public String getMessage() {
                        String msg;
                        if (count == 1) {
                            msg = mContext.getString(R.string.wings_gcp__notification_shared_msg_single,
                                    printerIdentifier);
                        } else {
                            msg = mContext.getString(R.string.wings_gcp__notification_shared_msg_multi, count,
                                    printerIdentifier);
                        }
                        return msg;
                    }

                    @Override
                    public String getTicker() {
                        return mContext.getString(R.string.wings_gcp__notification_shared_ticker);
                    }

                    @Override
                    public Intent getIntent() {
                        return new Intent();
                    }
                };

                notifications.add(notification);
            }
        }

        return notifications;
    }

    @Override
    @Produce
    public GoogleCloudPrintEndpoint.LinkEvent produceLinkEvent() {
        return new LinkEvent(isLinked());
    }

    //
    // Public interfaces and classes.
    //

    /**
     * The list of destination ids.
     */
    public interface DestinationId extends WingsEndpoint.DestinationId {

        /**
         * The GCP print queue.
         */
        int PRINT_QUEUE = 0;
    }

    /**
     * The link event implementation associated with this endpoint.
     */
    public static class LinkEvent extends WingsEndpoint.LinkEvent {

        /**
         * Private constructor.
         *
         * @param isLinked true if current link state for this endpoint is linked; false otherwise.
         */
        private LinkEvent(boolean isLinked) {
            super(GoogleCloudPrintEndpoint.class, isLinked);
        }
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class GcpResponse {

        @JsonProperty("success")
        boolean hasSucceeded;

        @JsonProperty("message")
        String message;

    }
}