diff options
author | ÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂâÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂosanaÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂâÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂÃÂà<osana.babayan@mapbox.com> | 2017-11-29 02:03:58 -0500 |
---|---|---|
committer | “osana” <osana.babayan@mapbox.com> | 2017-12-01 17:52:51 -0500 |
commit | 59fb1ff2cdf3f800d87e820d5f8bd93bfaa3b873 (patch) | |
tree | d0d2fda771237ab385515005ee6ece067b3d08da | |
parent | a2817ff5ed301f0da5817279ca7184b0c22bdf21 (diff) | |
download | qtlocation-mapboxgl-upstream/osana-offline.tar.gz |
[android] Added offline list regions test && offline download form (needs more work)upstream/osana-offline
30 files changed, 2098 insertions, 0 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java index 6a2bf6b07b..9e0da81f61 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java @@ -144,6 +144,7 @@ public class OfflineManager { * Retrieve all regions in the offline database. * <p> * The query will be executed asynchronously and the results passed to the given + * The query will be executed asyncchronously and the results passed to the given * callback on the main thread. * </p> * @@ -203,6 +204,7 @@ public class OfflineManager { return; } + fileSource.activate(); ConnectivityReceiver.instance(context).activate(); createOfflineRegion(fileSource, definition, metadata, new CreateOfflineRegionCallback() { @@ -212,6 +214,7 @@ public class OfflineManager { @Override public void run() { ConnectivityReceiver.instance(context).deactivate(); + fileSource.deactivate(); callback.onCreate(offlineRegion); } }); @@ -222,6 +225,7 @@ public class OfflineManager { getHandler().post(new Runnable() { @Override public void run() { + fileSource.deactivate(); ConnectivityReceiver.instance(context).deactivate(); callback.onError(error); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 2ced75fc75..5f84e00739 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -357,6 +357,37 @@ android:value=".activity.FeatureOverviewActivity"/> </activity> <activity + android:name=".activity.offline.OfflineRegionsListActivity" + android:description="@string/description_offline_regions_list" + android:label="@string/activity_offline_regions_list"> + <meta-data + android:name="@string/category" + android:value="@string/category_offline"/> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity"/> + </activity> + <activity + android:name=".activity.offline.OfflineMapDownload" + android:description="@string/description_offline_map_form" + android:label="@string/activity_offline_map_form"> + <meta-data + android:name="@string/category" + android:value="@string/category_offline"/> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity"/> + </activity> + <activity + android:name=".activity.offline.SimpleMapViewActivity"> + <meta-data + android:name="@string/category" + android:value="@string/category_offline"/> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.offline.OfflineRegionsListActivity"/> + </activity> + <activity android:name=".activity.imagegenerator.SnapshotActivity" android:description="@string/description_snapshot" android:label="@string/activity_snapshot"> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChainMultiRegion.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChainMultiRegion.java new file mode 100644 index 0000000000..6b97cb1012 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/ChainMultiRegion.java @@ -0,0 +1,250 @@ +package com.mapbox.mapboxsdk.testapp.activity.offline; + + +import android.util.Log; + +import com.mapbox.mapboxsdk.geometry.LatLngBounds; + + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import timber.log.Timber; + +public class ChainMultiRegion implements Region, Region.OnStatusChangeListener { + + private static final String TAG = "TEST-OFFLINE"; + + private final String name; + private final List<Region> regions; + private Region curRegion = null; + private LatLngBounds bounds = null; + private OnStatusChangeListener listener; + + public ChainMultiRegion(List<Region> regionsList) { + if (regionsList == null && regionsList.size() > 0) { + name = ""; + regions = new ArrayList<>(); + } else { + this.name = (regionsList.get(0).getName()); + regions = new ArrayList<>(regionsList.size()); + regions.addAll(regionsList); + } + } + + public ChainMultiRegion(String name, List<Region> regionsList) { + this.name = name; + regions = new ArrayList<>(regionsList == null ? 0 : regionsList.size()); + regions.addAll(regionsList); + } + + + @Override + public String getName() { + return name; + } + + @Override + public void startDownload() { + startMeasuringDownload(); + + // find the first region that was not downloaded yet + for (Region region : regions) { + if (!region.isComplete()) { + curRegion = region; + curRegion.startDownload(); + return; + } + } + } + + @Override + public void stopDownload() { + for (Region region : regions) { + region.stopDownload(); + } + curRegion = null; + stopMeasuringDownload(); + } + + @Override + public void onStatusChanged(Region region) { + if (this.listener != null) { + + if (curRegion == region && region.isComplete()) { + + Log.d(TAG, " >>>>> Another Region COMPLETED: completeCount=" + curRegion.getRequiredResourceCount()+ + " size=" + getSize(curRegion.getCompletedResourceSize())); + curRegion.stopDownload(); + curRegion = null; + + // find the first region that was not downloaded yet + for (Region nextRegion : regions) { + if (!nextRegion.isComplete()) { + curRegion = nextRegion; + curRegion.startDownload(); + return; + } + } + + if (isComplete()) { + stopMeasuringDownload(); + } + } + + this.listener.onStatusChanged(ChainMultiRegion.this); + } + } + + @Override + public void startTrackingStatus(OnStatusChangeListener listener) { + this.listener = listener; + for (Region region : regions) { + region.startTrackingStatus(this); + } + } + + @Override + public void stopTrackingStatus() { + this.listener = null; + for (Region region : regions) { + region.stopTrackingStatus(); + } + } + + public boolean isComplete() { + for (Region region : regions) { + if (!region.isComplete()) { + return false; + } + } + return true; + } + + @Override + public boolean isDownloadStarted() { + for (Region region : regions) { + if (region.isDownloadStarted()) { + return true; + } + } + return false; + } + + @Override + public long getRequiredResourceCount() { + long resCount = 0; + for (Region region : regions) { + resCount += region.getRequiredResourceCount(); + } + return resCount; + } + + @Override + public long getCompletedResourceCount() { + long resCount = 0; int i=0; + for (Region region : regions) { + resCount += region.getCompletedResourceCount(); + } + return resCount; + } + + @Override + public long getCompletedResourceSize() { + long resCount = 0; + for (Region region : regions) { + resCount += region.getCompletedResourceSize(); + } + return resCount; + } + + @Override + public LatLngBounds getBounds() { + if (bounds == null) { + bounds = regions.get(0).getBounds(); + bounds = LatLngBounds.from(bounds.getLatNorth(), bounds.getLonEast(), + bounds.getLatSouth(), bounds.getLonWest()); + + for(int i = 1; i < regions.size(); i++) { + bounds.union(regions.get(i).getBounds()); + } + } + return bounds; + } + + @Override + public String getStyleURL() { + String styleUrl = regions.get(0).getStyleURL(); + for (int i = 1; i < regions.size(); i++) { + Region region = regions.get(i); + if (!styleUrl.equals(region.getStyleURL())) { + throw new IllegalArgumentException(); + } + } + return styleUrl; + } + + @Override + public double getMinZoom() { + double minZoom = 0; + for (Region region : regions) { + if (region.getMinZoom() > minZoom) { + minZoom = region.getMinZoom(); + } + } + + return minZoom; + } + + @Override + public double getMaxZoom() { + double maxZoom = regions.get(0).getMaxZoom(); + for (int i = 1; i < regions.size(); i++) { + Region region = regions.get(i); + if (region.getMaxZoom() < maxZoom) { + maxZoom = region.getMaxZoom(); + } + } + + return maxZoom; + } + + private long startTime = 0; + private long downloadTime = 0; + + @Override + public long getDownloadTime() { + if (startTime > 0) { + downloadTime = System.currentTimeMillis() - startTime; + } + return downloadTime; + } + + private void startMeasuringDownload() { + startTime = System.currentTimeMillis(); + } + + private void stopMeasuringDownload() { + downloadTime = System.currentTimeMillis() - startTime; + + Log.d("TEST-OFFLINE", " >>>>> It took " + + TimeUnit.MILLISECONDS.toMinutes(downloadTime) + " minutes to load " + + getSize(getCompletedResourceSize()) + " the map of " +name); + + startTime = 0; + } + + private static String getSize(long size) { + if (size == 0) { + return "0 B"; + } else if (size < 1024) { + return size + " B"; + } else if (size < 1048576){ + return size / 1024 + " KB"; + } else { + return size /1048576 + " MB"; + } + } + +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/MultiRegion.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/MultiRegion.java new file mode 100644 index 0000000000..846cc23943 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/MultiRegion.java @@ -0,0 +1,225 @@ +package com.mapbox.mapboxsdk.testapp.activity.offline; + + +import android.util.Log; + +import com.mapbox.mapboxsdk.geometry.LatLngBounds; + + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class MultiRegion implements Region, Region.OnStatusChangeListener { + + private static final String TAG = "TEST-OFFLINE"; + + private final String name; + private final List<Region> regions; + private LatLngBounds bounds = null; + private OnStatusChangeListener listener; + + public MultiRegion(List<Region> regionsList) { + if (regionsList == null && regionsList.size() > 0) { + name = ""; + regions = new ArrayList<>(); + } else { + this.name = (regionsList.get(0).getName()); + regions = new ArrayList<>(regionsList.size()); + regions.addAll(regionsList); + } + } + + public MultiRegion(String name, List<Region> regionsList) { + this.name = name; + regions = new ArrayList<>(regionsList == null ? 0 : regionsList.size()); + regions.addAll(regionsList); + } + + + @Override + public String getName() { + return name; + } + + @Override + public void startDownload() { + startMeasuringDownload(); + + for (Region region : regions) { + region.startDownload(); + } + } + + @Override + public void stopDownload() { + for (Region region : regions) { + region.stopDownload(); + } + stopMeasuringDownload(); + } + + @Override + public void onStatusChanged(Region region) { + if (this.listener != null) { + + this.listener.onStatusChanged(MultiRegion.this); + + // Stop measuring downlaod ! + if (isComplete()) { + stopMeasuringDownload(); + } + } + } + + @Override + public void startTrackingStatus(OnStatusChangeListener listener) { + this.listener = listener; + for (Region region : regions) { + region.startTrackingStatus(this); + } + } + + @Override + public void stopTrackingStatus() { + this.listener = null; + for (Region region : regions) { + region.stopTrackingStatus(); + } + } + + public boolean isComplete() { + for (Region region : regions) { + if (!region.isComplete()) { + return false; + } + } + return true; + } + + @Override + public boolean isDownloadStarted() { + for (Region region : regions) { + if (region.isDownloadStarted()) { + return true; + } + } + return false; + } + + @Override + public long getRequiredResourceCount() { + long resCount = 0; + for (Region region : regions) { + resCount += region.getRequiredResourceCount(); + } + return resCount; + } + + @Override + public long getCompletedResourceCount() { + long resCount = 0; int i=0; + for (Region region : regions) { + resCount += region.getCompletedResourceCount(); + } + return resCount; + } + + @Override + public long getCompletedResourceSize() { + long resCount = 0; + for (Region region : regions) { + resCount += region.getCompletedResourceSize(); + } + return resCount; + } + + @Override + public LatLngBounds getBounds() { + if (bounds == null) { + bounds = regions.get(0).getBounds(); + bounds = LatLngBounds.from(bounds.getLatNorth(), bounds.getLonEast(), + bounds.getLatSouth(), bounds.getLonWest()); + + for(int i = 1; i < regions.size(); i++) { + bounds.union(regions.get(i).getBounds()); + } + } + return bounds; + } + + @Override + public String getStyleURL() { + String styleUrl = regions.get(0).getStyleURL(); + for (int i = 1; i < regions.size(); i++) { + Region region = regions.get(i); + if (!styleUrl.equals(region.getStyleURL())) { + throw new IllegalArgumentException(); + } + } + return styleUrl; + } + + @Override + public double getMinZoom() { + double minZoom = 0; + for (Region region : regions) { + if (region.getMinZoom() > minZoom) { + minZoom = region.getMinZoom(); + } + } + + return minZoom; + } + + @Override + public double getMaxZoom() { + double maxZoom = regions.get(0).getMaxZoom(); + for (int i = 1; i < regions.size(); i++) { + Region region = regions.get(i); + if (region.getMaxZoom() < maxZoom) { + maxZoom = region.getMaxZoom(); + } + } + + return maxZoom; + } + + private long startTime = 0; + private long downloadTime = 0; + + @Override + public long getDownloadTime() { + if (startTime > 0) { + downloadTime = System.currentTimeMillis() - startTime; + } + return downloadTime; + } + + private void startMeasuringDownload() { + startTime = System.currentTimeMillis(); + } + + private void stopMeasuringDownload() { + downloadTime = System.currentTimeMillis() - startTime; + + Log.d("TEST-OFFLINE", " >>>>> It took " + + TimeUnit.MILLISECONDS.toMinutes(downloadTime) + " minutes to load " + + getSize(getCompletedResourceSize()) + " the map of " +name); + + startTime = 0; + } + + private static String getSize(long size) { + if (size == 0) { + return "0 B"; + } else if (size < 1024) { + return size + " B"; + } else if (size < 1048576){ + return size / 1024 + " KB"; + } else { + return size /1048576 + " MB"; + } + } + +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineMapDownload.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineMapDownload.java new file mode 100644 index 0000000000..0ee820d401 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineMapDownload.java @@ -0,0 +1,409 @@ +package com.mapbox.mapboxsdk.testapp.activity.offline; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.SeekBar; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import com.mapbox.mapboxsdk.constants.Style; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +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 com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.utils.OfflineUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import timber.log.Timber; + +/** + * Created by osanababayan on 11/28/17. + */ + +public class OfflineMapDownload extends AppCompatActivity + implements View.OnClickListener, SeekBar.OnSeekBarChangeListener { + + private EditText regionNameView; + private Spinner spinner; + private TextView minZoomView, maxZoomView; + private SeekBar minZoomSeekBar, maxZoomSeekBar; + private EditText latNorthView, latSouthView, lonEastView, lonWestView; + private TextView downloadProgressView; + private Button actionButton; + + private OfflineRegion offlineRegion = null; + private OfflineRegionStatus status = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_offline_map_form); + + initUI(); + } + + @Override + protected void onDestroy() { + cleanUI(); + + stopDownload(); + + if (offlineRegion != null) { + offlineRegion.setObserver(null); + offlineRegion = null; + } + + super.onDestroy(); + } + + private void initUI() { + regionNameView = (EditText)findViewById(R.id.name); + + spinner = (Spinner)findViewById(R.id.style); + initSpinner(); + + minZoomView = (TextView)findViewById(R.id.minzoom); + maxZoomView = (TextView)findViewById(R.id.maxzoom); + + minZoomSeekBar = (SeekBar) findViewById(R.id.minzoom_slider); + minZoomSeekBar.setOnSeekBarChangeListener(this); + maxZoomSeekBar = (SeekBar) findViewById(R.id.maxzoom_slider); + maxZoomSeekBar.setOnSeekBarChangeListener(this); + + latNorthView = (EditText)findViewById(R.id.lat_north); + lonEastView = (EditText)findViewById(R.id.lon_east); + + latSouthView = (EditText)findViewById(R.id.lat_south); + lonWestView = (EditText)findViewById(R.id.lon_west); + + downloadProgressView = (TextView)findViewById(R.id.download_progress); + + actionButton = (Button)findViewById(R.id.action_button); + actionButton.setOnClickListener(this); + + // Set Default values; + minZoomSeekBar.setProgress(0); + maxZoomSeekBar.setProgress(15); + + // New York + latNorthView.setText("40.7589372691904"); + lonEastView.setText("-73.96024123810196"); + latSouthView.setText("40.740763489055496"); + lonWestView.setText("-73.97569076188057"); + + // Berlin +// latNorthView.setText("52.6780473464"); +// lonEastView.setText("13.7603759766"); +// latSouthView.setText("52.3305137868"); +// lonWestView.setText("13.0627441406"); + // styleView.setText(style); + } + + private void cleanUI() { + actionButton.setOnClickListener(null); + minZoomSeekBar.setOnSeekBarChangeListener(null); + maxZoomSeekBar.setOnSeekBarChangeListener(null); + } + + + private void initSpinner() { + List<String> styleList = new ArrayList<String>(); + List<String> list = new ArrayList<String>(Arrays.asList( + Style.MAPBOX_STREETS, + Style.OUTDOORS, + Style.LIGHT, + Style.DARK, + Style.SATELLITE, + Style.SATELLITE_STREETS, + Style.TRAFFIC_DAY, + Style.TRAFFIC_NIGHT, + "CUSTOM")); + + ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, + android.R.layout.simple_spinner_item, list); + dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner.setAdapter(dataAdapter); + } + + public void onClick(View button) { + + Timber.e(">>>>> complete=" +isDownloadComplete()+ " isDownloading=" +isDownloading()); + + if (isDownloadComplete()) { + // Display offline map in a new Activity + + showRegion(offlineRegion); + + } else if (isDownloading()) { + actionButton.setText("Pause download"); + stopDownload(); + + } else { + + actionButton.setText("Downloading..."); + // Create offline Region and + // start download it once it is created + createOfflineRegionAndStartDownload(); + } + + } + + + public void createOfflineRegionAndStartDownload() { + // get data from UI + String regionName = regionNameView.getText().toString(); + double latitudeNorth = Double.parseDouble(latNorthView.getText().toString()); + double longitudeEast = Double.parseDouble(lonEastView.getText().toString()); + double latitudeSouth = Double.parseDouble(latSouthView.getText().toString()); + double longitudeWest = Double.parseDouble(lonWestView.getText().toString()); + + float pixelDensity = getResources().getDisplayMetrics().density; + + String styleUrl = getStyleUrl(); + double offlineRegionMinZoom = minZoomSeekBar.getProgress(); + double offlineRegionMaxZoom = maxZoomSeekBar.getProgress(); + + // create offline definition from data + OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition( + styleUrl, + new LatLngBounds.Builder() + .include(new LatLng(latitudeNorth, longitudeEast)) + .include(new LatLng(latitudeSouth, longitudeWest)) + .build(), + offlineRegionMinZoom, + offlineRegionMaxZoom, + pixelDensity + ); + + Timber.e(">>>>>> Create Offline Region with minZoom=" +offlineRegionMinZoom+ " maxZoom=" +offlineRegionMaxZoom+ + " styleUrl=" +getStyleUrl()+ " bounds=" +definition.getBounds()); + + + OfflineManager.getInstance(this.getApplicationContext()) + .createOfflineRegion(definition, + OfflineUtils.convertRegionName(regionName), + new OfflineManager.CreateOfflineRegionCallback() { + @Override + public void onCreate(OfflineRegion offlineRegion) { + Timber.e(">>>> Region created >>> start Download"); + startDownLoad(offlineRegion); + } + + @Override + public void onError(String error) { + Timber.e("Failed to create offline Region"); + } + } + ); + } + + + private void startDownLoad(OfflineRegion offlineRegion) { + if (offlineRegion != null && !isDownloading()) { + Timber.e(">>>> Start Download offlineRegion=" +offlineRegion); + this.offlineRegion = offlineRegion; + + // Get observing offline region's status. + offlineRegion.getStatus(new OfflineRegion.OfflineRegionStatusCallback() { + @Override + public void onStatus(OfflineRegionStatus status) { + onDownloadStatusChanged(status); + } + + @Override + public void onError(String error) { + Timber.e("Failed to get status"); + } + }); + + //Start observing offline region's status + offlineRegion.setObserver(new OfflineRegion.OfflineRegionObserver() { + @Override + public void onStatusChanged(OfflineRegionStatus status) { + + // Stop downlaod ! + if (status.isComplete()) { + + stopMeasuringDownload(); + Toast.makeText(OfflineMapDownload.this, + "Download is complete - turn off WiFi to Test", + Toast.LENGTH_SHORT) + .show(); + actionButton.setText("Show Offline Region"); + } + + onDownloadStatusChanged(status); + } + + @Override + public void onError(OfflineRegionError error) { + Timber.e("Failed to report status " +error.getMessage()); + } + + @Override + public void mapboxTileCountLimitExceeded(long limit) { + + } + }); + + startMeasuringDownload(); + this.offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE); + } + } + + private void stopDownload() { + if (isDownloading() && offlineRegion != null) { + offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE); + stopMeasuringDownload(); + } + } + + private void showRegion(OfflineRegion region) { + + OfflineTilePyramidRegionDefinition definition = (OfflineTilePyramidRegionDefinition)region.getDefinition(); + + Bundle bundle = new Bundle(); + bundle.putParcelable(SimpleMapViewActivity.BOUNDS_ARG, region.getDefinition().getBounds()); + bundle.putString(SimpleMapViewActivity.STYLE_ARG, getStyleUrl()); + bundle.putDouble(SimpleMapViewActivity.MINZOOM_ARG, definition.getMinZoom()); + bundle.putDouble(SimpleMapViewActivity.MAXZOOM_ARG, definition.getMaxZoom()); // should be taken from definition + + Timber.e(" >>>> SHOW StyleURl: =" + getStyleUrl()); + Timber.e(" >>>> SHOW Bounds: =" + region.getDefinition().getBounds()); + Timber.e(" >>>> SHOW Min ZOOM: =" + definition.getMinZoom()); + Timber.e(" >>>> SHOW Max ZOOM: =" + definition.getMaxZoom()); + + Intent intent = new Intent(this, SimpleMapViewActivity.class); + intent.putExtras(bundle); + startActivity(intent); + } + + + String getStyleUrl() { + String style =(String) spinner.getSelectedItem(); + if ("CUSTOM".equals(style)) { + return getResources().getString(R.string.custom_style_url); + } + + return style; + } + + private void onDownloadStatusChanged(OfflineRegionStatus status) { + + this.status = status; + + // Compute a percentage + final int percentage = status.getRequiredResourceCount() >= 0 ? + (int)(100.0 * status.getCompletedResourceCount() / status.getRequiredResourceCount()) : 0; + String progressStr = getSize(status.getCompletedResourceSize()) + ", " + percentage + " %"; + + if (status.isComplete()) { + progressStr += " " +TimeUnit.MILLISECONDS.toMinutes(downloadTime) + " minutes"; + } + downloadProgressView.setText(progressStr); + + Timber.e(String.format("REGION STATUS CHANGED: %s - %s/%s resources; %s bytes downloaded.", + status.isComplete() ? " COMPLETE " : (isDownloading() ? " DOWNLOADING " : " AVAILABLE"), + String.valueOf(status.getCompletedResourceCount()), + String.valueOf(status.getRequiredResourceCount()), + String.valueOf(status.getCompletedResourceSize()))); + } + + private boolean isDownloading() { + return status != null && status.getDownloadState() == OfflineRegion.STATE_ACTIVE; + } + + private boolean isDownloadComplete() { + return status != null && status.isComplete(); + } + + static String getSize(long size) { + if (size == 0) { + return "0 B"; + } else if (size < 1024) { + return size + " B"; + } else if (size < 1048576){ + return size / 1024 + " KB"; + } else { + return size /1048576 + " MB"; + } + } + + //https://en.wikipedia.org/wiki/Haversine_formula + static double latLongToMeters(LatLngBounds bounds) { + double lat1 = bounds.getLatNorth(); + double lon1 = bounds.getLonEast(); + double lat2 = bounds.getLatSouth(); + double lon2 = bounds.getLonWest(); + + double R = 6378.137; // Radius of earth in KM + double dLat = lat2 * Math.PI / 180 - lat1 * Math.PI / 180; + double dLon = lon2 * Math.PI / 180 - lon1 * Math.PI / 180; + double a = Math.sin(dLat/2) * Math.sin(dLat/2) + + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * + Math.sin(dLon/2) * Math.sin(dLon/2); + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + double d = R * c; + return d * 1000; // meters + } + + + private long startTime = 0; + private long downloadTime = 0; + + private long getDownloadTime() { + if (startTime > 0) { + downloadTime = startTime - System.currentTimeMillis(); + } + return downloadTime; + } + + + private void startMeasuringDownload() { + startTime = System.currentTimeMillis(); + } + + private void stopMeasuringDownload() { + downloadTime = startTime - System.currentTimeMillis(); + + Timber.e(" >>>>> It took " + TimeUnit.MILLISECONDS.toMinutes(downloadTime) + " minutes to load " + + getSize(status.getCompletedResourceSize()) + " the map of " + + OfflineUtils.convertRegionName(offlineRegion.getMetadata()) ); + + startTime = 0; + } + + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + if (seekBar == minZoomSeekBar) { + minZoomView.setText(String.valueOf(i)); + } else { + maxZoomView.setText(String.valueOf(i)); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineRegionListAdapter.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineRegionListAdapter.java new file mode 100644 index 0000000000..8472c321c2 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineRegionListAdapter.java @@ -0,0 +1,82 @@ +package com.mapbox.mapboxsdk.testapp.activity.offline; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.mapbox.mapboxsdk.testapp.R; + +import java.util.List; +import java.util.concurrent.TimeUnit; + + +public class OfflineRegionListAdapter extends ArrayAdapter<Region> { + public OfflineRegionListAdapter(@NonNull Context context, int resource) { + super(context, resource); + } + + public OfflineRegionListAdapter(@NonNull Context context, int resource, int textViewResourceId, @NonNull List<Region> objects) { + super(context, resource, textViewResourceId, objects); + } + + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.offline_region_list_item, parent, false); + } + + Region region = getItem(position); + TextView name = (TextView)convertView.findViewById(R.id.area_name); + name.setText(region.getName()); + + TextView sizeText = (TextView)convertView.findViewById(R.id.size); + ImageView stateIcon = (ImageView) convertView.findViewById(R.id.state_icon); + + // Display downloaded size and status icon according to last reported status + + + // Compute a percentage + int percentage = region.getRequiredResourceCount() >= 0 ? + (int)(100.0 * region.getCompletedResourceCount() / region.getRequiredResourceCount()) : 0; + + String summary = getSize(region.getCompletedResourceSize()) + ", " + percentage + " %"; + if (region.isComplete()) { + summary += " " + TimeUnit.MILLISECONDS.toMinutes(region.getDownloadTime()) + " minutes"; + } + sizeText.setText(summary); + + if (region.isComplete() || percentage == 100) { + stateIcon.setImageResource(R.mipmap.ic_play_arrow_black_24dp); + + } else if (region.isDownloadStarted()) { + stateIcon.setImageResource(R.mipmap.ic_autorenew_black_24dp); + + } else { + stateIcon.setImageResource(R.mipmap.ic_file_download_black_24dp); + } + + + return convertView; + } + + static String getSize(long size) { + if (size == 0) { + return "0 B"; + } else if (size < 1024) { + return size + " B"; + } else if (size < 1048576){ + return size / 1024 + " KB"; + } else { + return size /1048576 + " MB"; + } + } + +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineRegionsListActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineRegionsListActivity.java new file mode 100644 index 0000000000..212a65664c --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineRegionsListActivity.java @@ -0,0 +1,427 @@ +package com.mapbox.mapboxsdk.testapp.activity.offline; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; + +import com.mapbox.mapboxsdk.constants.Style; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.offline.OfflineManager; +import com.mapbox.mapboxsdk.offline.OfflineRegion; +import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition; +import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.utils.OfflineUtils; + +import java.util.ArrayList; +import java.util.List; + +import timber.log.Timber; + +public class OfflineRegionsListActivity extends AppCompatActivity implements Region.OnStatusChangeListener { + + private static final String TAG = "TEST-OFFLINE"; + + private List<Region> regions; + private ListView regionsList; + private OfflineRegionListAdapter regionsAdapter; + + private OfflineManager offlineManager; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_offline_region_list); + + regions = new ArrayList<>(); + + // Set up a list to hold available offline regions + regionsAdapter = new OfflineRegionListAdapter(this, 0); + regionsList = (ListView)findViewById(R.id.areas); + regionsList.setAdapter(regionsAdapter); + regionsList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { + + Region region = regionsAdapter.getItem(i); + + if (region != null) { + if (region.isComplete()) { + Log.d(TAG, "Region +" +region.getName()+ " clicked - download is complete -> show the region"); + + Bundle bundle = new Bundle(); + bundle.putParcelable(SimpleMapViewActivity.BOUNDS_ARG, region.getBounds()); + bundle.putString(SimpleMapViewActivity.STYLE_ARG, region.getStyleURL()); + bundle.putDouble(SimpleMapViewActivity.MINZOOM_ARG, region.getMinZoom()); + bundle.putDouble(SimpleMapViewActivity.MAXZOOM_ARG, region.getMaxZoom()); + + Log.d(TAG," >>>> SHOW StyleURl: =" + region.getStyleURL()); + Log.d(TAG," >>>> SHOW Bounds: =" + region.getBounds()); + Log.d(TAG," >>>> SHOW Min ZOOM: =" + region.getMinZoom()); + Log.d(TAG," >>>> SHOW Max ZOOM: =" + region.getMaxZoom()); + + Intent intent = new Intent(OfflineRegionsListActivity.this, SimpleMapViewActivity.class); + intent.putExtras(bundle); + startActivity(intent); + + } else if (region.isDownloadStarted()) { + Log.d(TAG, "Region +" +region.getName()+ " clicked - download is in progress"); + + } else { + + Log.d(TAG, "Region +" +region.getName()+ " clicked - start download"); + region.startDownload(); + } + } + } + }); + + // Set up the offlineManager + offlineManager = OfflineManager.getInstance(this); + + Log.d(TAG, ">>>>>>>>>> onCreate: listOfflineRegions"); + // Download available regions from the OfflineManager + // If there are no regions available -> add default ones (Berlin and Hessen) + offlineManager.listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() { + @Override + public void onList(OfflineRegion[] regions) { + + if (regions == null || regions.length == 0) { + requestAddDefaultRegions(); + + } else { + + // Offline Regions that were included in one of the MultiRegions + List<OfflineRegion> added = new ArrayList<>(); + + for (int i = 0; i < regions.length; i++) { + OfflineRegion region = regions[i]; + if (added.contains(region)) { + continue; + } + + // Find all regions with the same name after this one + // Add them all together as MultiRegion + // If there is only one OfflineRegion with this name - add as SingleRegion + String name = OfflineUtils.convertRegionName(region.getMetadata()); + if (name != null) { + List<Region> sameNameRegions = new ArrayList<>(); + for (int j = i + 1; j < regions.length; j++) { + if (name.equals(OfflineUtils.convertRegionName(regions[j].getMetadata()))) { + if (sameNameRegions.size() == 0) { + sameNameRegions.add(new SingleRegion(region)); + } + sameNameRegions.add(new SingleRegion(regions[j])); + added.add(regions[j]); + } + } + if (sameNameRegions.size() > 0) { + addToList(new MultiRegion(sameNameRegions)); + sameNameRegions.clear(); + continue; + } + } + addToList(new SingleRegion(region)); + } + } + } + + @Override + public void onError(String error) { + Log.d(TAG, " Error getting regions error=" +error); + + } + }); + } + + + @Override + protected void onDestroy() { + + Log.d(TAG, ">>>>>>>>>> onDestroy"); + + // TODO: Should we clean offlineManager listAll callback? + + + if (regions != null) { + for (Region region : regions) { + region.stopTrackingStatus(); + region.stopDownload(); + } + regions.clear(); + } + if (regionsAdapter != null) { + regionsAdapter.clear(); + regionsAdapter = null; + } + if (regionsList != null) { + regionsList.setOnItemClickListener(null); + regionsList.setAdapter(null); + regionsList = null; + } + super.onDestroy(); + } + + @Override + public void onStatusChanged(Region region) { + boolean isComplete = region.isComplete(); + boolean isBeingDownloaded = region.isDownloadStarted(); + long completedCount = region.getCompletedResourceCount(); + long allCount = region.getRequiredResourceCount(); + long completedSize = region.getCompletedResourceSize(); + long downLoadTime = region.getDownloadTime(); + + Log.d(TAG, String.format("REGION STATUS CHANGED: Name=%s %s - %s/%s resources; %s bytes downloaded.", + region.getName(), isComplete ? " COMPLETE " : (isBeingDownloaded ? " ACTIVE " : " AVAILABLE"), + String.valueOf(completedCount), + String.valueOf(allCount), + String.valueOf(completedSize))); + + if (regionsAdapter != null) { + regionsAdapter.notifyDataSetChanged(); + } + } + + /** + * Add a region to regions list and to the list adapter. + * Start observing offline region's status. + * When status changes list needs to be updated. + * Given that getting status is an async operation, we will store last reported status in the SingleRegion instance + */ + private void addToList(Region newRegion) { + + if (regions != null) { + regions.add(newRegion); + regionsAdapter.add(newRegion); + newRegion.startTrackingStatus(this); + } + } + + + /** + * Request SingleRegion with given name, bounds, default style, minZoom, maxZoom and pixelDensity to be added + * to Offline Map Regions. + * @param regionName + * @param styleUrl + * @param bounds + * @param minZoom + * @param maxZoom + * @param pixelDensity + */ + private void requestOfflineRegionAdd(final String regionName, String styleUrl, + LatLngBounds bounds, double minZoom , double maxZoom, float pixelDensity) { + + Timber.e("Request offlineRegion regionName=" +regionName); + + OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition( + styleUrl, bounds, minZoom, maxZoom, pixelDensity); + + + // Create the offline region and launch the download + offlineManager.createOfflineRegion(definition, OfflineUtils.convertRegionName(regionName), + new OfflineManager.CreateOfflineRegionCallback() { + @Override + public void onCreate(OfflineRegion offlineRegion) { + Log.d(TAG, "Offline region created: " + regionName + + " offlineRegion: id=" + offlineRegion.getID() + " defenition.bounds=" +offlineRegion.getDefinition().getBounds()+ + " nameFromMetadata=" + OfflineUtils.convertRegionName(offlineRegion.getMetadata())); + addToList(new SingleRegion(regionName, offlineRegion)); + } + + @Override + public void onError(String error) { + Log.e(TAG, "Error: " + error); + } + }); + } + + /** + * Request SingleRegion with given name, bounds, default style, minZoom, maxZoom and pixelDensity to be added + * to Offline Map Regions. + * @param regionName + * @param styleUrl + * @param boundsList + * @param minZoom + * @param maxZoom + * @param pixelDensity + */ + private void requestOfflineMultiRegionAdd(final String regionName, String styleUrl, + final List<LatLngBounds> boundsList, + double minZoom , double maxZoom, float pixelDensity, final boolean doConcurrent) { + + if (boundsList == null) { + return; + } + + if (styleUrl == null) { + styleUrl = Style.MAPBOX_STREETS; + } + + Timber.e("Requesting MultiRegion " + regionName + (doConcurrent ? " CONCURRENT" : " CHAIN")); + + final List<Region> offlineRegionList = new ArrayList<>(); + for(LatLngBounds bounds : boundsList) { + + OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition( + styleUrl, bounds, minZoom, maxZoom, pixelDensity); + + + // Create the offline region and launch the download + offlineManager.createOfflineRegion(definition, OfflineUtils.convertRegionName(regionName), + new OfflineManager.CreateOfflineRegionCallback() { + @Override + public void onCreate(OfflineRegion offlineRegion) { + + Timber.e("Offline region created " +regionName + " for Multiregion addedSize=" +offlineRegionList.size()); + + offlineRegionList.add(new SingleRegion(regionName, offlineRegion)); + + // Create and add a new Region that consists of muliple OfflineRegions + // once all bounds were added to + if (boundsList.size() == offlineRegionList.size()) { + addToList(doConcurrent ? new MultiRegion(regionName, offlineRegionList) : + new ChainMultiRegion(regionName, offlineRegionList)); + } + } + + @Override + public void onError(String error) { + Log.e(TAG, "Error: " + error); + } + }); + } + } + + static List<LatLngBounds> hessenRegions = new ArrayList<>(); + static { + hessenRegions.add(LatLngBounds.from(51.3983488624, 9.0362548828, 51.0923105489, 8.5528564453)); + hessenRegions.add(LatLngBounds.from(51.52000000000001, 9.10499999999999, 51.399, 8.882000000000005)); + hessenRegions.add(LatLngBounds.from(51.399, 9.10499999999999, 51.16900000000001, 9.037000000000006)); + hessenRegions.add(LatLngBounds.from(51.16900000000001, 9.424000000000007, 51.119, 9.102000000000004)); + hessenRegions.add(LatLngBounds.from(51.52199999999999, 9.424000000000007, 51.52099999999999, 9.102000000000004)); + hessenRegions.add(LatLngBounds.from(51.52099999999999, 9.424000000000007, 51.16999999999999, 9.105999999999995)); + hessenRegions.add(LatLngBounds.from(51.65899999999999, 9.695999999999998, 51.522999999999996, 9.264999999999986)); + hessenRegions.add(LatLngBounds.from(51.522999999999996, 9.695999999999998, 51.22399999999999, 9.425000000000011)); + hessenRegions.add(LatLngBounds.from(51.22399999999999, 10.086000000000013, 51.17500000000001, 9.686000000000007)); + hessenRegions.add(LatLngBounds.from(51.42500000000001, 10.086000000000013, 51.224999999999994, 9.697000000000003)); + hessenRegions.add(LatLngBounds.from(51.22399999999999, 9.686000000000007, 50.95400000000001, 9.626000000000005)); + hessenRegions.add(LatLngBounds.from(51.17500000000001, 10.241000000000014, 50.95400000000001, 9.687000000000012)); + hessenRegions.add(LatLngBounds.from(51.260999999999996, 10.241000000000014, 51.17599999999999, 10.086999999999989)); + hessenRegions.add(LatLngBounds.from(51.010999999999996, 9.626000000000005, 50.67400000000001, 9.454000000000008)); + hessenRegions.add(LatLngBounds.from(50.95400000000001, 10.068999999999988, 50.67400000000001, 9.62700000000001)); + hessenRegions.add(LatLngBounds.from(50.67500000000001, 9.454000000000008, 50.39699999999999, 9.449999999999989)); + hessenRegions.add(LatLngBounds.from(50.67400000000001, 10.086000000000013, 50.39699999999999, 9.455000000000013)); + hessenRegions.add(LatLngBounds.from(51.09200000000001, 9.449999999999989, 50.21199999999999, 8.939999999999998)); + hessenRegions.add(LatLngBounds.from(51.16900000000001, 9.102000000000004, 51.09299999999999, 9.037000000000006)); + hessenRegions.add(LatLngBounds.from(51.119, 9.626000000000005, 51.09299999999999, 9.103000000000009)); + hessenRegions.add(LatLngBounds.from(51.22399999999999, 9.626000000000005, 51.120000000000005, 9.425000000000011)); + hessenRegions.add(LatLngBounds.from(50.39699999999999, 9.795999999999992, 50.21199999999999, 9.450999999999993)); + hessenRegions.add(LatLngBounds.from(51.09299999999999, 9.454000000000008, 50.67599999999999, 9.450999999999993)); + hessenRegions.add(LatLngBounds.from(51.09299999999999, 9.626000000000005, 51.012, 9.455000000000013)); + hessenRegions.add(LatLngBounds.from(50.345, 8.939999999999998, 50.078, 8.925999999999988)); + hessenRegions.add(LatLngBounds.from(50.21199999999999, 9.682999999999993, 50.078, 8.941000000000003)); + hessenRegions.add(LatLngBounds.from(51.20099999999999, 8.551999999999992, 50.837999999999994, 8.437999999999988)); + hessenRegions.add(LatLngBounds.from(51.09200000000001, 8.939999999999998, 50.837999999999994, 8.552999999999997)); + hessenRegions.add(LatLngBounds.from(50.88900000000001, 8.437999999999988, 50.531000000000006, 8.116000000000014)); + hessenRegions.add(LatLngBounds.from(50.837999999999994, 8.685000000000002, 50.531000000000006, 8.438999999999993)); + hessenRegions.add(LatLngBounds.from(50.56299999999999, 8.116000000000014, 50.202, 7.961000000000013)); + hessenRegions.add(LatLngBounds.from(50.531000000000006, 8.530000000000001, 50.202, 8.11699999999999)); + hessenRegions.add(LatLngBounds.from(50.27600000000001, 7.961000000000013, 49.91300000000001, 7.765999999999991)); + hessenRegions.add(LatLngBounds.from(50.202, 8.544999999999987, 49.91300000000001, 7.961999999999989)); + hessenRegions.add(LatLngBounds.from(50.27600000000001, 8.544999999999987, 50.203, 8.531000000000006)); + hessenRegions.add(LatLngBounds.from(49.91300000000001, 9.151999999999987, 49.52199999999999, 8.305000000000007)); + hessenRegions.add(LatLngBounds.from(50.94900000000001, 8.437999999999988, 50.889999999999986, 8.305000000000007)); + hessenRegions.add(LatLngBounds.from(50.531000000000006, 8.925999999999988, 50.27699999999999, 8.531000000000006)); + hessenRegions.add(LatLngBounds.from(50.27699999999999, 8.925999999999988, 49.91399999999999, 8.545999999999992)); + hessenRegions.add(LatLngBounds.from(50.837999999999994, 8.939999999999998, 50.53200000000001, 8.686000000000007)); + hessenRegions.add(LatLngBounds.from(50.078, 9.151999999999987, 49.91399999999999, 8.926999999999992)); + hessenRegions.add(LatLngBounds.from(50.53200000000001, 8.939999999999998, 50.346000000000004, 8.926999999999992)); + hessenRegions.add(LatLngBounds.from(49.52199999999999, 8.806000000000012, 49.497000000000014, 8.346000000000004)); + hessenRegions.add(LatLngBounds.from(49.497000000000014, 9.140999999999991, 49.387, 8.661000000000001)); + hessenRegions.add(LatLngBounds.from(49.52199999999999, 9.140999999999991, 49.49799999999999, 8.806999999999988)); + + } + + private void requestAddDefaultRegions() { + + Log.d(TAG, " Add defaults:"); + LatLngBounds firstBounds = hessenRegions.get(0); + LatLngBounds hessenBounds = LatLngBounds.from(firstBounds.getLatNorth(), firstBounds.getLonEast(), + firstBounds.getLatSouth(), firstBounds.getLonWest()); + + + for(int i = 1; i < hessenRegions.size(); i++) { + hessenBounds.union(hessenRegions.get(i)); + } + + LatLngBounds berlinBounds = new LatLngBounds.Builder() + .include(new LatLng(52.6780473464, 13.7603759766)) + .include(new LatLng(52.3305137868, 13.0627441406)) + .build(); + + LatLngBounds newYorkBounds = new LatLngBounds.Builder() + .include(new LatLng(40.7589372691904, -73.96024123810196)) + .include(new LatLng(40.740763489055496, -73.97569076188057)) + .build(); + + + List<LatLngBounds> newYorkMultBounds = new ArrayList<>(); + newYorkMultBounds.add(new LatLngBounds.Builder() + .include(new LatLng(40.858, -74.060)) + .include(new LatLng(40.840, -74.075)) + .build()); + newYorkMultBounds.add(new LatLngBounds.Builder() + .include(new LatLng(40.758, -73.960)) + .include(new LatLng(40.740, -73.975)) + .build()); + + + float pixelRatio = this.getResources().getDisplayMetrics().density; + String customStyleUrl = getResources().getString(R.string.custom_style_url); + + requestOfflineRegionAdd("New York - Custom (14,15)", customStyleUrl, newYorkBounds, + 14, 15, pixelRatio); + requestOfflineMultiRegionAdd("Multi New York - Custom(14, 15)", customStyleUrl, newYorkMultBounds, + 14, 15, pixelRatio, true); + requestOfflineMultiRegionAdd("Chain New York - Custom(14, 15)", customStyleUrl, newYorkMultBounds, + 14, 15, pixelRatio, false); + + requestOfflineRegionAdd("Berlin - Custom (0,15)", customStyleUrl, berlinBounds, + 0, 15, 4); + requestOfflineRegionAdd("Hessen - Custom (0,15)", customStyleUrl, hessenBounds, + 0, 15, 4); + + requestOfflineMultiRegionAdd("Multi Hessen - Custom (1,15)", customStyleUrl, hessenRegions, + 0, 15, 4, true); + + requestOfflineMultiRegionAdd("Chain Hessen - Custom (1,15)", customStyleUrl, hessenRegions, + 0, 15, 4, false); + + // Now the same with MB style + requestOfflineRegionAdd("New York - MB (14,15)", Style.MAPBOX_STREETS, newYorkBounds, + 14, 15, pixelRatio); + requestOfflineMultiRegionAdd("Multi New York - MB (14,15)", Style.MAPBOX_STREETS, newYorkMultBounds, + 14, 15, pixelRatio, true); + + requestOfflineMultiRegionAdd("Chain New York - MB (14,15)", Style.MAPBOX_STREETS, newYorkMultBounds, + 14, 15, pixelRatio, false); + + requestOfflineRegionAdd("Berlin - MB (0,15)", Style.MAPBOX_STREETS, berlinBounds, + 0, 15, 4); + requestOfflineRegionAdd("Hessen - MB 0,15)", Style.MAPBOX_STREETS, hessenBounds, + 0, 15, 4); + + requestOfflineMultiRegionAdd("Multi Hessen - MB 0,15)", Style.MAPBOX_STREETS, hessenRegions, + 0, 15, 4, true); + + requestOfflineMultiRegionAdd("Chain Hessen - MB 0,15)", Style.MAPBOX_STREETS, hessenRegions, + 0, 15, 4, false); + + }; + +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/Region.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/Region.java new file mode 100644 index 0000000000..1be26d40ed --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/Region.java @@ -0,0 +1,43 @@ +package com.mapbox.mapboxsdk.testapp.activity.offline; + + +import com.mapbox.mapboxsdk.geometry.LatLngBounds; + + +public interface Region { + + interface OnStatusChangeListener { + void onStatusChanged(Region region); + } + + public String getName(); + + public LatLngBounds getBounds(); + + public String getStyleURL(); + + public double getMinZoom(); + + public double getMaxZoom(); + + public void startDownload(); + + public void stopDownload(); + + public long getDownloadTime(); + + public void startTrackingStatus(OnStatusChangeListener listener); + + public void stopTrackingStatus(); + + public boolean isComplete(); + + public boolean isDownloadStarted(); + + public long getRequiredResourceCount(); + + public long getCompletedResourceCount(); + + public long getCompletedResourceSize(); + +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/SimpleMapViewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/SimpleMapViewActivity.java new file mode 100644 index 0000000000..675cc98066 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/SimpleMapViewActivity.java @@ -0,0 +1,166 @@ +package com.mapbox.mapboxsdk.testapp.activity.offline; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; + +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; +import com.mapbox.mapboxsdk.constants.Style; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.MapboxMapOptions; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.testapp.R; + +/** + * The most basic example of adding a map to an activity. + */ +public class SimpleMapViewActivity extends AppCompatActivity { + + private static final String TAG = "TEST-OFFLINE"; + + public static final String BOUNDS_ARG = "BOUNDS"; + public static final String STYLE_ARG = "STYLE"; + public static final String MINZOOM_ARG = "MINZOOM"; + public static final String MAXZOOM_ARG = "MAXZOOM"; + + private MapView mapView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle bundle = getIntent().getExtras(); + final String styleUrl = getStyleUrl(bundle, Style.MAPBOX_STREETS); + final double minZoom = getZoom(bundle, MINZOOM_ARG, 0); + final double maxZoom = getZoom(bundle, MAXZOOM_ARG, 15); + final CameraPosition cameraPosition = getCameraPostion(bundle, minZoom, maxZoom); + + + Log.d(TAG, " >>>> StyleURl: =" + styleUrl); + Log.d(TAG, " >>>> Camera pos: =" + cameraPosition); + Log.d(TAG, " >>>> Min ZOOM: =" + minZoom); + Log.d(TAG, " >>>> Max ZOOM: =" + maxZoom); + + // configure inital map state +// +// // create map +// mapView = new MapView(this, options); + + mapView = new MapView(this); + mapView.setId(R.id.mapView); + mapView.onCreate(savedInstanceState); + setContentView(mapView); + + mapView.getMapAsync(new OnMapReadyCallback() { + @Override + public void onMapReady(MapboxMap mapboxMap) { + + // correct style + mapboxMap.setStyle(styleUrl); + + // position map on top of offline region + mapboxMap.setCameraPosition(cameraPosition); + + // restrict camera movement + mapboxMap.setMinZoomPreference(minZoom); + mapboxMap.setMaxZoomPreference(maxZoom); + // mapboxMap.setLatLngBoundsForCameraTarget(definition.getBounds()); + } + }); + + } + + + private CameraPosition getCameraPostion(Bundle bundle, double minZoom, double maxZoom) { + LatLng cameraPos = null; + if (bundle != null && bundle.containsKey(BOUNDS_ARG)) { + LatLngBounds latLngBounds = (LatLngBounds) bundle.getParcelable(BOUNDS_ARG); + if (latLngBounds != null) { + cameraPos = latLngBounds.getCenter(); + } + } + if (cameraPos == null) { + cameraPos = new LatLng(45.520486, -122.673541); + } + + return new CameraPosition.Builder() + .target(cameraPos) + .zoom(maxZoom > minZoom ? maxZoom - minZoom / 2 : maxZoom) + .build(); + } + + private String getStyleUrl(Bundle bundle, String defaultValue) { + if (bundle != null) { + return bundle.getString(STYLE_ARG, defaultValue); + } + + return defaultValue; + } + + private double getZoom(Bundle bundle, String arg, double defaultValue) { + if (bundle != null) { + return bundle.getDouble(arg, defaultValue); + } + + return defaultValue; + } + + private MapboxMapOptions getMapBoxOptions(Bundle bundle) { + + double minZoom = getZoom(bundle, MINZOOM_ARG, 0); + double maxZoom = getZoom(bundle, MAXZOOM_ARG, 15); + return new MapboxMapOptions() + .styleUrl(getStyleUrl(bundle, Style.MAPBOX_STREETS)) + .camera(getCameraPostion(bundle, minZoom, maxZoom)); + } + + + + // Add the mapView lifecycle to the activity's lifecycle methods + @Override + public void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + public void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/SingleRegion.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/SingleRegion.java new file mode 100644 index 0000000000..f9a933805a --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/SingleRegion.java @@ -0,0 +1,212 @@ +package com.mapbox.mapboxsdk.testapp.activity.offline; + +import android.util.Log; + +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +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 com.mapbox.mapboxsdk.testapp.utils.OfflineUtils; + +import java.util.concurrent.TimeUnit; + +public class SingleRegion implements Region { + + private static final String TAG = "TEST-OFFLINE"; + + private final String name; + private final OfflineRegion offlineRegion; + private OfflineRegionStatus lastReportedStatus = null; + private OnStatusChangeListener listener = null; + + public SingleRegion(OfflineRegion offlineRegion) { + this.name = OfflineUtils.convertRegionName(offlineRegion.getMetadata()); + this.offlineRegion = offlineRegion; + } + + public SingleRegion(String name, OfflineRegion offlineRegion) { + this.name = name; + this.offlineRegion = offlineRegion; + } + + @Override + public String getName() { + return name; + } + + @Override + public void startDownload() { + Log.d(TAG, ">>>>> START DOWNLOAD name=" +name); + offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE); + startMeasuringDownload(); + } + + @Override + public void stopDownload() { + Log.d(TAG, ">>>>> STOP DOWNLOAD name=" +name); + offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE); + stopMeasuringDownload(); + } + + @Override + public void startTrackingStatus(OnStatusChangeListener listener) { + + Log.d(TAG, ">>>>> Start Tracking name=" +name); + this.listener = listener; + + // Get observing offline region's status. + offlineRegion.getStatus(new OfflineRegion.OfflineRegionStatusCallback() { + @Override + public void onStatus(OfflineRegionStatus status) { + + lastReportedStatus = status; + + if (SingleRegion.this.listener != null) { + SingleRegion.this.listener.onStatusChanged(SingleRegion.this); + } + } + + @Override + public void onError(String error) { + Log.d(TAG, " Errro adding region : "+ error); + } + }); + + //Start observing offline region's status + offlineRegion.setObserver(new OfflineRegion.OfflineRegionObserver() { + @Override + public void onStatusChanged(OfflineRegionStatus status) { + + lastReportedStatus = status; + + if (SingleRegion.this.listener != null) { + SingleRegion.this.listener.onStatusChanged(SingleRegion.this); + } + + // Stop measuring downlaod ! + if (status.isComplete()) { + stopMeasuringDownload(); + } + } + + @Override + public void onError(OfflineRegionError error) { + Log.d(TAG, ">>>>> OfflineRegionError : reason=" +error.getReason() +" msg=" +error.getMessage()); + + } + + @Override + public void mapboxTileCountLimitExceeded(long limit) { + Log.d(TAG, ">>>>> mapboxTileCountLimitExceeded " + limit); + + } + }); + } + + @Override + public void stopTrackingStatus() { + Log.d(TAG, ">>>>> Stop Tracking name=" +name); + this.listener = null; + offlineRegion.setObserver(null); + } + + @Override + public LatLngBounds getBounds() { + return offlineRegion.getDefinition().getBounds(); + } + + @Override + public String getStyleURL() { + OfflineTilePyramidRegionDefinition definition = + (OfflineTilePyramidRegionDefinition)offlineRegion.getDefinition(); + return definition.getStyleURL(); + } + + @Override + public double getMinZoom() { + OfflineTilePyramidRegionDefinition definition = + (OfflineTilePyramidRegionDefinition)offlineRegion.getDefinition(); + return definition.getMinZoom(); + } + + @Override + public double getMaxZoom() { + OfflineTilePyramidRegionDefinition definition = + (OfflineTilePyramidRegionDefinition)offlineRegion.getDefinition(); + return definition.getMaxZoom(); + } + + + @Override + public boolean isComplete() { + if (lastReportedStatus != null) { + return lastReportedStatus.isComplete(); + } + + return false; + } + + @Override + public boolean isDownloadStarted() { + if (lastReportedStatus != null) { + return lastReportedStatus.getDownloadState() == OfflineRegion.STATE_ACTIVE; + } + + return false; + } + + @Override + public long getRequiredResourceCount() { + return lastReportedStatus == null ? 0 : lastReportedStatus.getRequiredResourceCount(); + } + + @Override + public long getCompletedResourceCount() { + return lastReportedStatus == null ? 0 : lastReportedStatus.getCompletedResourceCount(); + } + + @Override + public long getCompletedResourceSize() { + return lastReportedStatus == null ? 0 : lastReportedStatus.getCompletedResourceSize(); + } + + + private long startTime = 0; + private long downloadTime = 0; + + @Override + public long getDownloadTime() { + if (startTime > 0) { + downloadTime = System.currentTimeMillis() - startTime; + } + return downloadTime; + } + + + private void startMeasuringDownload() { + startTime = System.currentTimeMillis(); + } + + private void stopMeasuringDownload() { + downloadTime = System.currentTimeMillis() - startTime; + + Log.d("TEST-OFFLINE", " >>>>> It took " + + TimeUnit.MILLISECONDS.toMinutes(downloadTime) + " minutes to load " + + getSize(getCompletedResourceSize()) + " the map of " +name); + + startTime = 0; + } + + private static String getSize(long size) { + if (size == 0) { + return "0 B"; + } else if (size < 1024) { + return size + " B"; + } else if (size < 1048576){ + return size / 1024 + " KB"; + } else { + return size /1048576 + " MB"; + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_map_form.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_map_form.xml new file mode 100644 index 0000000000..4b680cd9d2 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_map_form.xml @@ -0,0 +1,194 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="20dp" + android:paddingRight="20dp" + android:paddingTop="10dp"> + + <!-- Region Name --> + <TextView + android:id="@+id/name_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp" + android:text="REGION NAME:" /> + + <EditText + android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_toRightOf="@id/name_label" + android:layout_toEndOf="@id/name_label" + android:layout_alignBaseline="@id/name_label" + android:hint="Enter Region Name" /> + + <!-- Style --> + <TextView + android:id="@+id/style_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/name_label" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp" + android:text="STYLE:" /> + + <Spinner + android:id="@+id/style" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/name" + android:layout_toRightOf="@id/style_label" + android:layout_toEndOf="@id/style_label" + android:layout_alignBaseline="@id/style_label"/> + + <!-- Min Zoom --> + <TextView + android:id="@+id/minzoom_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/style_label" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp" + android:text="MIN ZOOM:"/> + + <TextView + android:id="@+id/minzoom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/style_label" + android:layout_alignBaseline="@id/minzoom_label" + android:layout_toRightOf="@+id/minzoom_label" + android:layout_toEndOf="@+id/minzoom_label" + android:text="0"/> + + <SeekBar + android:id="@+id/minzoom_slider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/style_label" + android:layout_toRightOf="@+id/minzoom" + android:layout_toEndOf="@+id/minzoom" + android:layout_alignParentRight="true" + android:layout_alignParentEnd="true" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp"/> + + <!-- Max Zoom --> + <TextView + android:id="@+id/maxzoom_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/minzoom_label" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp" + android:text="MAX ZOOM: "/> + + <TextView + android:id="@+id/maxzoom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/minzoom_label" + android:layout_alignBaseline="@id/maxzoom_label" + android:layout_toRightOf="@+id/maxzoom_label" + android:layout_toEndOf="@+id/maxzoom_label" + android:text="25"/> + + <SeekBar + android:id="@+id/maxzoom_slider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/minzoom_label" + android:layout_toRightOf="@+id/maxzoom" + android:layout_toEndOf="@+id/maxzoom" + android:layout_alignParentRight="true" + android:layout_alignParentEnd="true" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp"/> + + + <LinearLayout + android:id="@+id/north_east_lat_lon" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/maxzoom_label" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp" + android:orientation="horizontal"> + + <TextView + android:id="@+id/north_east_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="NORTH EAST:" /> + + <EditText + android:id="@+id/lat_north" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:inputType="numberSigned|numberDecimal" + android:layout_weight="1"/> + + <EditText + android:id="@+id/lon_east" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:inputType="numberSigned|numberDecimal" + android:layout_weight="1"/> + </LinearLayout> + + + <LinearLayout + android:id="@+id/south_west_lat_lon" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/north_east_lat_lon" + android:layout_marginBottom="10dp" + android:layout_marginTop="10dp" + android:orientation="horizontal"> + + <TextView + android:id="@+id/south_west_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="SOUTH WEST:" /> + + <EditText + android:id="@+id/lat_south" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:inputType="numberSigned|numberDecimal" + android:layout_weight="1"/> + + <EditText + android:id="@+id/lon_west" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:inputType="numberSigned|numberDecimal" + android:layout_weight="1"/> + </LinearLayout> + + + <Button + android:id="@+id/action_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/south_west_lat_lon" + android:text="Start Download"/> + + <TextView + android:id="@+id/download_progress" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignBottom="@id/action_button" + android:layout_below="@id/south_west_lat_lon" + android:layout_toRightOf="@id/action_button" + android:layout_toEndOf="@id/action_button" + android:layout_alignBaseline="@id/action_button" + android:text="0B, 0%" /> + + + +</RelativeLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_list.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_list.xml new file mode 100644 index 0000000000..cae030471d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_list.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ListView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/areas" /> + +</RelativeLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/offline_region_list_item.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/offline_region_list_item.xml new file mode 100644 index 0000000000..7b2a1486e7 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/offline_region_list_item.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/list_item" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="20dp" + android:paddingStart="20dp" + android:paddingRight="20dp" + android:paddingEnd="20dp" + android:paddingTop="10dp" + android:paddingBottom="10dp"> + + <TextView + android:id="@+id/area_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Hessen" + android:textSize="24sp" /> + + <TextView + android:id="@+id/size" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/area_name" + android:text="" + /> + + + <ImageView + android:id="@+id/state_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_centerVertical="true" + android:adjustViewBounds="false" + android:src="@mipmap/ic_file_download_black_24dp" /> + +</RelativeLayout>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_autorenew_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_autorenew_black_24dp.png Binary files differnew file mode 100644 index 0000000000..39be19e473 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_autorenew_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_file_download_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_file_download_black_24dp.png Binary files differnew file mode 100644 index 0000000000..d9aacea4c6 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_file_download_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_play_arrow_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_play_arrow_black_24dp.png Binary files differnew file mode 100644 index 0000000000..e9c288c991 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-hdpi/ic_play_arrow_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_autorenew_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_autorenew_black_24dp.png Binary files differnew file mode 100644 index 0000000000..2c9f369779 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_autorenew_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_file_download_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_file_download_black_24dp.png Binary files differnew file mode 100644 index 0000000000..c2c845e849 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_file_download_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_play_arrow_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_play_arrow_black_24dp.png Binary files differnew file mode 100644 index 0000000000..d78c57bad5 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-mdpi/ic_play_arrow_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_autorenew_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_autorenew_black_24dp.png Binary files differnew file mode 100644 index 0000000000..217fe38112 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_autorenew_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_file_download_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_file_download_black_24dp.png Binary files differnew file mode 100644 index 0000000000..f5afb24dc5 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_file_download_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_play_arrow_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_play_arrow_black_24dp.png Binary files differnew file mode 100644 index 0000000000..f208795fcc --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xhdpi/ic_play_arrow_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_autorenew_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_autorenew_black_24dp.png Binary files differnew file mode 100644 index 0000000000..910746ecc4 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_autorenew_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_file_download_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_file_download_black_24dp.png Binary files differnew file mode 100644 index 0000000000..ce97c85dfa --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_file_download_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_play_arrow_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_play_arrow_black_24dp.png Binary files differnew file mode 100644 index 0000000000..5345ee3c4a --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxhdpi/ic_play_arrow_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_autorenew_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_autorenew_black_24dp.png Binary files differnew file mode 100644 index 0000000000..3c0b5d203d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_autorenew_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_file_download_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_file_download_black_24dp.png Binary files differnew file mode 100644 index 0000000000..8c83bffa7e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_file_download_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_play_arrow_black_24dp.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_play_arrow_black_24dp.png Binary files differnew file mode 100644 index 0000000000..d12d495622 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/mipmap-xxxhdpi/ic_play_arrow_black_24dp.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index d0aab04d93..8c87a2007a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -24,6 +24,8 @@ <string name="description_offline">Offline Map example</string> <string name="description_update_metadata">Update metadata example</string> <string name="description_offline_region_delete">Delete region example</string> + <string name="description_offline_regions_list">List offline regions example</string> + <string name="description_offline_map_form">Form to download offline map</string> <string name="description_animated_marker">Animate the position change of a marker</string> <string name="description_polyline">Add a polyline to a map</string> <string name="description_polygon">Add a polygon to a map</string> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index b90cedc518..273018ece6 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -32,6 +32,8 @@ <string name="activity_offline">Offline Map</string> <string name="activity_update_metadata">Update metadata Map</string> <string name="activity_offline_region_delete">Delete region</string> + <string name="activity_offline_regions_list">List offline regions</string> + <string name="activity_offline_map_form">Download offline map form</string> <string name="activity_minmax_zoom">Min/Max Zoom</string> <string name="activity_viewpager">ViewPager</string> <string name="activity_runtime_style">Runtime Style</string> |