| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.weex.extend.module.location; |
| |
| import android.Manifest; |
| import android.content.Context; |
| import android.content.pm.PackageManager; |
| import android.location.Address; |
| import android.location.Criteria; |
| import android.location.Geocoder; |
| import android.location.Location; |
| import android.location.LocationListener; |
| import android.location.LocationManager; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.support.v4.app.ActivityCompat; |
| import android.text.TextUtils; |
| |
| import com.taobao.weex.WXEnvironment; |
| import com.taobao.weex.WXSDKInstance; |
| import com.taobao.weex.bridge.SimpleJSCallback; |
| import com.taobao.weex.utils.WXLogUtils; |
| |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.UUID; |
| |
| public class DefaultLocation implements ILocatable { |
| |
| private static final String TAG = "DefaultLocation"; |
| private static final int TIME_OUT_WHAT = 0x11; |
| |
| private Map<String, WXLocationListener> mRegisterSucCallbacks = new HashMap<>(); |
| private List<WXLocationListener> mWXLocationListeners = new ArrayList<>(); |
| private WXSDKInstance mWXSDKInstance; |
| private LocationManager mLocationManager; |
| |
| private static final int GPS_TIMEOUT = 15000; |
| private int MIN_TIME = 20000; |
| private int MIN_DISTANCE = 5; |
| |
| public DefaultLocation(WXSDKInstance instance) { |
| mWXSDKInstance = instance; |
| } |
| |
| @Override |
| public void setWXSDKInstance(WXSDKInstance WXSDKInstance) { |
| mWXSDKInstance = WXSDKInstance; |
| } |
| |
| @Override |
| public void getCurrentPosition(final String successCallback, final String errorCallback, final String params) { |
| WXLogUtils.d(TAG, "into--[getCurrentPosition] successCallback:" + successCallback + " \nerrorCallback:" + errorCallback + " \nparams:" + params); |
| if (!TextUtils.isEmpty(params)) { |
| try { |
| JSONObject jsObj = new JSONObject(params); |
| boolean enableHighAccuracy = jsObj.optBoolean("enableHighAccuracy"); |
| boolean enableAddress = jsObj.optBoolean("address"); |
| WXLocationListener listener = findLocation(null, successCallback, errorCallback, enableHighAccuracy, enableAddress); |
| if (listener != null) { |
| mWXLocationListeners.add(listener); |
| } |
| return; |
| } catch (JSONException e) { |
| WXLogUtils.e(TAG, e); |
| } |
| } |
| Map<String, Object> options = new HashMap<>(); |
| options.put(ERROR_CODE, ErrorCode.PARAMS_ERROR); |
| options.put(ERROR_MSG, ErrorMsg.PARAMS_ERROR); |
| if (mWXSDKInstance != null) { |
| new SimpleJSCallback(mWXSDKInstance.getInstanceId(), errorCallback).invoke(options); |
| } |
| } |
| |
| private WXLocationListener findLocation(String watchId, String sucCallback, String errorCallback, boolean enableHighAccuracy, boolean enableAddress) { |
| WXLogUtils.d(TAG, "into--[findLocation] mWatchId:" + watchId + "\nsuccessCallback:" + sucCallback + "\nerrorCallback:" + errorCallback + "\nenableHighAccuracy:" + enableHighAccuracy + "\nmEnableAddress:" + enableAddress); |
| |
| if (mLocationManager == null) { |
| mLocationManager = (LocationManager) mWXSDKInstance.getContext().getSystemService(Context.LOCATION_SERVICE); |
| } |
| Criteria criteria = new Criteria(); |
| if (enableHighAccuracy) { |
| criteria.setAccuracy(Criteria.ACCURACY_COARSE); |
| } |
| //String provider = locationManager.getBestProvider(criteria, false); |
| if (ActivityCompat.checkSelfPermission(mWXSDKInstance.getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mWXSDKInstance.getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { |
| WXLocationListener WXLocationListener = new WXLocationListener(mLocationManager, mWXSDKInstance, watchId, sucCallback, errorCallback, enableAddress); |
| if (mLocationManager.getAllProviders().contains(LocationManager.GPS_PROVIDER)) { |
| mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, MIN_DISTANCE, WXLocationListener); |
| } |
| if (mLocationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER)) { |
| mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE, WXLocationListener); |
| } |
| return WXLocationListener; |
| } else { |
| Map<String, Object> options = new HashMap<>(); |
| options.put(ERROR_CODE, ErrorCode.NO_PERMISSION_ERROR); |
| options.put(ERROR_MSG, ErrorMsg.NO_PERMISSION_ERROR); |
| if (mWXSDKInstance != null) { |
| new SimpleJSCallback(mWXSDKInstance.getInstanceId(), errorCallback).invoke(options); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public void watchPosition(final String successCallback, final String errorCallback, final String params) { |
| if (WXEnvironment.isApkDebugable()){ |
| WXLogUtils.d("into--[watchPosition] successCallback:" + successCallback + " errorCallback:" + errorCallback + "\nparams:" + params); |
| } |
| if (!TextUtils.isEmpty(params)) { |
| try { |
| JSONObject jsObj = new JSONObject(params); |
| boolean enableHighAccuracy = jsObj.optBoolean("enableHighAccuracy"); |
| boolean enableAddress = jsObj.optBoolean("address"); |
| |
| String id = UUID.randomUUID().toString(); |
| WXLocationListener listener = findLocation(id, successCallback, errorCallback, enableHighAccuracy, enableAddress); |
| if (listener != null) { |
| mRegisterSucCallbacks.put(id, listener); |
| } |
| return; |
| } catch (JSONException e) { |
| WXLogUtils.e(TAG, e); |
| } |
| } |
| Map<String, Object> options = new HashMap<>(); |
| options.put(ERROR_CODE, ErrorCode.PARAMS_ERROR); |
| options.put(ERROR_MSG, ErrorMsg.PARAMS_ERROR); |
| if (mWXSDKInstance != null) { |
| new SimpleJSCallback(mWXSDKInstance.getInstanceId(), errorCallback).invoke(options); |
| } |
| } |
| |
| @Override |
| public void clearWatch(String watchId) { |
| WXLogUtils.d("into--[clearWatch] mWatchId:" + watchId); |
| if (mWXSDKInstance == null || mWXSDKInstance.isDestroy() || mLocationManager == null) { |
| return; |
| } |
| if (ActivityCompat.checkSelfPermission(mWXSDKInstance.getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mWXSDKInstance.getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { |
| WXLocationListener listener = mRegisterSucCallbacks.get(watchId); |
| if (listener != null) { |
| listener.destroy(); |
| mLocationManager.removeUpdates(listener); |
| } |
| mRegisterSucCallbacks.remove(watchId); |
| } |
| } |
| |
| @Override |
| public void destroy() { |
| WXLogUtils.d("into--[destroy]"); |
| if (mWXSDKInstance == null || mWXSDKInstance.isDestroy() || mLocationManager == null) { |
| return; |
| } |
| |
| if (mWXLocationListeners != null && mWXLocationListeners.size() > 0) { |
| if (ActivityCompat.checkSelfPermission(mWXSDKInstance.getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mWXSDKInstance.getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { |
| for (WXLocationListener listener : mWXLocationListeners) { |
| if (listener != null) { |
| listener.destroy(); |
| mLocationManager.removeUpdates(listener); |
| } |
| } |
| mWXLocationListeners.clear(); |
| } |
| } |
| |
| if (mRegisterSucCallbacks != null && mRegisterSucCallbacks.size() > 0) { |
| Collection<WXLocationListener> values = mRegisterSucCallbacks.values(); |
| if (ActivityCompat.checkSelfPermission(mWXSDKInstance.getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mWXSDKInstance.getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { |
| for (WXLocationListener listener : values) { |
| listener.destroy(); |
| mLocationManager.removeUpdates(listener); |
| } |
| mRegisterSucCallbacks.clear(); |
| } |
| } |
| } |
| |
| static class WXLocationListener implements LocationListener, Handler.Callback { |
| |
| private Context mContext = null; |
| private String mWatchId; |
| private SimpleJSCallback mSucCallback = null; |
| private SimpleJSCallback mErrorCallback = null; |
| private boolean mEnableAddress; |
| private Handler mHandler; |
| private LocationManager mLocationManager; |
| |
| private WXLocationListener(LocationManager locationManager, WXSDKInstance instance, String watchId, String sucCallback, String errorCallback, boolean enableAddress) { |
| this.mWatchId = watchId; |
| if (instance != null) { |
| this.mSucCallback = new SimpleJSCallback(instance.getInstanceId(), sucCallback); |
| this.mErrorCallback = new SimpleJSCallback(instance.getInstanceId(), errorCallback); |
| mContext = instance.getContext(); |
| } |
| this.mEnableAddress = enableAddress; |
| mHandler = new Handler(this); |
| mLocationManager = locationManager; |
| mHandler.sendEmptyMessageDelayed(TIME_OUT_WHAT, GPS_TIMEOUT); |
| } |
| |
| @Override |
| public void onLocationChanged(Location location) { |
| mHandler.removeMessages(TIME_OUT_WHAT); |
| WXLogUtils.d(TAG, "into--[onLocationChanged] location:" + location == null ? "Location is NULL!" : location.toString()); |
| |
| if (location != null) { |
| Map<String, Object> result = new HashMap<>(); |
| Map<String, Object> coords = new HashMap<>(); |
| double longitude = location.getLongitude(); |
| double latitude = location.getLatitude(); |
| coords.put("longitude", longitude); |
| coords.put("latitude", latitude); |
| coords.put("altitude", location.getAltitude()); |
| coords.put("accuracy", location.getAccuracy()); |
| coords.put("heading", location.getBearing()); |
| coords.put("speed", location.getSpeed()); |
| result.put(COORDS, coords); |
| |
| // 行政区域 |
| if (mEnableAddress) { |
| Address addr = getAddress(latitude, longitude); |
| Map<String, Object> address = new HashMap<>(); |
| if (addr != null) { |
| address.put("country", addr.getCountryName()); |
| address.put("province", addr.getAdminArea()); |
| address.put("city", addr.getLocality()); |
| address.put("cityCode", addr.getPostalCode()); |
| address.put("area", addr.getSubLocality()); |
| address.put("road", addr.getThoroughfare()); |
| // 其中getAddressLine(0)表示国家,getAddressLine(1)表示精确到某个区,getAddressLine(2)表示精确到具体的街 |
| StringBuilder sb = new StringBuilder(); |
| for (int i = 1; i <= 2; i++) { |
| if (!TextUtils.isEmpty(addr.getAddressLine(i))) { //防止null导致的拼接错误 |
| sb.append(addr.getAddressLine(i)); |
| } |
| } |
| address.put("addressLine", sb.toString()); |
| } |
| result.put(ADDRESS, address); |
| } |
| result.put(ERROR_CODE, ErrorCode.SUCCESS); |
| result.put(ERROR_MSG, ErrorMsg.SUCCESS); |
| if (!TextUtils.isEmpty(mWatchId)) { |
| result.put(WATCH_ID, mWatchId); |
| } |
| |
| if (mSucCallback != null) { |
| boolean isKeepAlive = TextUtils.isEmpty(mWatchId) ? false : true; |
| if (isKeepAlive) { |
| mSucCallback.invokeAndKeepAlive(result); |
| } else { |
| mSucCallback.invoke(result); |
| } |
| } |
| } else { |
| Map<String, Object> options = new HashMap<>(); |
| options.put(ERROR_CODE, ErrorCode.LOCATION_ERROR); |
| options.put(ERROR_MSG, ErrorMsg.LOCATION_ERROR); |
| if (!TextUtils.isEmpty(mWatchId)) { |
| options.put(WATCH_ID, mWatchId); |
| } |
| if (mErrorCallback != null) { |
| boolean isKeepAlive = TextUtils.isEmpty(mWatchId) ? false : true; |
| if (isKeepAlive) { |
| mErrorCallback.invokeAndKeepAlive(options); |
| } else { |
| mErrorCallback.invoke(options); |
| } |
| } |
| } |
| if (TextUtils.isEmpty(mWatchId) && mContext != null) { |
| if (mLocationManager != null && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { |
| destroy(); |
| mLocationManager.removeUpdates(this); |
| } |
| } |
| } |
| |
| @Override |
| public void onStatusChanged(String provider, int status, Bundle extras) { |
| WXLogUtils.i(TAG, "into--[onStatusChanged] provider:" + provider + " status:" + status); |
| } |
| |
| @Override |
| public void onProviderEnabled(String provider) { |
| WXLogUtils.i(TAG, "into--[onProviderEnabled] provider:" + provider); |
| } |
| |
| @Override |
| public void onProviderDisabled(String provider) { |
| WXLogUtils.i(TAG, "into--[onProviderDisabled] provider:" + provider); |
| } |
| |
| @Override |
| public boolean handleMessage(Message msg) { |
| if (msg.what == TIME_OUT_WHAT) { |
| WXLogUtils.d(TAG, "into--[handleMessage] Location Time Out!"); |
| if (mContext == null || mLocationManager == null) { |
| return false; |
| } |
| if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { |
| mLocationManager.removeUpdates(this); |
| } |
| Map<String, Object> options = new HashMap<>(); |
| options.put(ERROR_CODE, ErrorCode.LOCATION_TIME_OUT); |
| options.put(ERROR_MSG, ErrorMsg.LOCATION_TIME_OUT); |
| if (!TextUtils.isEmpty(mWatchId)) { |
| options.put(WATCH_ID, mWatchId); |
| } |
| if (mErrorCallback != null) { |
| mErrorCallback.invoke(options); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * get address info |
| */ |
| private Address getAddress(double latitude, double longitude) { |
| WXLogUtils.d(TAG, "into--[getAddress] latitude:" + latitude + " longitude:" + longitude); |
| try { |
| if (mContext == null) { |
| return null; |
| } |
| Geocoder gc = new Geocoder(mContext); |
| List<Address> list = gc.getFromLocation(latitude, longitude, 1); |
| if (list != null && list.size() > 0) { |
| return list.get(0); |
| } |
| } catch (Exception e) { |
| WXLogUtils.e(TAG, e); |
| } |
| return null; |
| } |
| |
| public void destroy() { |
| if (mHandler != null) { |
| mHandler.removeMessages(TIME_OUT_WHAT); |
| mContext = null; |
| } |
| } |
| } |
| } |