Merge pull request #7031 from osmandapp/turn_screen_on_plugin

Turn screen on Plugin
This commit is contained in:
Alexey 2019-07-06 16:01:35 +03:00 committed by GitHub
commit e9ae109ef8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 587 additions and 149 deletions

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:id="@android:id/title"
style="?android:attr/listSeparatorTextViewStyle"/>
<TextView android:id="@android:id/summary"
android:paddingLeft="@dimen/content_padding_half" android:paddingRight="@dimen/content_padding_half"
android:textColor="?android:textColorPrimary"
android:layout_width="match_parent" android:layout_height="wrap_content"/>
</LinearLayout>

View file

@ -11,6 +11,12 @@
Thx - Hardy
-->
<string name="turn_screen_on_router">Wake on turn</string>
<string name="turn_screen_on_time_descr">Set the time for which the screen will turn on.</string>
<string name="turn_screen_on_sensor">Use proximity sensor</string>
<string name="turn_screen_on_sensor_descr">Wave your hand over the top of the screen to turn on the screen while navigating.</string>
<string name="app_profile_custom_nav_subtitle"></string>
<string name="rate_dialog_descr">Please give us 30 seconds, share feedback and rate our work on Google Play.</string>
<string name="app_mode_offroad">Offroad</string>
<string name="edit_profile_setup_title">Setup Profile</string>
<string name="edit_profile_setup_subtitle">Profile keeps its own settings</string>

View file

@ -72,6 +72,23 @@
-->
</PreferenceCategory>
<PreferenceCategory
android:key="turn_screen_on"
android:layout="@layout/preference_category_summary"
android:summary="@string/wake_on_voice_descr"
android:title="@string/wake_on_voice">
<ListPreference
android:key="turn_screen_on_time_int"
android:summary="@string/turn_screen_on_time_descr"
android:title="@string/shared_string_time"/>
<CheckBoxPreference
android:key="turn_screen_on_sensor"
android:summary="@string/turn_screen_on_sensor_descr"
android:title="@string/turn_screen_on_sensor"/>
</PreferenceCategory>
<PreferenceCategory
android:key="voice"
android:title="@string/voice_pref_title">

View file

@ -3,6 +3,7 @@ package net.osmand;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@ -20,6 +21,7 @@ import android.graphics.drawable.StateListDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.AttrRes;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
@ -56,6 +58,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static android.content.Context.POWER_SERVICE;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static android.util.TypedValue.COMPLEX_UNIT_SP;
@ -537,4 +540,15 @@ public class AndroidUtils {
}
return result;
}
public static boolean isScreenOn(Context context) {
PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH && powerManager.isInteractive()
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT_WATCH && powerManager.isScreenOn();
}
public static boolean isScreenLocked(Context context) {
KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
return keyguardManager.inKeyguardRestrictedInputMode();
}
}

View file

@ -45,4 +45,9 @@ interface IOsmAndAidlCallback {
* @param layerId - id of layer point and button associated with
*/
void onContextMenuButtonClicked(in int buttonId, String pointId, String layerId);
/**
* Callback for {@link IOsmAndAidlInterface} registerForVoiceRouterMessages() method.
*/
void onVoiceRouterNotify();
}

View file

@ -84,6 +84,7 @@ import net.osmand.aidl.plugins.PluginParams;
import net.osmand.aidl.copyfile.CopyFileParams;
import net.osmand.aidl.navigation.ANavigationUpdateParams;
import net.osmand.aidl.navigation.ANavigationVoiceRouterMessageParams;
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.UpdateContextMenuButtonsParams;
@ -806,4 +807,13 @@ interface IOsmAndAidlInterface {
*
*/
boolean setCustomization(in CustomizationInfoParams params);
/**
* Method to register for Voice Router voice messages during navigation. Notifies user about voice messages.
*
* @params subscribeToUpdates (boolean) - boolean flag to subscribe or unsubscribe from messages
* @params callbackId (long) - id of callback, needed to unsubscribe from messages
* @params callback (IOsmAndAidlCallback) - callback to notify user on voice message
*/
long registerForVoiceRouterMessages(in ANavigationVoiceRouterMessageParams params, IOsmAndAidlCallback callback);
}

View file

@ -73,6 +73,7 @@ import net.osmand.plus.audionotes.AudioVideoNotesPlugin;
import net.osmand.plus.dialogs.ConfigureMapMenu;
import net.osmand.plus.helpers.ColorDialogs;
import net.osmand.plus.helpers.ExternalApiHelper;
import net.osmand.plus.helpers.LockHelper;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.other.IContextMenuButtonListener;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
@ -81,6 +82,7 @@ import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.routing.IRoutingDataUpdateListener;
import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.routing.VoiceRouter;
import net.osmand.plus.views.AidlMapLayer;
import net.osmand.plus.views.MapInfoLayer;
import net.osmand.plus.views.OsmandMapLayer;
@ -123,6 +125,7 @@ import static net.osmand.aidl.OsmandAidlConstants.COPY_FILE_WRITE_LOCK_ERROR;
import static net.osmand.aidl.OsmandAidlConstants.OK_RESPONSE;
import static net.osmand.aidl.OsmandAidlService.KEY_ON_CONTEXT_MENU_BUTTONS_CLICK;
import static net.osmand.aidl.OsmandAidlService.KEY_ON_NAV_DATA_UPDATE;
import static net.osmand.aidl.OsmandAidlService.KEY_ON_VOICE_MESSAGE;
public class OsmandAidlApi {
@ -198,6 +201,7 @@ public class OsmandAidlApi {
private Map<String, BroadcastReceiver> receivers = new TreeMap<>();
private Map<String, ConnectedApp> connectedApps = new ConcurrentHashMap<>();
private Map<String, ContextMenuButtonsParams> contextMenuButtonsParams = new ConcurrentHashMap<>();
private Map<Long, VoiceRouter.VoiceMessageListener> voiceRouterMessageCallbacks= new ConcurrentHashMap<>();
private AMapPointUpdateListener aMapPointUpdateListener;
@ -1881,7 +1885,7 @@ public class OsmandAidlApi {
try {
cb.getCallback().updateNavigationInfo(directionInfo);
} catch (Exception e) {
LOG.debug(e.getMessage(), e);
LOG.error(e.getMessage(), e);
}
}
}
@ -1897,6 +1901,31 @@ public class OsmandAidlApi {
navUpdateCallbacks.remove(id);
}
public void registerForVoiceRouterMessages(long id) {
VoiceRouter.VoiceMessageListener listener = new VoiceRouter.VoiceMessageListener() {
@Override
public void onVoiceMessage() {
if (aidlCallbackListener != null) {
for (OsmandAidlService.AidlCallbackParams cb : aidlCallbackListener.getAidlCallbacks().values()) {
if (!aidlCallbackListener.getAidlCallbacks().isEmpty() && (cb.getKey() & KEY_ON_VOICE_MESSAGE) > 0) {
try {
cb.getCallback().onVoiceRouterNotify();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
}
}
}
};
voiceRouterMessageCallbacks.put(id, listener);
app.getRoutingHelper().getVoiceRouter().addVoiceMessageListener(listener);
}
public void unregisterFromVoiceRouterMessages(long id) {
app.getRoutingHelper().getVoiceRouter().removeVoiceMessageListener(voiceRouterMessageCallbacks.get(id));
voiceRouterMessageCallbacks.remove(id);
}
public Map<String, ContextMenuButtonsParams> getContextMenuButtonsParams() {
return contextMenuButtonsParams;
@ -1964,7 +1993,7 @@ public class OsmandAidlApi {
try {
cb.getCallback().onContextMenuButtonClicked(buttonId, pointId, layerId);
} catch (Exception e) {
LOG.debug(e.getMessage(), e);
LOG.error(e.getMessage(), e);
}
}
}

View file

@ -57,6 +57,7 @@ import net.osmand.aidl.navdrawer.NavDrawerFooterParams;
import net.osmand.aidl.navdrawer.NavDrawerHeaderParams;
import net.osmand.aidl.navdrawer.SetNavDrawerItemsParams;
import net.osmand.aidl.navigation.ANavigationUpdateParams;
import net.osmand.aidl.navigation.ANavigationVoiceRouterMessageParams;
import net.osmand.aidl.navigation.MuteNavigationParams;
import net.osmand.aidl.navigation.NavigateGpxParams;
import net.osmand.aidl.navigation.NavigateParams;
@ -74,6 +75,7 @@ import net.osmand.aidl.search.SearchParams;
import net.osmand.aidl.search.SearchResult;
import net.osmand.aidl.tiles.ASqliteDbFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.routing.VoiceRouter;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -98,6 +100,7 @@ public class OsmandAidlService extends Service implements AidlCallbackListener {
public static final int KEY_ON_UPDATE = 1;
public static final int KEY_ON_NAV_DATA_UPDATE = 2;
public static final int KEY_ON_CONTEXT_MENU_BUTTONS_CLICK = 4;
public static final int KEY_ON_VOICE_MESSAGE = 5;
private Map<Long, AidlCallbackParams> callbacks = new ConcurrentHashMap<>();
private Handler mHandler = null;
@ -1137,6 +1140,29 @@ public class OsmandAidlService extends Service implements AidlCallbackListener {
return false;
}
}
@Override
public long registerForVoiceRouterMessages(ANavigationVoiceRouterMessageParams params, final IOsmAndAidlCallback callback) throws RemoteException {
try {
OsmandAidlApi api = getApi("registerForVoiceRouterMessages");
if (api != null ) {
if (!params.isSubscribeToUpdates() && params.getCallbackId() != -1) {
api.unregisterFromVoiceRouterMessages(params.getCallbackId());
removeAidlCallback(params.getCallbackId());
return -1;
} else {
long id = addAidlCallback(callback, KEY_ON_VOICE_MESSAGE);
api.registerForVoiceRouterMessages(id);
return id;
}
} else {
return -1;
}
} catch (Exception e) {
handleException(e);
return UNKNOWN_API_ERROR;
}
}
};
public static class AidlCallbackParams {

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.navigation;
parcelable ANavigationVoiceRouterMessageParams;

View file

@ -0,0 +1,56 @@
package net.osmand.aidl.navigation;
import android.os.Parcel;
import android.os.Parcelable;
public class ANavigationVoiceRouterMessageParams implements Parcelable{
private boolean subscribeToUpdates = true;
private long callbackId = -1L;
public ANavigationVoiceRouterMessageParams() {
}
public long getCallbackId() {
return callbackId;
}
public void setCallbackId(long callbackId) {
this.callbackId = callbackId;
}
public void setSubscribeToUpdates(boolean subscribeToUpdates) {
this.subscribeToUpdates = subscribeToUpdates;
}
public boolean isSubscribeToUpdates() {
return subscribeToUpdates;
}
protected ANavigationVoiceRouterMessageParams(Parcel in) {
callbackId = in.readLong();
subscribeToUpdates = in.readByte() != 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(callbackId);
dest.writeByte((byte) (subscribeToUpdates ? 1 : 0));
}
@Override
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<ANavigationVoiceRouterMessageParams> CREATOR = new Parcelable.Creator<ANavigationVoiceRouterMessageParams>() {
@Override
public ANavigationVoiceRouterMessageParams createFromParcel(Parcel in) {
return new ANavigationVoiceRouterMessageParams(in);
}
@Override
public ANavigationVoiceRouterMessageParams[] newArray(int size) {
return new ANavigationVoiceRouterMessageParams[size];
}
};
}

View file

@ -32,6 +32,7 @@ import net.osmand.plus.base.MapViewTrackingUtilities;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
import net.osmand.plus.helpers.AvoidSpecificRoads;
import net.osmand.plus.helpers.LockHelper;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.liveupdates.LiveUpdatesHelper;
@ -497,6 +498,7 @@ public class AppInitializer implements IProgress {
app.travelDbHelper.initTravelBooks();
}
app.travelDbHelper = startupInit(app.travelDbHelper, TravelDbHelper.class);
app.lockHelper = startupInit(new LockHelper(app), LockHelper.class);
initOpeningHoursParser();

View file

@ -53,6 +53,7 @@ import net.osmand.plus.download.DownloadIndexesThread;
import net.osmand.plus.download.DownloadService;
import net.osmand.plus.download.IndexItem;
import net.osmand.plus.helpers.AvoidSpecificRoads;
import net.osmand.plus.helpers.LockHelper;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.mapcontextmenu.other.RoutePreferencesMenu;
@ -134,6 +135,7 @@ public class OsmandApplication extends MultiDexApplication {
TravelDbHelper travelDbHelper;
InAppPurchaseHelper inAppPurchaseHelper;
MapViewTrackingUtilities mapViewTrackingUtilities;
LockHelper lockHelper;
private RoutingConfiguration.Builder routingConfig;
private Locale preferredLocale = null;
@ -328,7 +330,11 @@ public class OsmandApplication extends MultiDexApplication {
public DayNightHelper getDaynightHelper() {
return daynightHelper;
}
public LockHelper getLockHelper() {
return lockHelper;
}
public synchronized DownloadIndexesThread getDownloadThread() {
if(downloadIndexesThread == null) {
downloadIndexesThread = new DownloadIndexesThread(this);

View file

@ -1391,11 +1391,26 @@ public class OsmandSettings {
public final CommonPreference<Integer> KEEP_INFORMING = new IntPreference("keep_informing", 0).makeProfile();
{
// 0 means never
KEEP_INFORMING.setModeDefaultValue(ApplicationMode.CAR, 0);
KEEP_INFORMING.setModeDefaultValue(ApplicationMode.BICYCLE, 0);
KEEP_INFORMING.setModeDefaultValue(ApplicationMode.PEDESTRIAN, 0);
}
public final CommonPreference<Integer> TURN_SCREEN_ON_TIME_INT = new IntPreference("turn_screen_on_time_int", 0).makeProfile();
{
TURN_SCREEN_ON_TIME_INT.setModeDefaultValue(ApplicationMode.CAR, 0);
TURN_SCREEN_ON_TIME_INT.setModeDefaultValue(ApplicationMode.BICYCLE, 0);
TURN_SCREEN_ON_TIME_INT.setModeDefaultValue(ApplicationMode.PEDESTRIAN, 0);
}
public final CommonPreference<Boolean> TURN_SCREEN_ON_SENSOR = new BooleanPreference("turn_screen_on_sensor", false).makeProfile();
{
TURN_SCREEN_ON_SENSOR.setModeDefaultValue(ApplicationMode.CAR, false);
TURN_SCREEN_ON_SENSOR.setModeDefaultValue(ApplicationMode.BICYCLE, false);
TURN_SCREEN_ON_SENSOR.setModeDefaultValue(ApplicationMode.PEDESTRIAN, false);
}
// this value string is synchronized with settings_pref.xml preference name
// try without AUTO_FOLLOW_ROUTE_NAV (see forum discussion 'Simplify our navigation preference menu')

View file

@ -36,6 +36,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewStub;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@ -86,7 +87,6 @@ import net.osmand.plus.dashboard.DashboardOnMap.DashboardType;
import net.osmand.plus.dialogs.CrashBottomSheetDialogFragment;
import net.osmand.plus.dialogs.RateUsBottomSheetDialogFragment;
import net.osmand.plus.dialogs.SendAnalyticsBottomSheetDialogFragment;
import net.osmand.plus.dialogs.RateUsBottomSheetDialog;
import net.osmand.plus.dialogs.WhatsNewDialogFragment;
import net.osmand.plus.dialogs.XMasDialogFragment;
import net.osmand.plus.download.DownloadActivity;
@ -99,6 +99,7 @@ import net.osmand.plus.helpers.DiscountHelper;
import net.osmand.plus.helpers.ExternalApiHelper;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.helpers.ImportHelper.ImportGpxBottomSheetDialogFragment;
import net.osmand.plus.helpers.LockHelper;
import net.osmand.plus.mapcontextmenu.AdditionalActionsBottomSheetDialogFragment;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.MenuController.MenuState;
@ -157,7 +158,7 @@ import java.util.regex.Pattern;
public class MapActivity extends OsmandActionBarActivity implements DownloadEvents,
OnRequestPermissionsResultCallback, IRouteInformationListener, AMapPointUpdateListener,
MapMarkerChangedListener, OnDismissDialogFragmentListener, OnDrawMapListener, OsmAndAppCustomizationListener {
MapMarkerChangedListener, OnDismissDialogFragmentListener, OnDrawMapListener, OsmAndAppCustomizationListener, LockHelper.LockUIAdapter {
public static final String INTENT_KEY_PARENT_MAP_ACTIVITY = "intent_parent_map_activity_key";
public static final String INTENT_PARAMS = "intent_prarams";
@ -221,6 +222,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
private boolean stopped = true;
private ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
private LockHelper lockHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -228,6 +231,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
long tm = System.currentTimeMillis();
app = getMyApplication();
settings = app.getSettings();
lockHelper = app.getLockHelper();
app.applyTheme(this);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
@ -338,6 +342,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
registerReceiver(screenOffReceiver, filter);
app.getAidlApi().onCreateMapActivity(this);
lockHelper.setLockUIAdapter(this);
mIsDestroyed = false;
}
@ -1288,6 +1294,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
protected void onStart() {
super.onStart();
stopped = false;
lockHelper.onStart(this);
getMyApplication().getNotificationHelper().showNotifications();
}
@ -1306,6 +1313,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
onPauseActivity();
}
stopped = true;
lockHelper.onStop(this);
super.onStop();
}
@ -1325,6 +1333,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
if (atlasMapRendererView != null) {
atlasMapRendererView.handleOnDestroy();
}
lockHelper.setLockUIAdapter(null);
mIsDestroyed = true;
}
@ -1876,6 +1886,30 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
return oldPoint.getLayerId().equals(layerId) && oldPoint.getId().equals(point.getId());
}
public void changeKeyguardFlags(final boolean enable) {
app.runInUIThread(new Runnable() {
@Override
public void run() {
if (enable) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
}
}
});
}
@Override
public void lock() {
changeKeyguardFlags(false);
}
@Override
public void unlock() {
changeKeyguardFlags(true);
}
private class ScreenOffReceiver extends BroadcastReceiver {
@Override

View file

@ -204,9 +204,23 @@ public class SettingsNavigationActivity extends SettingsBaseActivity {
addTurnScreenOn((PreferenceGroup) screen.findPreference("turn_screen_on"));
addVoicePrefs((PreferenceGroup) screen.findPreference("voice"));
}
private void addTurnScreenOn(PreferenceGroup screen) {
Integer[] screenPowerSaveValues = new Integer[] { 0, 5, 10, 15, 20, 30, 45, 60 };
String[] screenPowerSaveNames = new String[screenPowerSaveValues.length];
screenPowerSaveNames[0] = getString(R.string.shared_string_never);
for (int i = 1; i < screenPowerSaveValues.length; i++) {
screenPowerSaveNames[i] = screenPowerSaveValues[i] + " "
+ getString(R.string.int_seconds);
}
registerListPreference(settings.TURN_SCREEN_ON_TIME_INT, screen, screenPowerSaveNames, screenPowerSaveValues);
registerBooleanPreference(settings.TURN_SCREEN_ON_SENSOR, screen);
}
private void reloadVoiceListPreference(PreferenceScreen screen) {
String[] entries;
String[] entrieValues;
@ -415,6 +429,10 @@ public class SettingsNavigationActivity extends SettingsBaseActivity {
return true;
}
super.onPreferenceChange(preference, newValue);
if (id.equals(settings.TURN_SCREEN_ON_TIME_INT.getId())) {
boolean isRoutingListenerEnabled = Integer.valueOf(newValue.toString()) > 0;
getMyApplication().getLockHelper().setVoiceRouterListener(isRoutingListenerEnabled);
}
return true;
}

View file

@ -203,7 +203,8 @@ public class MapViewTrackingUtilities implements OsmAndLocationListener, IMapLoc
showViewAngle = routePlanningMode; // disable compass rotation in that mode
}
registerUnregisterSensor(location, smallSpeedForDirectionOfMovement);
if (settings.ANIMATE_MY_LOCATION.get() && !smallSpeedForAnimation && !movingToMyLocation) {
if (settings.ANIMATE_MY_LOCATION.get() && !smallSpeedForAnimation && !movingToMyLocation &&
settings.TURN_SCREEN_ON_TIME_INT.get() == 0) {
mapView.getAnimatedDraggingThread().startMoving(
location.getLatitude(), location.getLongitude(), zoom, rotation, false);
} else {

View file

@ -0,0 +1,163 @@
package net.osmand.plus.helpers;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.PowerManager;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.routing.VoiceRouter;
public class LockHelper implements SensorEventListener {
private static final org.apache.commons.logging.Log LOG = PlatformUtil.getLog(LockHelper.class);
private static final int SENSOR_SENSITIVITY = 4;
private final SensorManager mSensorManager;
private final Sensor mProximity;
private PowerManager.WakeLock wakeLock = null;
private Handler uiHandler;
private OsmandApplication app;
private LockRunnable lockRunnable;
private LockUIAdapter lockUIAdapter;
private OsmandSettings settings;
private VoiceRouter.VoiceMessageListener voiceMessageListener;
public interface LockUIAdapter {
void lock();
void unlock();
}
private class LockRunnable implements Runnable {
@Override
public void run() {
lock();
}
}
public LockHelper(final OsmandApplication app) {
this.app = app;
uiHandler = new Handler();
lockRunnable = new LockRunnable();
settings = app.getSettings();
mSensorManager = (SensorManager) app.getSystemService(Context.SENSOR_SERVICE);
mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
voiceMessageListener = new VoiceRouter.VoiceMessageListener() {
@Override
public void onVoiceMessage() {
unlockEvent();
}
};
}
private void releaseWakeLocks() {
if (wakeLock != null) {
if (wakeLock.isHeld()) {
wakeLock.release();
}
wakeLock = null;
}
}
private void unlock(long timeInMills) {
releaseWakeLocks();
if (lockUIAdapter != null) {
lockUIAdapter.unlock();
}
PowerManager pm = (PowerManager) app.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP, "tso:wakelocktag");
wakeLock.acquire(timeInMills);
}
private void lock() {
releaseWakeLocks();
if (lockUIAdapter != null) {
lockUIAdapter.lock();
}
}
private void timedUnlock(long millis) {
uiHandler.removeCallbacks(lockRunnable);
unlock(millis);
uiHandler.postDelayed(lockRunnable, millis);
}
public void unlockEvent() {
int unlockTime = app.getSettings().TURN_SCREEN_ON_TIME_INT.get();
if (unlockTime > 0) {
timedUnlock(unlockTime * 1000L);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
if (event.values[0] >= -SENSOR_SENSITIVITY && event.values[0] <= SENSOR_SENSITIVITY) {
unlockEvent();
}
}
}
public void setSensor(boolean enable) {
if (enable) {
mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
} else {
mSensorManager.unregisterListener(this);
}
}
public void setVoiceRouterListener(boolean enable) {
VoiceRouter vr = app.getRoutingHelper().getVoiceRouter();
if (enable) {
vr.addVoiceMessageListener(voiceMessageListener);
} else {
vr.removeVoiceMessageListener(voiceMessageListener);
}
}
public void refreshSettings() {
boolean isVRListenerEnabled = settings.TURN_SCREEN_ON_TIME_INT.get() > 0;
setVoiceRouterListener(isVRListenerEnabled);
boolean isSensorEnabled = settings.TURN_SCREEN_ON_SENSOR.get()
&& app.getRoutingHelper().isFollowingMode();
setSensor(isSensorEnabled);
}
public void onStart(Activity a) {
if (wakeLock == null) {
setSensor(false);
setVoiceRouterListener(false);
}
}
public void onStop(Activity a) {
if(!a.isFinishing()) {
refreshSettings();
}
}
public void setLockUIAdapter(LockUIAdapter adapter) {
lockUIAdapter = adapter;
}
}

View file

@ -2,6 +2,7 @@ package net.osmand.plus.routing;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -21,10 +22,8 @@ import net.osmand.plus.voice.CommandBuilder;
import net.osmand.plus.voice.CommandPlayer;
import net.osmand.router.RouteSegmentResult;
import net.osmand.router.TurnType;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import android.media.AudioManager;
import android.media.SoundPool;
@ -81,13 +80,13 @@ public class VoiceRouter {
void onVoiceMessage();
}
private ConcurrentHashMap<VoiceMessageListener, Integer> voiceMessageListeners;
private ConcurrentHashMap<WeakReference<VoiceMessageListener>, Integer> voiceMessageListeners;
VoiceRouter(RoutingHelper router, final OsmandSettings settings) {
this.router = router;
this.settings = settings;
mute = settings.VOICE_MUTE.get();
voiceMessageListeners = new ConcurrentHashMap<VoiceRouter.VoiceMessageListener, Integer>();
voiceMessageListeners = new ConcurrentHashMap<>();
}
public void setPlayer(CommandPlayer player) {
@ -226,10 +225,10 @@ public class VoiceRouter {
if (waitAnnouncedOffRoute == 0 || ms - lastAnnouncedOffRoute > waitAnnouncedOffRoute) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
notifyOnVoiceMessage();
p.offRoute(dist).play();
p.offRoute(dist);
announceBackOnRoute = true;
}
play(p);
if (waitAnnouncedOffRoute == 0) {
waitAnnouncedOffRoute = 60000;
} else {
@ -243,79 +242,72 @@ public class VoiceRouter {
CommandBuilder p = getNewCommandPlayerToPlay();
if (announceBackOnRoute) {
if (p != null) {
notifyOnVoiceMessage();
p.backOnRoute().play();
p.backOnRoute();
}
play(p);
announceBackOnRoute = false;
}
}
public void approachWaypoint(Location location, List<LocationPointWrapper> points) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p == null) {
return;
if (p != null) {
double[] dist = new double[1];
makeSound();
String text = getText(location, points, dist);
p.goAhead(dist[0], new StreetName()).andArriveAtWayPoint(text);
}
notifyOnVoiceMessage();
double[] dist = new double[1];
makeSound();
String text = getText(location, points, dist);
p.goAhead(dist[0], new StreetName()).andArriveAtWayPoint(text).play();
play(p);
}
public void approachFavorite(Location location, List<LocationPointWrapper> points) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p == null) {
return;
if (p != null) {
double[] dist = new double[1];
makeSound();
String text = getText(location, points, dist);
p.goAhead(dist[0], new StreetName()).andArriveAtFavorite(text);
}
notifyOnVoiceMessage();
double[] dist = new double[1];
makeSound();
String text = getText(location, points, dist);
p.goAhead(dist[0], new StreetName()).andArriveAtFavorite(text).play();
play(p);
}
public void approachPoi(Location location, List<LocationPointWrapper> points) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p == null) {
return;
if (p != null) {
double[] dist = new double[1];
String text = getText(location, points, dist);
p.goAhead(dist[0], new StreetName()).andArriveAtPoi(text);
}
notifyOnVoiceMessage();
double[] dist = new double[1];
String text = getText(location, points, dist);
p.goAhead(dist[0], new StreetName()).andArriveAtPoi(text).play();
play(p);
}
public void announceWaypoint(List<LocationPointWrapper> points) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p == null) {
return;
if (p != null) {
makeSound();
String text = getText(null, points, null);
p.arrivedAtWayPoint(text);
}
notifyOnVoiceMessage();
makeSound();
String text = getText(null, points,null);
p.arrivedAtWayPoint(text).play();
play(p);
}
public void announceFavorite(List<LocationPointWrapper> points) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p == null) {
return;
if (p != null) {
makeSound();
String text = getText(null, points, null);
p.arrivedAtFavorite(text);
}
notifyOnVoiceMessage();
makeSound();
String text = getText(null, points,null);
p.arrivedAtFavorite(text).play();
play(p);
}
public void announcePoi(List<LocationPointWrapper> points) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p == null) {
return;
if (p != null) {
String text = getText(null, points, null);
p.arrivedAtPoi(text);
}
notifyOnVoiceMessage();
String text = getText(null, points,null);
p.arrivedAtPoi(text).play();
play(p);
}
protected String getText(Location location, List<LocationPointWrapper> points, double[] dist) {
@ -344,33 +336,33 @@ public class VoiceRouter {
if (router.getSettings().SPEAK_SPEED_CAMERA.get()) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
notifyOnVoiceMessage();
p.attention(type+"").play();
p.attention(type+"");
}
play(p);
}
} else if (type == AlarmInfoType.PEDESTRIAN) {
if (router.getSettings().SPEAK_PEDESTRIAN.get()) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
notifyOnVoiceMessage();
p.attention(type+"").play();
p.attention(type+"");
}
play(p);
}
} else if (type == AlarmInfoType.TUNNEL) {
if (router.getSettings().SPEAK_TUNNELS.get()) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
notifyOnVoiceMessage();
p.attention(type+"").play();
p.attention(type+"");
}
play(p);
}
} else {
if (router.getSettings().SPEAK_TRAFFIC_WARNINGS.get()) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
notifyOnVoiceMessage();
p.attention(type+"").play();
p.attention(type+"");
}
play(p);
// See Issue 2377: Announce destination again - after some motorway tolls roads split shortly after the toll
if (type == AlarmInfoType.TOLL_BOOTH) {
suppressDest = false;
@ -393,11 +385,11 @@ public class VoiceRouter {
} else if (router.getSettings().SPEAK_SPEED_LIMIT.get() && ms - waitAnnouncedSpeedLimit > 10 * 1000 ) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
notifyOnVoiceMessage();
lastAnnouncedSpeedLimit = ms;
waitAnnouncedSpeedLimit = 0;
p.speedAlarm(maxSpeed, speed).play();
p.speedAlarm(maxSpeed, speed);
}
play(p);
}
}
}
@ -555,29 +547,30 @@ public class VoiceRouter {
}
private boolean playMakeUTwp() {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
play.makeUTwp().play();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
p.makeUTwp();
play(p);
return true;
}
play(p);
return false;
}
void playThen() {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
play.then().play();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
p.then();
}
play(p);
}
private void playGoAhead(int dist, StreetName streetName) {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
play.goAhead(dist, streetName).play();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
p.goAhead(dist, streetName);
}
play(p);
}
private StreetName getSpeakableStreetName(RouteSegmentResult currentSegment, RouteDirectionInfo i, boolean includeDest) {
@ -658,36 +651,34 @@ public class VoiceRouter {
}
private void playPrepareTurn(RouteSegmentResult currentSegment, RouteDirectionInfo next, int dist) {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
String tParam = getTurnType(next.getTurnType());
if (tParam != null) {
notifyOnVoiceMessage();
play.prepareTurn(tParam, dist, getSpeakableStreetName(currentSegment, next, true)).play();
p.prepareTurn(tParam, dist, getSpeakableStreetName(currentSegment, next, true));
} else if (next.getTurnType().isRoundAbout()) {
notifyOnVoiceMessage();
play.prepareRoundAbout(dist, next.getTurnType().getExitOut(), getSpeakableStreetName(currentSegment, next, true)).play();
p.prepareRoundAbout(dist, next.getTurnType().getExitOut(), getSpeakableStreetName(currentSegment, next, true));
} else if (next.getTurnType().getValue() == TurnType.TU || next.getTurnType().getValue() == TurnType.TRU) {
notifyOnVoiceMessage();
play.prepareMakeUT(dist, getSpeakableStreetName(currentSegment, next, true)).play();
}
p.prepareMakeUT(dist, getSpeakableStreetName(currentSegment, next, true));
}
}
play(p);
}
private void playMakeTurnIn(RouteSegmentResult currentSegment, RouteDirectionInfo next, int dist, RouteDirectionInfo pronounceNextNext) {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
String tParam = getTurnType(next.getTurnType());
boolean isPlay = true;
if (tParam != null) {
play.turn(tParam, dist, getSpeakableStreetName(currentSegment, next, true));
p.turn(tParam, dist, getSpeakableStreetName(currentSegment, next, true));
suppressDest = true;
} else if (next.getTurnType().isRoundAbout()) {
play.roundAbout(dist, next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut(), getSpeakableStreetName(currentSegment, next, true));
p.roundAbout(dist, next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut(), getSpeakableStreetName(currentSegment, next, true));
// Other than in prepareTurn, in prepareRoundabout we do not announce destination, so we can repeat it one more time
suppressDest = false;
} else if (next.getTurnType().getValue() == TurnType.TU || next.getTurnType().getValue() == TurnType.TRU) {
play.makeUT(dist, getSpeakableStreetName(currentSegment, next, true));
p.makeUT(dist, getSpeakableStreetName(currentSegment, next, true));
suppressDest = true;
} else {
isPlay = false;
@ -697,19 +688,18 @@ public class VoiceRouter {
TurnType t = pronounceNextNext.getTurnType();
isPlay = true;
if (t.getValue() != TurnType.C && next.getTurnType().getValue() == TurnType.C) {
play.goAhead(dist, getSpeakableStreetName(currentSegment, next, true));
p.goAhead(dist, getSpeakableStreetName(currentSegment, next, true));
}
if (t.getValue() == TurnType.TL || t.getValue() == TurnType.TSHL || t.getValue() == TurnType.TSLL
|| t.getValue() == TurnType.TU || t.getValue() == TurnType.KL ) {
play.then().bearLeft( getSpeakableStreetName(currentSegment, next, false));
p.then().bearLeft( getSpeakableStreetName(currentSegment, next, false));
} else if (t.getValue() == TurnType.TR || t.getValue() == TurnType.TSHR || t.getValue() == TurnType.TSLR
|| t.getValue() == TurnType.TRU || t.getValue() == TurnType.KR) {
play.then().bearRight( getSpeakableStreetName(currentSegment, next, false));
p.then().bearRight( getSpeakableStreetName(currentSegment, next, false));
}
}
if (isPlay) {
notifyOnVoiceMessage();
play.play();
play(p);
}
}
}
@ -731,32 +721,32 @@ public class VoiceRouter {
private void playAndArriveAtDestination(NextDirectionInfo info) {
if (isTargetPoint(info)) {
String pointName = (info == null || info.pointName == null) ? "" : info.pointName;
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
if (info != null && info.intermediatePoint) {
play.andArriveAtIntermediatePoint(getSpeakablePointName(pointName)).play();
p.andArriveAtIntermediatePoint(getSpeakablePointName(pointName));
} else {
play.andArriveAtDestination(getSpeakablePointName(pointName)).play();
p.andArriveAtDestination(getSpeakablePointName(pointName));
}
}
play(p);
}
}
private void playMakeTurn(RouteSegmentResult currentSegment, RouteDirectionInfo next, NextDirectionInfo nextNextInfo) {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
String tParam = getTurnType(next.getTurnType());
boolean isplay = true;
if (tParam != null) {
play.turn(tParam, getSpeakableStreetName(currentSegment, next, !suppressDest));
p.turn(tParam, getSpeakableStreetName(currentSegment, next, !suppressDest));
} else if (next.getTurnType().isRoundAbout()) {
play.roundAbout(next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut(), getSpeakableStreetName(currentSegment, next, !suppressDest));
p.roundAbout(next.getTurnType().getTurnAngle(), next.getTurnType().getExitOut(), getSpeakableStreetName(currentSegment, next, !suppressDest));
} else if (next.getTurnType().getValue() == TurnType.TU || next.getTurnType().getValue() == TurnType.TRU) {
play.makeUT(getSpeakableStreetName(currentSegment, next, !suppressDest));
// Do not announce goAheads
//} else if (next.getTurnType().getValue() == TurnType.C)) {
// play.goAhead();
p.makeUT(getSpeakableStreetName(currentSegment, next, !suppressDest));
// Do not announce goAheads
//} else if (next.getTurnType().getValue() == TurnType.C)) {
// play.goAhead();
} else {
isplay = false;
}
@ -765,31 +755,30 @@ public class VoiceRouter {
// This case only needed should we want a prompt at the end of straight segments (equivalent of makeTurn) when nextNextInfo should be announced again there.
if (nextNextInfo.directionInfo.getTurnType().getValue() != TurnType.C && next.getTurnType().getValue() == TurnType.C) {
play.goAhead();
p.goAhead();
isplay = true;
}
String t2Param = getTurnType(nextNextInfo.directionInfo.getTurnType());
if (t2Param != null) {
if (isplay) {
play.then();
play.turn(t2Param, nextNextInfo.distanceTo, new StreetName());
p.then();
p.turn(t2Param, nextNextInfo.distanceTo, new StreetName());
}
} else if (nextNextInfo.directionInfo.getTurnType().isRoundAbout()) {
if (isplay) {
play.then();
play.roundAbout(nextNextInfo.distanceTo, nextNextInfo.directionInfo.getTurnType().getTurnAngle(), nextNextInfo.directionInfo.getTurnType().getExitOut(), new StreetName());
p.then();
p.roundAbout(nextNextInfo.distanceTo, nextNextInfo.directionInfo.getTurnType().getTurnAngle(), nextNextInfo.directionInfo.getTurnType().getExitOut(), new StreetName());
}
} else if (nextNextInfo.directionInfo.getTurnType().getValue() == TurnType.TU) {
if (isplay) {
play.then();
play.makeUT(nextNextInfo.distanceTo, new StreetName());
p.then();
p.makeUT(nextNextInfo.distanceTo, new StreetName());
}
}
}
if (isplay) {
notifyOnVoiceMessage();
play.play();
play(p);
}
}
}
@ -816,33 +805,33 @@ public class VoiceRouter {
}
public void gpsLocationLost() {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
play.gpsLocationLost().play();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
p.gpsLocationLost();
}
play(p);
}
public void gpsLocationRecover() {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
play.gpsLocationRecover().play();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
p.gpsLocationRecover();
}
play(p);
}
public void newRouteIsCalculated(boolean newRoute) {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
if (!newRoute) {
play.routeRecalculated(router.getLeftDistance(), router.getLeftTime()).play();
p.routeRecalculated(router.getLeftDistance(), router.getLeftTime());
} else {
play.newRouteCalculated(router.getLeftDistance(), router.getLeftTime()).play();
p.newRouteCalculated(router.getLeftDistance(), router.getLeftTime());
}
} else if (player == null) {
pendingCommand = new VoiceCommandPending(!newRoute ? VoiceCommandPending.ROUTE_RECALCULATED : VoiceCommandPending.ROUTE_CALCULATED, this);
}
play(p);
if (newRoute) {
playGoAheadDist = -1;
}
@ -852,28 +841,28 @@ public class VoiceRouter {
}
public void arrivedDestinationPoint(String name) {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
play.arrivedAtDestination(getSpeakablePointName(name)).play();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
p.arrivedAtDestination(getSpeakablePointName(name));
}
play(p);
}
public void arrivedIntermediatePoint(String name) {
CommandBuilder play = getNewCommandPlayerToPlay();
if (play != null) {
notifyOnVoiceMessage();
play.arrivedAtIntermediatePoint(getSpeakablePointName(name)).play();
CommandBuilder p = getNewCommandPlayerToPlay();
if (p != null) {
p.arrivedAtIntermediatePoint(getSpeakablePointName(name));
}
play(p);
}
// This is not needed, used are only arrivedIntermediatePoint (for points on the route) or announceWaypoint (for points near the route=)
//public void arrivedWayPoint(String name) {
// CommandBuilder play = getNewCommandPlayerToPlay();
// if (play != null) {
// notifyOnVoiceMessage();
// play.arrivedAtWayPoint(getSpeakablePointName(name)).play();
// CommandBuilder p = getNewCommandPlayerToPlay();
// if (p != null) {
// p.arrivedAtWayPoint(getSpeakablePointName(name));
// }
// play(p);
//}
public void onApplicationTerminate() {
@ -889,7 +878,7 @@ public class VoiceRouter {
}
/**
* Command to wait until voice player is initialized
* Command to wait until voice player is initialized
*/
private class VoiceCommandPending {
public static final int ROUTE_CALCULATED = 1;
@ -907,16 +896,22 @@ public class VoiceRouter {
int time = voiceRouter.router.getLeftTime();
if (left > 0) {
if (type == ROUTE_CALCULATED) {
notifyOnVoiceMessage();
newCommand.newRouteCalculated(left, time).play();
newCommand.newRouteCalculated(left, time);
} else if (type == ROUTE_RECALCULATED) {
notifyOnVoiceMessage();
newCommand.routeRecalculated(left, time).play();
newCommand.routeRecalculated(left, time);
}
play(newCommand);
}
}
}
private void play(CommandBuilder p) {
if (p != null) {
p.play();
}
notifyOnVoiceMessage();
}
private void makeSound() {
if (isMute()) {
return;
@ -937,13 +932,37 @@ public class VoiceRouter {
}
public void addVoiceMessageListener(VoiceMessageListener voiceMessageListener) {
voiceMessageListeners.put(voiceMessageListener, 0);
voiceMessageListeners = updateVoiceMessageListeners(new ConcurrentHashMap<>(voiceMessageListeners),
voiceMessageListener, true);
}
public void removeVoiceMessageListener(VoiceMessageListener voiceMessageListener) {
voiceMessageListeners.remove(voiceMessageListener);
voiceMessageListeners = updateVoiceMessageListeners(new ConcurrentHashMap<>(voiceMessageListeners),
voiceMessageListener, false);
}
public void notifyOnVoiceMessage() {
for (WeakReference<VoiceMessageListener> weakReferenceWrapper : voiceMessageListeners.keySet()) {
VoiceMessageListener lnt = weakReferenceWrapper.get();
if (lnt != null) {
lnt.onVoiceMessage();
}
}
}
private ConcurrentHashMap<WeakReference<VoiceMessageListener>, Integer> updateVoiceMessageListeners(
ConcurrentHashMap<WeakReference<VoiceMessageListener>, Integer> copy,
VoiceMessageListener listener, boolean isNewListener) {
for (WeakReference<VoiceMessageListener> wr : copy.keySet()) {
VoiceMessageListener l = wr.get();
if (l == null || l.equals(listener)) {
copy.remove(wr);
}
}
if (isNewListener) {
copy.put(new WeakReference<>(listener), 0);
}
return copy;
}
}