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

Java tutorial

Introduction

Here is the source code for com.groundupworks.wings.gcp.GoogleCloudPrintSettingsActivity.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.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.Toast;

import com.dpsmarques.android.account.activity.AccountSelectionActivityHelper;
import com.dpsmarques.android.auth.GoogleOauthTokenObservable;
import com.dpsmarques.android.auth.activity.OperatorGoogleAuthenticationActivityController;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.github.dpsm.android.print.GoogleCloudPrint;
import com.github.dpsm.android.print.jackson.JacksonPrinterSearchResultOperator;
import com.github.dpsm.android.print.jackson.model.JacksonPrinterSearchResult;
import com.github.dpsm.android.print.model.Printer;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.internal.spi.json.JacksonJsonProvider;
import com.jayway.jsonpath.internal.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.json.JsonProvider;
import com.jayway.jsonpath.spi.mapper.MappingProvider;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import retrofit.client.Response;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;

/**
 * {@link android.app.Activity} to select a Google Cloud printer.
 *
 * @author David Marques
 */
public class GoogleCloudPrintSettingsActivity extends Activity
        implements AccountSelectionActivityHelper.AccountSelectionListener,
        OperatorGoogleAuthenticationActivityController.GoogleAuthenticationListener {

    private static final String GOOGLE_PRINT_SCOPE = "oauth2:https://www.googleapis.com/auth/cloudprint";

    private static final String[] ACCOUNT_TYPE = new String[] { "com.google" };

    private static final JsonPath OPTIONS_JSON_PATH;

    static {
        Configuration.setDefaults(new Configuration.Defaults() {

            private final JsonProvider jsonProvider = new JacksonJsonProvider();

            @Override
            public JsonProvider jsonProvider() {
                return jsonProvider;
            }

            @Override
            public MappingProvider mappingProvider() {
                return new JacksonMappingProvider();
            }

            @Override
            public Set<Option> options() {
                return EnumSet.noneOf(Option.class);
            }
        });

        OPTIONS_JSON_PATH = JsonPath.compile("$.printers[*].capabilities.printer.media_size.option[*]");
    }

    static final String EXTRA_ACCOUNT = "account";
    static final String EXTRA_PRINTER = "printer";
    static final String EXTRA_PRINTER_NAME = "printer_name";
    static final String EXTRA_TOKEN = "token";
    static final String EXTRA_MEDIA = "media";

    private static final int REQUEST_CODE_BASE = 1000;

    private final Action1<Throwable> mShowPrinterNotFoundAction = new Action1<Throwable>() {
        @Override
        public void call(final Throwable throwable) {
            Toast.makeText(getApplicationContext(), R.string.wings_gcp__settings__error_no_printer,
                    Toast.LENGTH_SHORT).show();
        }
    };

    private GoogleCloudPrint mGoogleCloudPrint;
    private AccountSelectionActivityHelper mAccountSelectionHelper;
    private OperatorGoogleAuthenticationActivityController mAuthenticationHelper;

    private Observable<String> mOauthObservable;
    private String mAccountSelected;
    private String mAuthenticationToken;

    private Button mSelectPrinterButton;
    private Spinner mPrinterSpinner;
    private Spinner mMediaSpinner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gcp_activity_settings);

        mAuthenticationHelper = new OperatorGoogleAuthenticationActivityController(this, REQUEST_CODE_BASE + 100);
        mAccountSelectionHelper = new AccountSelectionActivityHelper(this, REQUEST_CODE_BASE);
        mGoogleCloudPrint = new GoogleCloudPrint();

        mSelectPrinterButton = (Button) findViewById(R.id.gcp_activity_settings_button_link);
        mPrinterSpinner = (Spinner) findViewById(R.id.gcp_activity_settings_spinner_printers);
        mPrinterSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
                onPrinterSelected(position);
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {

            }
        });

        mMediaSpinner = (Spinner) findViewById(R.id.gcp_activity_settings_spinner_media_sizes);

        mSelectPrinterButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View view) {
                final Printer selectedPrinter = (Printer) mPrinterSpinner.getSelectedItem();
                final MediaSize selectedMedia = (MediaSize) mMediaSpinner.getSelectedItem();
                if (selectedPrinter != null) {
                    final String id = selectedPrinter.getId();
                    final String account = mAccountSelected;
                    final String token = mAuthenticationToken;
                    if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(account) && !TextUtils.isEmpty(token)) {
                        final Intent intent = new Intent();
                        intent.putExtra(EXTRA_PRINTER, id);
                        intent.putExtra(EXTRA_PRINTER_NAME, selectedPrinter.getName());
                        intent.putExtra(EXTRA_ACCOUNT, account);
                        intent.putExtra(EXTRA_TOKEN, token);
                        if (selectedMedia != null) {
                            intent.putExtra(EXTRA_MEDIA, selectedMedia.id);
                        }

                        setResult(Activity.RESULT_OK, intent);
                        finish();
                    }
                }
            }
        });
    }

    private void onPrinterSelected(final int position) {
        mMediaSpinner.setVisibility(View.GONE);
        final Printer printer = (Printer) mPrinterSpinner.getAdapter().getItem(position);
        mOauthObservable.subscribe(new Action1<String>() {
            @Override
            public void call(final String token) {
                getPrinterDetails(token, printer.getId()).subscribe(new Action1<Response>() {
                    @Override
                    public void call(Response response) {
                        onPrinterDetails(response);
                    }
                }, mShowPrinterNotFoundAction);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        mAccountSelectionHelper.selectUserAccount(ACCOUNT_TYPE);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (mAccountSelectionHelper.handleActivityResult(requestCode, resultCode, data)) {
            return; // Handled by helper.
        }
        if (mAuthenticationHelper.handleActivityResult(requestCode, resultCode, data)) {
            return; // Handled by helper.
        }
    }

    @Override
    public void onAccountSelected(final String accountName) {
        mAccountSelected = accountName;
        mOauthObservable = GoogleOauthTokenObservable.create(this, accountName, GOOGLE_PRINT_SCOPE)
                .authenticateUsing(this, REQUEST_CODE_BASE).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());

        findPrinters();
    }

    @Override
    public void onAccountSelectionCanceled() {
        setResult(Activity.RESULT_CANCELED);
        finish();
    }

    @Override
    public void onAuthenticationError(final Throwable throwable) {
        Toast.makeText(getApplicationContext(), R.string.wings_gcp__settings__error_authenticate,
                Toast.LENGTH_SHORT).show();

        setResult(Activity.RESULT_CANCELED);
        finish();
    }

    @Override
    public void onAuthenticationSucceeded(final String token) {
        mAuthenticationToken = token;
    }

    @Override
    public void onRetryAuthentication() {
        Toast.makeText(getApplicationContext(), R.string.wings_gcp__settings__error_authenticate,
                Toast.LENGTH_SHORT).show();

        setResult(Activity.RESULT_CANCELED);
        finish();
    }

    /**
     * Finds printers associated with the account.
     */
    private void findPrinters() {
        mOauthObservable.subscribe(new Action1<String>() {
            @Override
            public void call(final String token) {
                searchPrinters(token).subscribe(new Action1<JacksonPrinterSearchResult>() {
                    @Override
                    public void call(JacksonPrinterSearchResult result) {
                        onPrinterSearchResult(result);
                    }
                }, mShowPrinterNotFoundAction);
            }
        });
    }

    private Observable<JacksonPrinterSearchResult> searchPrinters(final String token) {
        return mGoogleCloudPrint.getPrinters(token).lift(new JacksonPrinterSearchResultOperator())
                .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
    }

    private Observable<Response> getPrinterDetails(final String token, final String printerId) {
        return mGoogleCloudPrint.getPrinter(token, printerId, true, null).observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io());
    }

    private void onPrinterSearchResult(final JacksonPrinterSearchResult result) {
        final List<Printer> printers = result.getPrinters();
        if (printers != null && printers.size() > 0) {
            mPrinterSpinner.setAdapter(new ArrayAdapter<Printer>(GoogleCloudPrintSettingsActivity.this,
                    R.layout.gcp_settings_spinner_item, R.id.activity_main_spinner_item_text, printers));
        } else {
            Toast.makeText(getApplicationContext(), R.string.wings_gcp__settings__error_no_printer,
                    Toast.LENGTH_SHORT).show();
        }
    }

    private void onPrinterDetails(final Response response) {
        if (response.getStatus() == HttpURLConnection.HTTP_OK) {
            final List<MediaSize> sizes = parseMediaSizes(response);
            final boolean hasMediaSize = !sizes.isEmpty();
            if (hasMediaSize) {
                mMediaSpinner.setAdapter(new ArrayAdapter<MediaSize>(GoogleCloudPrintSettingsActivity.this,
                        R.layout.gcp_settings_spinner_item, R.id.activity_main_spinner_item_text, sizes));
            }
            mMediaSpinner.setVisibility(hasMediaSize ? View.VISIBLE : View.GONE);
        }
    }

    private List<MediaSize> parseMediaSizes(Response response) {
        final List<MediaSize> mediaSizes = new LinkedList<MediaSize>();
        try {
            mediaSizes.addAll(JsonPath.parse(response.getBody().in()).read(OPTIONS_JSON_PATH, MediaSizeList.class));
        } catch (IOException e) {
            // Do nothing.
        }
        return mediaSizes;
    }

    static class MediaSizeList extends ArrayList<MediaSize> {
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    static class MediaSize {

        @JsonProperty("custom_display_name")
        String name;

        @JsonProperty("vendor_id")
        String id;

        @Override
        public String toString() {
            return name;
        }
    }
}