com.nextgis.maplibui.service.LayerFillService.java Source code

Java tutorial

Introduction

Here is the source code for com.nextgis.maplibui.service.LayerFillService.java

Source

/*
 * Project:  NextGIS Mobile
 * Purpose:  Mobile GIS for Android.
 * Author:   Dmitry Baryshnikov (aka Bishop), bishop.dev@gmail.com
 * Author:   Stanislav Petriakov, becomeglory@gmail.com
 * *****************************************************************************
 * Copyright (c) 2015-2017 NextGIS, info@nextgis.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.nextgis.maplibui.service;

import android.accounts.Account;
import android.accounts.AccountsException;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.nextgis.maplib.api.IGISApplication;
import com.nextgis.maplib.api.ILayer;
import com.nextgis.maplib.api.IProgressor;
import com.nextgis.maplib.datasource.Field;
import com.nextgis.maplib.datasource.GeoGeometryFactory;
import com.nextgis.maplib.map.Layer;
import com.nextgis.maplib.map.LayerGroup;
import com.nextgis.maplib.map.MapBase;
import com.nextgis.maplib.map.NGWLookupTable;
import com.nextgis.maplib.map.NGWVectorLayer;
import com.nextgis.maplib.map.TMSLayer;
import com.nextgis.maplib.map.VectorLayer;
import com.nextgis.maplib.util.Constants;
import com.nextgis.maplib.util.FileUtil;
import com.nextgis.maplib.util.GeoConstants;
import com.nextgis.maplib.util.GeoJSONUtil;
import com.nextgis.maplib.util.NGException;
import com.nextgis.maplib.util.NGWUtil;
import com.nextgis.maplibui.R;
import com.nextgis.maplibui.mapui.LocalTMSLayerUI;
import com.nextgis.maplibui.mapui.NGWVectorLayerUI;
import com.nextgis.maplibui.mapui.VectorLayerUI;
import com.nextgis.maplibui.util.ConstantsUI;
import com.nextgis.maplibui.util.LayerUtil;
import com.nextgis.maplibui.util.NotificationHelper;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * Service for filling layers with data
 */
public class LayerFillService extends Service implements IProgressor {
    protected NotificationManager mNotifyManager;
    protected List<LayerFillTask> mQueue;
    protected static final int FILL_NOTIFICATION_ID = 9;
    protected NotificationCompat.Builder mBuilder;

    public final static int VECTOR_LAYER = 1;
    public final static int VECTOR_LAYER_WITH_FORM = 2;
    public final static int TMS_LAYER = 3;
    public final static int NGW_LAYER = 4;

    public static final String ACTION_STOP = "com.nextgis.maplibui.FILL_LAYER_STOP";
    public static final String ACTION_ADD_TASK = "com.nextgis.maplibui.ADD_FILL_LAYER_TASK";
    public static final String ACTION_SHOW = "com.nextgis.maplibui.SHOW_PROGRESS_DIALOG";
    public static final String ACTION_UPDATE = "com.nextgis.maplibui.UPDATE_FILL_LAYER_PROGRESS";
    public static final String KEY_STATUS = "status";
    public static final String KEY_PROGRESS = "progress";
    public static final String KEY_TOTAL = "count";
    public static final String KEY_TITLE = "title";
    public static final String KEY_MESSAGE = "message";
    public static final String KEY_CANCELLED = "cancel";
    public static final String KEY_RESULT = "result";
    public static final String KEY_SYNC = "sync";
    public static final String KEY_URI = "uri";
    public static final String KEY_PATH = "path";
    public static final String KEY_LAYER_PATH = "layer_path";
    public static final String KEY_REMOTE_ID = "remote_id";
    public static final String KEY_LOOKUP_ID = "lookup_id";
    public static final String KEY_ACCOUNT = "account";
    public static final String KEY_NAME = "name";
    public static final String KEY_INPUT_TYPE = "input_type";
    public static final String KEY_DELETE_SRC_FILE = "delete_source_file";
    public static final String KEY_LAYER_GROUP_ID = "layer_group_id";
    public static final String KEY_TMS_TYPE = "tms_type";
    public static final String KEY_TMS_CACHE = "tms_cache";
    public static final String NGFP_META = "ngfp_meta.json";
    protected final static String NGFP_FILE_META = "meta.json";
    protected final static String NGFP_FILE_DATA = "data.geojson";

    public static final short STATUS_START = 0;
    public static final short STATUS_UPDATE = 1;
    public static final short STATUS_STOP = 2;
    public static final short STATUS_SHOW = 3;

    protected int mProgressMax;
    protected int mProgressValue;
    protected LayerGroup mLayerGroup;
    protected long mLastUpdate = 0;
    protected String mProgressMessage;
    protected boolean mIndeterminate;
    protected boolean mIsCanceled;
    protected boolean mIsRunning;
    protected Handler mHandler;
    protected Intent mProgressIntent;

    protected static final String BUNDLE_MSG_KEY = "error_message";

    @Override
    public void onCreate() {
        mNotifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Bitmap largeIcon = NotificationHelper.getLargeIcon(R.drawable.ic_notification_download, getResources());

        mProgressIntent = new Intent(ACTION_UPDATE);
        Intent intent = new Intent(this, LayerFillService.class);
        intent.setAction(ACTION_STOP);
        PendingIntent stopService = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        intent.setAction(ACTION_SHOW);
        PendingIntent showProgressDialog = PendingIntent.getService(this, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        mBuilder = new NotificationCompat.Builder(this);
        mBuilder.setSmallIcon(R.drawable.ic_notification_download).setLargeIcon(largeIcon).setAutoCancel(false)
                .setOngoing(true).setContentIntent(showProgressDialog)
                .addAction(R.drawable.ic_action_cancel_dark, getString(R.string.tracks_stop), stopService);
        mIsCanceled = false;

        mQueue = new LinkedList<>();
        mIsRunning = false;
        mHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Bundle resultData = msg.getData();
                Toast.makeText(LayerFillService.this, resultData.getString(BUNDLE_MSG_KEY), Toast.LENGTH_LONG)
                        .show();
            }
        };

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("LayerFillService", "Received start id " + startId + ": " + intent);
        if (intent != null) {
            String action = intent.getAction();

            if (!TextUtils.isEmpty(action)) {
                switch (action) {
                case ACTION_ADD_TASK:
                    int layerGroupId = intent.getIntExtra(KEY_LAYER_GROUP_ID, Constants.NOT_FOUND);
                    mLayerGroup = (LayerGroup) MapBase.getInstance().getLayerById(layerGroupId);

                    Bundle extra = intent.getExtras();
                    int layerType = extra.getInt(KEY_INPUT_TYPE, Constants.NOT_FOUND);

                    switch (layerType) {
                    case VECTOR_LAYER:
                        mQueue.add(new VectorLayerFillTask(extra));
                        break;
                    case VECTOR_LAYER_WITH_FORM:
                        mQueue.add(new UnzipForm(extra));
                        break;
                    case TMS_LAYER:
                        mQueue.add(new LocalTMSFillTask(extra));
                        break;
                    case NGW_LAYER:
                        mQueue.add(new NGWVectorLayerFillTask(extra));
                        break;
                    }

                    if (!mIsRunning) {
                        startNextTask();
                    }

                    return START_STICKY;
                case ACTION_STOP:
                    mQueue.clear();
                    mIsCanceled = true;
                    break;
                case ACTION_SHOW:
                    mProgressIntent.putExtra(KEY_STATUS, STATUS_SHOW).putExtra(KEY_TITLE, mBuilder.mContentTitle);
                    sendBroadcast(mProgressIntent);
                    break;
                }
            }
        }
        return START_STICKY;
    }

    protected void startNextTask() {
        if (mQueue.isEmpty()) {
            mNotifyManager.cancel(FILL_NOTIFICATION_ID);
            stopSelf();
            return;
        }

        mIsCanceled = false;
        final IProgressor progressor = this;
        new Thread(new Runnable() {
            @Override
            public void run() {
                mIsRunning = true;
                LayerFillTask task = mQueue.remove(0);
                String notifyTitle = task.getDescription();

                mBuilder.setWhen(System.currentTimeMillis()).setContentTitle(notifyTitle).setTicker(notifyTitle);
                mNotifyManager.notify(FILL_NOTIFICATION_ID, mBuilder.build());

                if (mProgressIntent.getExtras() != null)
                    mProgressIntent.getExtras().clear();

                mProgressIntent.putExtra(KEY_STATUS, STATUS_START).putExtra(KEY_TITLE, notifyTitle);
                sendBroadcast(mProgressIntent);

                Process.setThreadPriority(Constants.DEFAULT_DOWNLOAD_THREAD_PRIORITY);
                progressor.setValue(0);
                boolean result = task.execute(progressor);

                if (!(task instanceof UnzipForm))
                    mProgressIntent.putExtra(KEY_MESSAGE, mProgressMessage);

                mProgressIntent.putExtra(KEY_STATUS, STATUS_STOP);
                mProgressIntent.putExtra(KEY_CANCELLED, mIsCanceled);
                mProgressIntent.putExtra(KEY_RESULT, result);
                mProgressIntent.putExtra(KEY_TOTAL, mQueue.size());

                if (result) {
                    mLayerGroup.addLayer(task.getLayer());
                    mLayerGroup.save();
                } else
                    task.cancel();

                if (task instanceof NGWVectorLayerFillTask && ((NGWVectorLayerFillTask) task).showSyncDialog()) {
                    mProgressIntent.putExtra(KEY_SYNC, true);
                    mProgressIntent.putExtra(KEY_ACCOUNT, ((NGWVectorLayerFillTask) task).getAccountName());
                    mProgressIntent.putExtra(KEY_REMOTE_ID, (task.getLayer().getId()));
                }

                sendBroadcast(mProgressIntent);
                mIsRunning = false;
                startNextTask();
            }
        }).start();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void setMax(int maxValue) {
        mProgressMax = maxValue;
    }

    @Override
    public boolean isCanceled() {
        return mIsCanceled;
    }

    @Override
    public void setValue(int value) {
        mProgressValue = value;
        updateNotify();
    }

    @Override
    public void setIndeterminate(boolean indeterminate) {
        mIndeterminate = indeterminate;
        updateNotify();
    }

    @Override
    public void setMessage(String message) {
        mProgressMessage = message;
        updateNotify();
    }

    protected void updateNotify() {
        if (mLastUpdate + ConstantsUI.NOTIFICATION_DELAY < System.currentTimeMillis()) {
            mLastUpdate = System.currentTimeMillis();
            mBuilder.setProgress(mProgressMax, mProgressValue, mIndeterminate).setContentText(mProgressMessage);
            // Displays the progress bar for the first time.
            mNotifyManager.notify(FILL_NOTIFICATION_ID, mBuilder.build());
        }

        mProgressIntent.getExtras().clear();
        mProgressIntent.putExtra(KEY_STATUS, STATUS_UPDATE).putExtra(KEY_TOTAL, mProgressMax)
                .putExtra(KEY_PROGRESS, mProgressValue).putExtra(KEY_MESSAGE, mProgressMessage);
        sendBroadcast(mProgressIntent);
    }

    private void notifyError(String error) {
        Bundle bundle = new Bundle();
        bundle.putString(BUNDLE_MSG_KEY, error);

        Message msg = new Message();
        msg.setData(bundle);
        mHandler.sendMessage(msg);
    }

    /**
     * task classes
     */

    private abstract class LayerFillTask {
        String mLayerName;
        File mLayerPath;
        Uri mUri;
        protected Layer mLayer;

        LayerFillTask(Bundle bundle) {
            mUri = bundle.getParcelable(KEY_URI);
            mLayerName = bundle.getString(KEY_NAME);
            mLayerPath = bundle.containsKey(KEY_LAYER_PATH) ? (File) bundle.getSerializable(KEY_LAYER_PATH)
                    : mLayerGroup.createLayerStorage();
        }

        void initLayer() {
            mLayer.setName(mLayerName);
            mLayer.setVisible(true);
            mLayer.setMinZoom(GeoConstants.DEFAULT_MIN_ZOOM);
            mLayer.setMaxZoom(GeoConstants.DEFAULT_MAX_ZOOM);
        }

        public abstract boolean execute(IProgressor progressor);

        public String getDescription() {
            if (null == mLayer)
                return "";
            return getString(R.string.processing) + " " + mLayer.getName();
        }

        public ILayer getLayer() {
            return mLayer;
        }

        public void cancel() {
            if (mLayer != null)
                mLayer.delete();
            else if (mLayerPath != null)
                FileUtil.deleteRecursive(mLayerPath);
        }
    }

    private class VectorLayerFillTask extends LayerFillTask {
        VectorLayerFillTask(Bundle bundle) {
            super(bundle);
            mLayer = new VectorLayerUI(mLayerGroup.getContext(), mLayerPath);
            initLayer();
        }

        @Override
        public boolean execute(IProgressor progressor) {
            try {
                VectorLayer vectorLayer = (VectorLayer) mLayer;
                if (null == vectorLayer)
                    return false;

                vectorLayer.createFromGeoJson(mUri, progressor);
            } catch (IOException | JSONException | SQLiteException | NGException | ClassCastException e) {
                e.printStackTrace();

                if (null != progressor)
                    progressor.setMessage(e.getLocalizedMessage());

                setMessage(e.getLocalizedMessage());
                notifyError(mProgressMessage);
                return false;
            }

            return true;
        }
    }

    private class UnzipForm extends LayerFillTask {

        UnzipForm(Bundle bundle) {
            super(bundle);
        }

        @Override
        public boolean execute(IProgressor progressor) {
            try {
                InputStream inputStream = getContentResolver().openInputStream(mUri);
                if (inputStream != null) {
                    int nSize = inputStream.available();
                    int nIncrement = 0;
                    byte[] buffer = new byte[Constants.IO_BUFFER_SIZE];
                    progressor.setMax(nSize);
                    progressor.setMessage(getString(R.string.message_loading));

                    ZipInputStream zis = new ZipInputStream(inputStream);
                    ZipEntry ze;
                    while ((ze = zis.getNextEntry()) != null) {
                        if (isCanceled())
                            return false;

                        FileUtil.unzipEntry(zis, ze, buffer, mLayerPath);
                        nIncrement += ze.getSize();
                        zis.closeEntry();
                        progressor.setValue(nIncrement);
                    }
                    zis.close();

                    //read meta.json
                    File meta = new File(mLayerPath, NGFP_FILE_META);
                    String jsonText = FileUtil.readFromFile(meta);
                    JSONObject metaJson = new JSONObject(jsonText);
                    File dataFile = new File(mLayerPath, NGFP_FILE_DATA);
                    Bundle extra = new Bundle();
                    extra.putSerializable(KEY_LAYER_PATH, mLayerPath);
                    extra.putString(KEY_NAME, mLayerName);

                    //read if this local o remote source
                    boolean isNgwConnection = metaJson.has(ConstantsUI.JSON_NGW_CONNECTION_KEY)
                            && !metaJson.isNull(ConstantsUI.JSON_NGW_CONNECTION_KEY);
                    if (isNgwConnection) {
                        FileUtil.deleteRecursive(dataFile);
                        JSONObject connection = metaJson.getJSONObject(ConstantsUI.JSON_NGW_CONNECTION_KEY);

                        //read url
                        String url = connection.getString("url");
                        if (!url.startsWith("http")) {
                            url = "http://" + url;
                        }

                        //read login
                        String login = connection.getString("login");
                        //read password
                        String password = connection.getString("password");
                        //read id
                        long resourceId = connection.getLong("id");
                        //check account exist and try to create

                        FileUtil.deleteRecursive(meta);

                        String accountName = "";
                        URI uri = new URI(url);

                        if (uri.getHost() != null && uri.getHost().length() > 0) {
                            accountName += uri.getHost();
                        }
                        if (uri.getPort() != 80 && uri.getPort() > 0) {
                            accountName += ":" + uri.getPort();
                        }
                        if (uri.getPath() != null && uri.getPath().length() > 0) {
                            accountName += uri.getPath();
                        }

                        IGISApplication app = (IGISApplication) getApplicationContext();
                        Account account = app.getAccount(accountName);
                        if (null == account) {
                            //create account
                            if (!app.addAccount(accountName, url, login, password, "ngw")) {
                                throw new AccountsException(getString(R.string.ngw_account_already_exists));
                            }
                        } else {
                            //compare login/password and report differences
                            String savedPassword = app.getAccountPassword(account);
                            String savedLogin = app.getAccountLogin(account);
                            boolean same = false;
                            if (savedPassword != null && savedLogin != null)
                                same = savedPassword.equals(password) && savedLogin.equals(login);
                            else {
                                if (savedLogin == null)
                                    same = login == null;
                                if (savedPassword == null)
                                    same = password == null;
                            }

                            if (!same) {
                                Intent msg = new Intent(ConstantsUI.MESSAGE_INTENT);
                                msg.putExtra(ConstantsUI.KEY_MESSAGE,
                                        getString(R.string.ngw_different_credentials));
                                sendBroadcast(msg);
                            }
                        }

                        File form = new File(mLayerPath, ConstantsUI.FILE_FORM);
                        ArrayList<String> lookupTableIds = LayerUtil.fillLookupTableIds(form);

                        extra.putStringArrayList(KEY_LOOKUP_ID, lookupTableIds);
                        extra.putLong(KEY_REMOTE_ID, resourceId);
                        extra.putString(KEY_ACCOUNT, accountName);
                        extra.putBoolean(KEY_SYNC, true);

                        if (!isCanceled())
                            mQueue.add(new NGWVectorLayerFillTask(extra));
                    } else {
                        // prevent overwrite meta.json by layer save routine
                        //noinspection ResultOfMethodCallIgnored
                        meta.renameTo(new File(meta.getParentFile(), LayerFillService.NGFP_META));

                        extra.putSerializable(LayerFillService.KEY_PATH, dataFile);
                        extra.putBoolean(LayerFillService.KEY_DELETE_SRC_FILE, true);

                        if (!isCanceled())
                            mQueue.add(new VectorLayerFormFillTask(extra));
                    }
                }
            } catch (AccountsException | JSONException | IOException | URISyntaxException | RuntimeException e) {
                e.printStackTrace();

                if (null != progressor)
                    progressor.setMessage(e.getLocalizedMessage());

                setMessage(e.getMessage());
                notifyError(mProgressMessage);
                return false;
            }

            return true;
        }
    }

    private class VectorLayerFormFillTask extends LayerFillTask {
        File mPath;
        boolean mDeletePath;

        VectorLayerFormFillTask(Bundle bundle) {
            super(bundle);
            mPath = (File) bundle.getSerializable(KEY_PATH);
            mDeletePath = bundle.getBoolean(KEY_DELETE_SRC_FILE, false);
            mLayer = new VectorLayerUI(mLayerGroup.getContext(), mLayerPath);
            initLayer();
        }

        @Override
        public boolean execute(IProgressor progressor) {
            try {
                VectorLayer vectorLayer = (VectorLayer) mLayer;
                if (null == vectorLayer)
                    return false;
                File meta = new File(mPath.getParentFile(), NGFP_META);

                if (meta.exists()) {
                    String jsonText = FileUtil.readFromFile(meta);
                    JSONObject metaJson = new JSONObject(jsonText);
                    //read fields
                    List<Field> fields = NGWUtil.getFieldsFromJson(metaJson.getJSONArray(NGWUtil.NGWKEY_FIELDS));
                    //read geometry type
                    String geomTypeString = metaJson.getString("geometry_type");
                    int geomType = GeoGeometryFactory.typeFromString(geomTypeString);
                    vectorLayer.create(geomType, fields);

                    if (GeoJSONUtil.isGeoJsonHasFeatures(mPath)) {
                        //read SRS -- not need as we will be fill layer with 3857
                        JSONObject srs = metaJson.getJSONObject("srs");
                        int nSRS = srs.getInt(NGWUtil.NGWKEY_ID);
                        vectorLayer.fillFromGeoJson(mPath, nSRS, progressor);
                    }

                    FileUtil.deleteRecursive(meta);
                } else
                    vectorLayer.createFromGeoJson(mPath, progressor);
            } catch (IOException | JSONException | SQLiteException | NGException | ClassCastException e) {
                e.printStackTrace();

                if (null != progressor)
                    progressor.setMessage(e.getLocalizedMessage());

                setMessage(e.getLocalizedMessage());
                notifyError(mProgressMessage);
                return false;
            }

            if (mDeletePath)
                FileUtil.deleteRecursive(mPath);

            return true;
        }
    }

    private class LocalTMSFillTask extends LayerFillTask {
        boolean mIsNgrc;

        LocalTMSFillTask(Bundle bundle) {
            super(bundle);
            mLayer = new LocalTMSLayerUI(mLayerGroup.getContext(), mLayerPath);
            mIsNgrc = !bundle.containsKey(KEY_TMS_TYPE);
            ((LocalTMSLayerUI) mLayer).setCacheSizeMultiply(bundle.getInt(KEY_TMS_CACHE));

            if (!mIsNgrc) { // it's zip
                ((LocalTMSLayerUI) mLayer).setTMSType(bundle.getInt(KEY_TMS_TYPE));
                initLayer();
            } else
                mLayerName = mUri.getLastPathSegment();
        }

        @Override
        public boolean execute(IProgressor progressor) {
            try {
                TMSLayer tmsLayer = (TMSLayer) mLayer;
                if (null == tmsLayer)
                    return false;

                if (mIsNgrc)
                    tmsLayer.fillFromNgrc(mUri, progressor);
                else
                    tmsLayer.fillFromZip(mUri, progressor);
            } catch (IOException | NGException | RuntimeException e) {
                e.printStackTrace();

                if (null != progressor)
                    progressor.setMessage(e.getLocalizedMessage());

                setMessage(e.getLocalizedMessage());
                notifyError(mProgressMessage);
                return false;
            }

            return true;
        }

        @Override
        public String getDescription() {
            return mIsNgrc ? mLayerName : super.getDescription();
        }
    }

    private class NGWVectorLayerFillTask extends LayerFillTask {
        private ArrayList<String> mLookupIds = new ArrayList<>();
        private boolean mShowSyncDialog;

        NGWVectorLayerFillTask(Bundle bundle) {
            super(bundle);
            mLayer = new NGWVectorLayerUI(mLayerGroup.getContext(), mLayerPath);
            ((NGWVectorLayerUI) mLayer).setRemoteId(bundle.getLong(KEY_REMOTE_ID));
            ((NGWVectorLayerUI) mLayer).setAccountName(bundle.getString(KEY_ACCOUNT));
            initLayer();

            if (bundle.containsKey(KEY_LOOKUP_ID))
                mLookupIds = bundle.getStringArrayList(KEY_LOOKUP_ID);

            mShowSyncDialog = bundle.getBoolean(KEY_SYNC, false);

            for (int i = 0; i < mLayerGroup.getLayerCount(); i++) {
                if (mLayerGroup.getLayer(i) instanceof NGWLookupTable) {
                    NGWLookupTable table = (NGWLookupTable) mLayerGroup.getLayer(i);
                    String id = table.getRemoteId() + "";
                    if (table.getAccountName().equals(bundle.getString(KEY_ACCOUNT)) && mLookupIds.contains(id))
                        mLookupIds.remove(id);
                }
            }
        }

        @Override
        public boolean execute(IProgressor progressor) {
            try {
                NGWVectorLayer ngwVectorLayer = (NGWVectorLayer) mLayer;
                if (null == ngwVectorLayer)
                    return false;

                for (String id : mLookupIds) {
                    NGWLookupTable table = new NGWLookupTable(mLayer.getContext(),
                            mLayerGroup.createLayerStorage());
                    table.setAccountName(((NGWVectorLayer) mLayer).getAccountName());
                    table.setRemoteId(Long.parseLong(id));
                    table.setSyncType(Constants.SYNC_ALL);
                    table.setName(getText(R.string.layer_lookuptable) + " #" + id);
                    table.fillFromNGW(null);
                    mLayerGroup.addLayer(table);
                }

                ngwVectorLayer.createFromNGW(progressor);
            } catch (JSONException | IOException | SQLiteException | NGException | ClassCastException e) {
                e.printStackTrace();

                if (null != progressor)
                    progressor.setMessage(e.getLocalizedMessage());

                setMessage(e.getLocalizedMessage());
                notifyError(mProgressMessage);
                return false;
            }

            return true;
        }

        boolean showSyncDialog() {
            return mShowSyncDialog;
        }

        String getAccountName() {
            return ((NGWVectorLayerUI) mLayer).getAccountName();
        }
    }
}