[android] Modified implicit receivers for lollipop or later

This commit is contained in:
Dmitry Donskoy 2018-08-27 18:17:39 +03:00 committed by Aleksandr Zatsepin
parent d934d0551c
commit 3d0727b571
8 changed files with 327 additions and 77 deletions

View file

@ -440,24 +440,22 @@
android:label="@string/subtittle_opt_out"
android:configChanges="keyboardHidden|orientation|screenSize">
</activity>
<receiver
android:name="com.mapswithme.maps.background.ConnectivityChangedReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<service
android:name="com.mapswithme.maps.background.WorkerService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<service
android:name="com.mapswithme.maps.background.NotificationService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false"/>
<service android:name="com.mapswithme.maps.scheduling.NativeJobService"
android:enabled="true"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
<receiver android:name="com.mapswithme.maps.location.TrackRecorderWakeReceiver">
<intent-filter>
<action android:name="com.mapswithme.maps.TRACK_RECORDER_ALARM"/>
@ -489,16 +487,6 @@
MultipleTrackerReferrerReceiver and then pass it manually to myTracker's one. -->
<service android:name="com.my.tracker.campaign.CampaignService"/>
<!-- Alohalytics -->
<receiver
android:name="org.alohalytics.ConnectivityChangedReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"

View file

@ -546,7 +546,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
mSearchController.setVisibilityListener(this);
SharingHelper.INSTANCE.initialize();
//TODO: uncomment after correct visible rect calculation.
//mVisibleRectMeasurer = new VisibleRectMeasurer(new VisibleRectListener() {
// @Override

View file

@ -28,6 +28,8 @@ import com.mapswithme.maps.maplayer.traffic.TrafficManager;
import com.mapswithme.maps.purchase.Factory;
import com.mapswithme.maps.purchase.PurchaseValidator;
import com.mapswithme.maps.routing.RoutingController;
import com.mapswithme.maps.scheduling.JobDispatcher;
import com.mapswithme.maps.scheduling.JobDispatcherComposite;
import com.mapswithme.maps.sound.TtsPlayer;
import com.mapswithme.maps.ugc.UGC;
import com.mapswithme.util.Config;
@ -81,54 +83,15 @@ public class MwmApplication extends Application
private Handler mMainLoopHandler;
private final Object mMainQueueToken = new Object();
private final MapManager.StorageCallback mStorageCallbacks = new MapManager.StorageCallback()
{
@Override
public void onStatusChanged(List<MapManager.StorageCallbackData> data)
{
for (MapManager.StorageCallbackData item : data)
if (item.isLeafNode && item.newStatus == CountryItem.STATUS_FAILED)
{
if (MapManager.nativeIsAutoretryFailed())
{
Notifier.notifyDownloadFailed(item.countryId, MapManager.nativeGetName(item.countryId));
MapManager.sendErrorStat(Statistics.EventName.DOWNLOADER_ERROR, MapManager.nativeGetError(item.countryId));
}
return;
}
}
@Override
public void onProgress(String countryId, long localSize, long remoteSize) {}
};
@NonNull
private final AppBackgroundTracker.OnTransitionListener mBackgroundListener =
new AppBackgroundTracker.OnTransitionListener()
{
@Override
public void onTransit(boolean foreground)
{
if (!foreground && LoggerFactory.INSTANCE.isFileLoggingEnabled())
{
Log.i(TAG, "The app goes to background. All logs are going to be zipped.");
LoggerFactory.INSTANCE.zipLogs(null);
}
}
};
private final AppBackgroundTracker.OnVisibleAppLaunchListener mVisibleAppLaunchListener = new VisibleAppLaunchListener();
@SuppressWarnings("NullableProblems")
@NonNull
private final AppBackgroundTracker.OnVisibleAppLaunchListener mVisibleAppLaunchListener =
new AppBackgroundTracker.OnVisibleAppLaunchListener()
{
@Override
public void onVisibleAppLaunch()
{
Statistics.INSTANCE.trackColdStartupInfo();
}
};
private JobDispatcher mJobDispatcher;
@NonNull
private final MapManager.StorageCallback mStorageCallbacks = new StorageCallbackImpl();
@NonNull
private final AppBackgroundTracker.OnTransitionListener mBackgroundListener = new TransitionListener();
@NonNull
public SubwayManager getSubwayManager()
@ -205,6 +168,8 @@ public class MwmApplication extends Application
mBackgroundTracker = new AppBackgroundTracker();
mBackgroundTracker.addListener(mVisibleAppLaunchListener);
mSubwayManager = new SubwayManager(this);
mJobDispatcher = new JobDispatcherComposite(this);
mJobDispatcher.dispatch();
}
private void initCoreIndependentSdks()
@ -476,6 +441,12 @@ public class MwmApplication extends Application
mMainLoopHandler.sendMessage(m);
}
@NonNull
public JobDispatcher getJobDispatcher()
{
return mJobDispatcher;
}
private native void nativeInitPlatform(String apkPath, String storagePath, String privatePath,
String tmpPath, String obbGooglePath, String flavorName,
String buildType, boolean isTablet);
@ -486,4 +457,48 @@ public class MwmApplication extends Application
@UiThread
private static native void nativeInitCrashlytics();
private static class VisibleAppLaunchListener implements AppBackgroundTracker.OnVisibleAppLaunchListener
{
@Override
public void onVisibleAppLaunch()
{
Statistics.INSTANCE.trackColdStartupInfo();
}
}
private static class StorageCallbackImpl implements MapManager.StorageCallback
{
@Override
public void onStatusChanged(List<MapManager.StorageCallbackData> data)
{
for (MapManager.StorageCallbackData item : data)
if (item.isLeafNode && item.newStatus == CountryItem.STATUS_FAILED)
{
if (MapManager.nativeIsAutoretryFailed())
{
Notifier.notifyDownloadFailed(item.countryId, MapManager.nativeGetName(item.countryId));
MapManager.sendErrorStat(Statistics.EventName.DOWNLOADER_ERROR, MapManager.nativeGetError(item.countryId));
}
return;
}
}
@Override
public void onProgress(String countryId, long localSize, long remoteSize) {}
}
private static class TransitionListener implements AppBackgroundTracker.OnTransitionListener
{
@Override
public void onTransit(boolean foreground)
{
if (!foreground && LoggerFactory.INSTANCE.isFileLoggingEnabled())
{
Log.i(TAG, "The app goes to background. All logs are going to be zipped.");
LoggerFactory.INSTANCE.zipLogs(null);
}
}
}
}

View file

@ -2,9 +2,9 @@ package com.mapswithme.maps.background;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
import android.text.TextUtils;
import com.mapswithme.maps.LightFramework;
import com.mapswithme.maps.MwmApplication;
@ -32,7 +32,7 @@ public class NotificationService extends JobIntentService
boolean tryToNotify();
}
static void startOnConnectivityChanged(Context context)
public static void startOnConnectivityChanged(Context context)
{
final Intent intent = new Intent(context, NotificationService.class)
.setAction(CONNECTIVITY_ACTION);
@ -88,15 +88,8 @@ public class NotificationService extends JobIntentService
{
final String action = intent.getAction();
if (TextUtils.isEmpty(action))
return;
switch(action)
{
case CONNECTIVITY_ACTION:
onConnectivityChanged();
break;
}
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action))
onConnectivityChanged();
}
private static void onConnectivityChanged()

View file

@ -89,7 +89,8 @@ public final class TrackRecorder
private static PendingIntent getAlarmIntent()
{
return PendingIntent.getBroadcast(MwmApplication.get(), 0, sAlarmIntent, 0);
Intent intent = new Intent(MwmApplication.get(), TrackRecorderWakeReceiver.class);
return PendingIntent.getBroadcast(MwmApplication.get(), 0, intent, 0);
}
private static void restartAlarmIfEnabled()

View file

@ -0,0 +1,7 @@
package com.mapswithme.maps.scheduling;
public interface JobDispatcher
{
void dispatch();
void cancelAll();
}

View file

@ -0,0 +1,199 @@
package com.mapswithme.maps.scheduling;
import android.annotation.TargetApi;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.support.annotation.NonNull;
import com.mapswithme.maps.MwmApplication;
import com.mapswithme.maps.background.ConnectivityChangedReceiver;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
public class JobDispatcherComposite implements JobDispatcher
{
@NonNull
private final JobDispatcher mMasterJobDispatcher;
@NonNull
private final MwmApplication mContext;
@NonNull
private final AtomicInteger mCurrentNetworkType;
public JobDispatcherComposite(@NonNull MwmApplication context)
{
mContext = context;
mMasterJobDispatcher = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
? new NativeJobDispatcher(mContext)
: new LegacyJobDispatcher(mContext);
mCurrentNetworkType = new AtomicInteger(getCurrentNetworkType().ordinal());
}
@Override
public void dispatch()
{
mMasterJobDispatcher.dispatch();
}
@Override
public void cancelAll()
{
mMasterJobDispatcher.cancelAll();
}
@NonNull
public NetworkStatus getNetworkStatus()
{
NetworkType currentNetworkType = getCurrentNetworkType();
int prevTypeIndex = mCurrentNetworkType.getAndSet(currentNetworkType.mType);
NetworkType prevNetworkType = NetworkType.getInstance(prevTypeIndex);
boolean isNetworkChanged = prevNetworkType != currentNetworkType;
return new NetworkStatus(isNetworkChanged, currentNetworkType);
}
private NetworkType getCurrentNetworkType()
{
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork;
if (cm == null || (activeNetwork = cm.getActiveNetworkInfo()) == null)
return NetworkType.UNDEFINED;
return NetworkType.getInstance(activeNetwork.getType());
}
public enum NetworkType
{
WIFI(ConnectivityManager.TYPE_WIFI),
MOBILE(ConnectivityManager.TYPE_MOBILE),
UNDEFINED;
private final int mType;
NetworkType(int type)
{
mType = type;
}
NetworkType()
{
this(-1);
}
@NonNull
public static NetworkType getInstance(int type)
{
for (NetworkType each : values())
{
if (each.mType == type)
return each;
}
return NetworkType.UNDEFINED;
}
}
public static JobDispatcherComposite from(@NonNull Context context)
{
MwmApplication application = (MwmApplication) context.getApplicationContext();
return (JobDispatcherComposite) application.getJobDispatcher();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static class NativeJobDispatcher implements JobDispatcher
{
private static final int PERIODIC_IN_MILLIS = 4000;
@NonNull
private final JobScheduler mJobScheduler;
@NonNull
private final Context mContext;
NativeJobDispatcher(@NonNull Context context)
{
mContext = context;
JobScheduler jobScheduler = (JobScheduler) mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
Objects.requireNonNull(jobScheduler);
mJobScheduler = jobScheduler;
}
@Override
public void dispatch()
{
ComponentName component = new ComponentName(mContext, NativeJobService.class);
int jobId = NativeJobService.class.hashCode();
JobInfo jobInfo = new JobInfo
.Builder(jobId, component)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPeriodic(PERIODIC_IN_MILLIS)
.build();
mJobScheduler.schedule(jobInfo);
}
@Override
public void cancelAll()
{
mJobScheduler.cancelAll();
}
}
public static class NetworkStatus
{
private final boolean mNetworkStateChanged;
@NonNull
private final NetworkType mCurrentNetworkType;
NetworkStatus(boolean networkStateChanged,
@NonNull NetworkType currentNetworkType)
{
mNetworkStateChanged = networkStateChanged;
mCurrentNetworkType = currentNetworkType;
}
public boolean isNetworkStateChanged()
{
return mNetworkStateChanged;
}
@NonNull
public NetworkType getCurrentNetworkType()
{
return mCurrentNetworkType;
}
}
private static class LegacyJobDispatcher implements JobDispatcher
{
@NonNull
private final MwmApplication mContext;
@NonNull
private final ConnectivityChangedReceiver mReceiver;
LegacyJobDispatcher(@NonNull MwmApplication context)
{
mContext = context;
mReceiver = new ConnectivityChangedReceiver();
}
@Override
public void dispatch()
{
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(mReceiver, filter);
}
@Override
public void cancelAll()
{
mContext.unregisterReceiver(mReceiver);
}
}
}

View file

@ -0,0 +1,48 @@
package com.mapswithme.maps.scheduling;
import android.annotation.TargetApi;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.os.Build;
import com.mapswithme.maps.background.NotificationService;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class NativeJobService extends JobService
{
@Override
public boolean onStartJob(JobParameters params)
{
JobDispatcherComposite jobDispatcher = JobDispatcherComposite.from(this);
JobDispatcherComposite.NetworkStatus status = jobDispatcher.getNetworkStatus();
if (status.isNetworkStateChanged())
NotificationService.startOnConnectivityChanged(this);
if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
scheduleRefresh();
return true;
}
private void scheduleRefresh()
{
JobScheduler service = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName component = new ComponentName(getApplicationContext(), NativeJobService.class);
int jobId = NativeJobService.class.hashCode();
/*FIXME*/
JobInfo jobInfo = new JobInfo.Builder(jobId, component)
.setMinimumLatency(4000)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
service.schedule(jobInfo);
}
@Override
public boolean onStopJob(JobParameters params)
{
return false;
}
}