com.esri.arcgisruntime.sample.exporttiles.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.esri.arcgisruntime.sample.exporttiles.MainActivity.java

Source

/* Copyright 2017 Esri
 *
 * 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.esri.arcgisruntime.sample.exporttiles;

import java.io.File;
import java.util.concurrent.ExecutionException;

import android.Manifest;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.constraint.ConstraintLayout;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.TileCache;
import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.layers.ArcGISTiledLayer;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.Viewpoint;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.tasks.tilecache.ExportTileCacheJob;
import com.esri.arcgisruntime.tasks.tilecache.ExportTileCacheParameters;
import com.esri.arcgisruntime.tasks.tilecache.ExportTileCacheTask;

public class MainActivity extends AppCompatActivity {

    private final String TAG = MainActivity.class.getSimpleName();

    private Button mExportTilesButton;
    private ConstraintLayout mTileCachePreviewLayout;
    private View mPreviewMask;

    private MapView mMapView;
    private MapView mTileCachePreview;
    private ArcGISTiledLayer mTiledLayer;
    private ExportTileCacheJob mExportTileCacheJob;
    private ExportTileCacheTask mExportTileCacheTask;

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

        // define permission to request
        String[] reqPermission = { Manifest.permission.WRITE_EXTERNAL_STORAGE };
        int requestCode = 2;
        // For API level 23+ request permission at runtime
        if (ContextCompat.checkSelfPermission(this, reqPermission[0]) != PackageManager.PERMISSION_GRANTED) {
            // request permission
            ActivityCompat.requestPermissions(this, reqPermission, requestCode);
        }

        // get references to ui elements
        mTileCachePreviewLayout = findViewById(R.id.mapPreviewLayout);
        mPreviewMask = findViewById(R.id.previewMask);
        mTileCachePreview = findViewById(R.id.previewMapView);
        mMapView = findViewById(R.id.mapView);

        mTiledLayer = new ArcGISTiledLayer(getString(R.string.world_street_map));
        ArcGISMap map = new ArcGISMap();
        map.setBasemap(new Basemap(mTiledLayer));
        // set a min scale to avoid instance of downloading a tile cache that is too big
        map.setMinScale(10000000);
        mMapView.setMap(map);
        mMapView.setViewpoint(new Viewpoint(51.5, 0.0, 10000000));

        mExportTilesButton = findViewById(R.id.exportTilesButton);
        mExportTilesButton.setOnClickListener(v -> initiateDownload());

        Button previewCloseButton = findViewById(R.id.closeButton);
        previewCloseButton.setOnClickListener(v -> clearPreview());

        clearPreview();
    }

    /**
     * Uses the current MapView to define an Envelope larger on all sides by one MapView in the relevant dimension.
     * ____________________
     * |                  |
     * |      downloaded  |
     * |     ________     |
     * |     |      |  t  |
     * |     | tile |  i  |
     * |     |cache |  l  |
     * |     |preview  e  |
     * |     | View |     |
     * |     --------     |
     * |       cache area |
     * |                  |
     * |                  |
     * --------------------
     *
     * @return an Envelope three times as high and three times as wide as the main MapView.
     */
    private Envelope viewToExtent() {
        // upper left corner of the downloaded tile cache area
        android.graphics.Point minScreenPoint = new android.graphics.Point(mMapView.getLeft() - mMapView.getWidth(),
                mMapView.getTop() - mMapView.getHeight());
        // lower right corner of the downloaded tile cache area
        android.graphics.Point maxScreenPoint = new android.graphics.Point(
                minScreenPoint.x + mMapView.getWidth() * 3, minScreenPoint.y + mMapView.getHeight() * 3);
        // convert screen points to map points
        Point minPoint = mMapView.screenToLocation(minScreenPoint);
        Point maxPoint = mMapView.screenToLocation(maxScreenPoint);
        // use the points to define and return an envelope
        return new Envelope(minPoint, maxPoint);
    }

    /**
     * Clear preview window.
     */
    private void clearPreview() {
        // make map preview invisible
        mTileCachePreview.getChildAt(0).setVisibility(View.INVISIBLE);
        mMapView.bringToFront();
        // show red preview mask
        mPreviewMask.bringToFront();
        mExportTilesButton.setVisibility(View.VISIBLE);
    }

    /**
     * Using scale defined by the main MapView and the TiledLayer and an extent defined by viewToExtent() as parameters,
     * downloads a TileCache locally to the device.
     */
    private void initiateDownload() {
        // map view's current scale as the minScale and tiled layer's max scale as maxScale
        double minScale = mMapView.getMapScale();
        double maxScale = mTiledLayer.getMaxScale();
        // minScale must always be larger than maxScale
        if (minScale <= maxScale) {
            minScale = maxScale + 1;
        }
        // initialize the export task
        mExportTileCacheTask = new ExportTileCacheTask(mTiledLayer.getUri());
        final ListenableFuture<ExportTileCacheParameters> parametersFuture = mExportTileCacheTask
                .createDefaultExportTileCacheParametersAsync(viewToExtent(), minScale, maxScale);
        parametersFuture.addDoneListener(() -> {
            // create directory for file
            File file = new File(Environment.getExternalStorageDirectory(), getString(R.string.tile_cache_folder));
            if (!file.exists()) {
                boolean dirCreated = file.mkdirs();
                if (dirCreated) {
                    Log.i(TAG, "Local TileCache directory created.");
                } else {
                    Log.e(TAG, "Error creating local TileCache directory.");
                }
            } else {
                Log.i(TAG, "No local TileCache directory created, one already exists.");
            }
            try {
                // export tile cache to directory
                ExportTileCacheParameters parameters = parametersFuture.get();
                mExportTileCacheJob = mExportTileCacheTask.exportTileCache(parameters,
                        Environment.getExternalStorageDirectory() + getString(R.string.tile_cache_folder)
                                + getString(R.string.world_street_map_tpk));
            } catch (InterruptedException e) {
                Log.e(TAG, "TileCacheParameters interrupted: " + e.getMessage());
            } catch (ExecutionException e) {
                Log.e(TAG, "Error generating parameters: " + e.getMessage());
            }
            mExportTileCacheJob.start();

            createProgressDialog(mExportTileCacheJob);

            mExportTileCacheJob.addJobDoneListener(() -> {
                if (mExportTileCacheJob.getResult() != null) {
                    TileCache exportedTileCacheResult = mExportTileCacheJob.getResult();
                    showMapPreview(exportedTileCacheResult);
                } else {
                    Log.e(TAG, "Tile cache job result null. File size may be too big.");
                    Toast.makeText(this,
                            "Tile cache job result null. File size may be too big. Try zooming in before exporting tiles",
                            Toast.LENGTH_LONG).show();
                }
            });
        });
    }

    /**
     * Show progress UI elements.
     *
     * @param exportTileCacheJob used to track progress and cancel when required
     */
    private void createProgressDialog(ExportTileCacheJob exportTileCacheJob) {

        ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("Export Tile Cache Job");
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel",
                (dialogInterface, i) -> exportTileCacheJob.cancel());
        progressDialog.show();

        exportTileCacheJob
                .addProgressChangedListener(() -> progressDialog.setProgress(exportTileCacheJob.getProgress()));
        exportTileCacheJob.addJobDoneListener(progressDialog::dismiss);
    }

    /**
     * Show tile cache preview window including MapView.
     *
     * @param result Takes the TileCache from the ExportTileCacheJob.
     */
    private void showMapPreview(TileCache result) {
        ArcGISTiledLayer newTiledLayer = new ArcGISTiledLayer(result);
        ArcGISMap map = new ArcGISMap(new Basemap(newTiledLayer));
        mTileCachePreview.setMap(map);
        mTileCachePreview.setViewpoint(mMapView.getCurrentViewpoint(Viewpoint.Type.CENTER_AND_SCALE));
        mTileCachePreview.setVisibility(View.VISIBLE);
        mTileCachePreviewLayout.bringToFront();
        mTileCachePreview.getChildAt(0).setVisibility(View.VISIBLE);
        mExportTilesButton.setVisibility(View.GONE);
    }

    @Override
    protected void onPause() {
        mMapView.pause();
        mTileCachePreview.pause();
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mMapView.resume();
        mTileCachePreview.resume();
    }

    @Override
    protected void onDestroy() {
        mMapView.dispose();
        mTileCachePreview.dispose();
        super.onDestroy();
    }
}