オフラインマネージャ
<?xml version="1.0" encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:mapbox="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".examples.offline.OfflineManagerActivity"> <com.mapbox.mapboxsdk.maps.MapViewandroid:id="@+id/mapView"android:layout_width="match_parent"android:layout_height="match_parent"mapbox:mapbox_cameraTargetLat="29.720"mapbox:mapbox_cameraTargetLng="-95.342"mapbox:mapbox_cameraZoom="15.27"mapbox:mapbox_cameraZoomMin="10"/> <ProgressBarandroid:id="@+id/progress_bar"style="?android:attr/progressBarStyleHorizontal"android:layout_width="match_parent"android:layout_height="25dp"android:layout_centerInParent="true"android:layout_centerHorizontal="true"android:paddingLeft="25dp"android:paddingRight="25dp"android:visibility="gone"/> <LinearLayoutandroid:id="@+id/bottom_navigation"style="?android:attr/buttonBarStyle"android:layout_width="match_parent"android:layout_height="56dp"android:layout_alignParentBottom="true"android:background="@color/colorAccent"android:elevation="8dp"android:orientation="horizontal"android:paddingTop="8dp"> <Buttonandroid:id="@+id/download_button"style="?android:attr/buttonBarButtonStyle"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:background="@android:color/transparent"android:clickable="true"android:drawableTop="@drawable/ic_get_app_24dp"android:text="@string/download_button_text"android:textAllCaps="false"android:textColor="@color/mapboxWhite"android:textSize="12sp"/> <Buttonandroid:id="@+id/list_button"style="?android:attr/buttonBarButtonStyle"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"android:background="@android:color/transparent"android:drawableTop="@drawable/ic_list_24dp"android:text="@string/list_button_text"android:textAllCaps="false"android:textColor="@color/mapboxWhite"android:textSize="12sp"/> </LinearLayout></RelativeLayout>
OfflineManagerActivity.java
package com.mapbox.mapboxandroiddemo.examples.offline; import android.app.AlertDialog;import android.content.DialogInterface;import android.os.Bundle;import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.Toast; import com.mapbox.mapboxandroiddemo.R;import com.mapbox.mapboxsdk.Mapbox;import com.mapbox.mapboxsdk.camera.CameraPosition;import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;import com.mapbox.mapboxsdk.geometry.LatLngBounds;import com.mapbox.mapboxsdk.maps.MapView;import com.mapbox.mapboxsdk.maps.MapboxMap;import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;import com.mapbox.mapboxsdk.maps.Style;import com.mapbox.mapboxsdk.offline.OfflineManager;import com.mapbox.mapboxsdk.offline.OfflineRegion;import com.mapbox.mapboxsdk.offline.OfflineRegionError;import com.mapbox.mapboxsdk.offline.OfflineRegionStatus;import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition; import org.json.JSONObject; import java.util.ArrayList; import timber.log.Timber; /*** Download, view, navigate to, and delete an offline region.*/public class OfflineManagerActivity extends AppCompatActivity { private static final String TAG = "OffManActivity"; // JSON encoding/decodingpublic static final String JSON_CHARSET = "UTF-8";public static final String JSON_FIELD_REGION_NAME = "FIELD_REGION_NAME"; // UI elementsprivate MapView mapView;private MapboxMap map;private ProgressBar progressBar;private Button downloadButton;private Button listButton; private boolean isEndNotified;private int regionSelected; // Offline objectsprivate OfflineManager offlineManager;private OfflineRegion offlineRegion; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); // Mapbox access token is configured here. This needs to be called either in your application// object or in the same activity which contains the mapview.Mapbox.getInstance(this, getString(R.string.access_token)); // This contains the MapView in XML and needs to be called after the access token is configured.setContentView(R.layout.activity_offline_manager); // Set up the MapViewmapView = findViewById(R.id.mapView);mapView.onCreate(savedInstanceState);mapView.getMapAsync(new OnMapReadyCallback() {@Overridepublic void onMapReady(@NonNull MapboxMap mapboxMap) {map = mapboxMap;mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {@Overridepublic void onStyleLoaded(@NonNull Style style) { // Assign progressBar for later useprogressBar = findViewById(R.id.progress_bar); // Set up the offlineManagerofflineManager = OfflineManager.getInstance(OfflineManagerActivity.this); // Bottom navigation bar button clicks are handled here.// Download offline buttondownloadButton = findViewById(R.id.download_button);downloadButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {downloadRegionDialog();}}); // List offline regionslistButton = findViewById(R.id.list_button);listButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {downloadedRegionList();}});}});}});} // Override Activity lifecycle methods@Overridepublic void onResume() {super.onResume();mapView.onResume();} @Overrideprotected void onStart() {super.onStart();mapView.onStart();} @Overrideprotected void onStop() {super.onStop();mapView.onStop();} @Overridepublic void onPause() {super.onPause();mapView.onPause();} @Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);mapView.onSaveInstanceState(outState);} @Overrideprotected void onDestroy() {super.onDestroy();mapView.onDestroy();} @Overridepublic void onLowMemory() {super.onLowMemory();mapView.onLowMemory();} private void downloadRegionDialog() {// Set up download interaction. Display a dialog// when the user clicks download button and require// a user-provided region nameAlertDialog.Builder builder = new AlertDialog.Builder(OfflineManagerActivity.this); final EditText regionNameEdit = new EditText(OfflineManagerActivity.this);regionNameEdit.setHint(getString(R.string.set_region_name_hint)); // Build the dialog boxbuilder.setTitle(getString(R.string.dialog_title)).setView(regionNameEdit).setMessage(getString(R.string.dialog_message)).setPositiveButton(getString(R.string.dialog_positive_button), new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {String regionName = regionNameEdit.getText().toString();// Require a region name to begin the download.// If the user-provided string is empty, display// a toast message and do not begin download.if (regionName.length() == 0) {Toast.makeText(OfflineManagerActivity.this, getString(R.string.dialog_toast), Toast.LENGTH_SHORT).show();} else {// Begin download processdownloadRegion(regionName);}}}).setNegativeButton(getString(R.string.dialog_negative_button), new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.cancel();}}); // Display the dialogbuilder.show();} private void downloadRegion(final String regionName) {// Define offline region parameters, including bounds,// min/max zoom, and metadata // Start the progressBarstartProgress(); // Create offline definition using the current// style and boundaries of visible map area map.getStyle(new Style.OnStyleLoaded() {@Overridepublic void onStyleLoaded(@NonNull Style style) {String styleUrl = style.getUri();LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds;double minZoom = map.getCameraPosition().zoom;double maxZoom = map.getMaxZoomLevel();float pixelRatio = OfflineManagerActivity.this.getResources().getDisplayMetrics().density;OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition(styleUrl, bounds, minZoom, maxZoom, pixelRatio); // Build a JSONObject using the user-defined offline region title,// convert it into string, and use it to create a metadata variable.// The metadata variable will later be passed to createOfflineRegion()byte[] metadata;try {JSONObject jsonObject = new JSONObject();jsonObject.put(JSON_FIELD_REGION_NAME, regionName);String json = jsonObject.toString();metadata = json.getBytes(JSON_CHARSET);} catch (Exception exception) {Timber.e("Failed to encode metadata: %s", exception.getMessage());metadata = null;} // Create the offline region and launch the downloadofflineManager.createOfflineRegion(definition, metadata, new OfflineManager.CreateOfflineRegionCallback() {@Overridepublic void onCreate(OfflineRegion offlineRegion) {Timber.d( "Offline region created: %s" , regionName);OfflineManagerActivity.this.offlineRegion = offlineRegion;launchDownload();} @Overridepublic void onError(String error) {Timber.e( "Error: %s" , error);}});}});} private void launchDownload() {// Set up an observer to handle download progress and// notify the user when the region is finished downloadingofflineRegion.setObserver(new OfflineRegion.OfflineRegionObserver() {@Overridepublic void onStatusChanged(OfflineRegionStatus status) {// Compute a percentagedouble percentage = status.getRequiredResourceCount() >= 0? (100.0 * status.getCompletedResourceCount() / status.getRequiredResourceCount()) :0.0; if (status.isComplete()) {// Download completeendProgress(getString(R.string.end_progress_success));return;} else if (status.isRequiredResourceCountPrecise()) {// Switch to determinate statesetPercentage((int) Math.round(percentage));} // Log what is being currently downloadedTimber.d("%s/%s resources; %s bytes downloaded.",String.valueOf(status.getCompletedResourceCount()),String.valueOf(status.getRequiredResourceCount()),String.valueOf(status.getCompletedResourceSize()));} @Overridepublic void onError(OfflineRegionError error) {Timber.e("onError reason: %s", error.getReason());Timber.e("onError message: %s", error.getMessage());} @Overridepublic void mapboxTileCountLimitExceeded(long limit) {Timber.e("Mapbox tile count limit exceeded: %s", limit);}}); // Change the region stateofflineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE);} private void downloadedRegionList() {// Build a region list when the user clicks the list button // Reset the region selected int to 0regionSelected = 0; // Query the DB asynchronouslyofflineManager.listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {@Overridepublic void onList(final OfflineRegion[] offlineRegions) {// Check result. If no regions have been// downloaded yet, notify user and returnif (offlineRegions == null || offlineRegions.length == 0) {Toast.makeText(getApplicationContext(), getString(R.string.toast_no_regions_yet), Toast.LENGTH_SHORT).show();return;} // Add all of the region names to a listArrayList<String> offlineRegionsNames = new ArrayList<>();for (OfflineRegion offlineRegion : offlineRegions) {offlineRegionsNames.add(getRegionName(offlineRegion));}final CharSequence[] items = offlineRegionsNames.toArray(new CharSequence[offlineRegionsNames.size()]); // Build a dialog containing the list of regionsAlertDialog dialog = new AlertDialog.Builder(OfflineManagerActivity.this).setTitle(getString(R.string.navigate_title)).setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// Track which region the user selectsregionSelected = which;}}).setPositiveButton(getString(R.string.navigate_positive_button), new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int id) { Toast.makeText(OfflineManagerActivity.this, items[regionSelected], Toast.LENGTH_LONG).show(); // Get the region bounds and zoomLatLngBounds bounds = (offlineRegions[regionSelected].getDefinition()).getBounds();double regionZoom = (offlineRegions[regionSelected].getDefinition()).getMinZoom(); // Create new camera positionCameraPosition cameraPosition = new CameraPosition.Builder().target(bounds.getCenter()).zoom(regionZoom).build(); // Move camera to new positionmap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); }}).setNeutralButton(getString(R.string.navigate_neutral_button_title), new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int id) {// Make progressBar indeterminate and// set it to visible to signal that// the deletion process has begunprogressBar.setIndeterminate(true);progressBar.setVisibility(View.VISIBLE); // Begin the deletion processofflineRegions[regionSelected].delete(new OfflineRegion.OfflineRegionDeleteCallback() {@Overridepublic void onDelete() {// Once the region is deleted, remove the// progressBar and display a toastprogressBar.setVisibility(View.INVISIBLE);progressBar.setIndeterminate(false);Toast.makeText(getApplicationContext(), getString(R.string.toast_region_deleted),Toast.LENGTH_LONG).show();} @Overridepublic void onError(String error) {progressBar.setVisibility(View.INVISIBLE);progressBar.setIndeterminate(false);Timber.e( "Error: %s", error);}});}}).setNegativeButton(getString(R.string.navigate_negative_button_title), new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int id) {// When the user cancels, don't do anything.// The dialog will automatically close}}).create();dialog.show(); } @Overridepublic void onError(String error) {Timber.e( "Error: %s", error);}});} private String getRegionName(OfflineRegion offlineRegion) {// Get the region name from the offline region metadataString regionName; try {byte[] metadata = offlineRegion.getMetadata();String json = new String(metadata, JSON_CHARSET);JSONObject jsonObject = new JSONObject(json);regionName = jsonObject.getString(JSON_FIELD_REGION_NAME);} catch (Exception exception) {Timber.e("Failed to decode metadata: %s", exception.getMessage());regionName = String.format(getString(R.string.region_name), offlineRegion.getID());}return regionName;} // Progress bar methodsprivate void startProgress() {// Disable buttonsdownloadButton.setEnabled(false);listButton.setEnabled(false); // Start and show the progress barisEndNotified = false;progressBar.setIndeterminate(true);progressBar.setVisibility(View.VISIBLE);} private void setPercentage(final int percentage) {progressBar.setIndeterminate(false);progressBar.setProgress(percentage);} private void endProgress(final String message) {// Don't notify more than onceif (isEndNotified) {return;} // Enable buttonsdownloadButton.setEnabled(true);listButton.setEnabled(true); // Stop and hide the progress barisEndNotified = true;progressBar.setIndeterminate(false);progressBar.setVisibility(View.GONE); // Show a toastToast.makeText(OfflineManagerActivity.this, message, Toast.LENGTH_LONG).show();}}