Sfoglia il codice sorgente

1.修改Android Apex CRM通知处理。

Pen Li 7 anni fa
parent
commit
163454cfce

+ 338 - 0
ApexDrivers/RAUtilsLibrary/src/main/java/com/usai/redant/rautils/application/ApexApplication.java

@@ -0,0 +1,338 @@
+package com.usai.redant.rautils.application;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.provider.Settings;
+import android.support.v4.app.NotificationCompat;
+import android.text.TextUtils;
+
+import com.usai.redant.rautils.R;
+import com.usai.redant.rautils.receiver.RABroadcast;
+import com.usai.redant.rautils.service.RAService;
+
+import static android.app.Notification.VISIBILITY_PUBLIC;
+import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
+
+
+public class ApexApplication extends Application {
+
+    // region Activity Life
+    private boolean isBackground = false;
+
+    public boolean isBackground() {
+        return isBackground;
+    }
+
+    private class LifeCallback implements ActivityLifecycleCallbacks {
+
+        private int activityStartCount = 0;
+        private Activity mCurrentActivity = null;
+
+        @Override
+        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+
+        }
+
+        @Override
+        public void onActivityStarted(Activity activity) {
+            activityStartCount++;
+            mCurrentActivity = activity;
+        }
+
+        @Override
+        public void onActivityResumed(Activity activity) {
+
+            if(isBackground==true)
+            {
+                isBackground = false;
+                applicationDidEnterForeground();
+            }
+        }
+
+        @Override
+        public void onActivityPaused(Activity activity) {
+
+        }
+
+        @Override
+        public void onActivityStopped(Activity activity) {
+
+            activityStartCount--;
+            if(activityStartCount == 0)
+            {
+                isBackground = true;
+                applicationDidEnterBackground();
+            }
+        }
+
+        @Override
+        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+
+        }
+
+        @Override
+        public void onActivityDestroyed(Activity activity) {
+
+        }
+    }
+    // endregion
+
+    // region Life Circle
+
+    private static ApexApplication instance;
+    private LifeCallback mLifeCallback;
+    private ServiceConnection mServiceConnection = null;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        instance = this;
+        mLifeCallback = new LifeCallback();
+        registerActivityLifecycleCallbacks(mLifeCallback);
+    }
+
+    @Override
+    public void onTerminate() {
+        super.onTerminate();
+
+        unregisterActivityLifecycleCallbacks(mLifeCallback);
+        if (mServiceConnection != null) {
+            unbindService(mServiceConnection);
+        }
+    }
+
+    // endregion
+
+    // region Getter
+    public static ApexApplication sharedApplication() {
+        return instance;
+    }
+
+    public Activity getCurrentActivity() {
+        if (mLifeCallback != null) {
+
+            return mLifeCallback.mCurrentActivity;
+        }
+        return null;
+    }
+
+    // endregion
+
+    // region Callback
+
+    public void applicationDidEnterBackground() {
+
+    }
+
+    public void applicationDidEnterForeground() {
+
+    }
+
+    // endregion
+
+    // region Service & Receiver
+
+    private RAService mService;
+    public void startService(Class serviceCls) {
+
+        mServiceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+
+                RAService.MyBinder binder = (RAService.MyBinder)service;
+                mService = (RAService) binder.getService();
+
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+
+                mService = null;
+            }
+        };
+
+        Intent serviceintent = new Intent();
+        serviceintent.setClass(this, serviceCls);
+
+        ComponentName cn;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            cn =this.startForegroundService(serviceintent);
+        } else {
+            cn =this.startService(serviceintent);
+        }
+
+        Intent intent = new Intent(getApplicationContext(),serviceCls);
+        bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
+    }
+
+    public RAService getService() {
+        return mService;
+    }
+
+    // endregion
+
+    // region Alarm
+
+    public void initAlarm(Class receiverCls) {
+
+        Intent bintent = new Intent(RABroadcast.ACTION_REDANT_INIT_ALARM);
+        bintent.setClass(this, receiverCls);
+        sendBroadcast(bintent);
+    }
+
+    // endregion
+
+    // region Preference
+
+    public SharedPreferences sharedPreferences(String key) {
+
+        SharedPreferences pref=null;
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+        {
+            Context c= this.createDeviceProtectedStorageContext();
+            pref = c.getSharedPreferences(key, 0);
+        }
+        else
+        {
+            pref = getSharedPreferences(key, 0);
+        }
+        return pref;
+    }
+
+    // endregion
+
+    // region Notification
+
+    public class NotificationContent {
+
+        public static final String ExtraKey = "extra";
+
+        private String title;
+        private String body;
+        private int id;
+        private String extra;
+
+        private int smallIcon;
+        private int largeIcon;
+
+        /**
+         * smallIcon like Driver R.drawable.small_icon_clear
+         * largeIcon like Driver R.drawable.large_notification_icon_clear
+         * */
+        public NotificationContent(int id, String title, String body, int smallIcon, int largeIcon, String extra) {
+            this.id = id;
+            this.title = title;
+            this.body = body;
+            this.extra = extra;
+            this.smallIcon = smallIcon;
+            this.largeIcon = largeIcon;
+        }
+    }
+
+    public Class getMainActivityClass() {
+        return Activity.class;
+    }
+
+    public void showNotification(NotificationContent content, String channelId, String channelName) {
+        if (content == null) {
+            return;
+        }
+
+        if (TextUtils.isEmpty(content.title) || TextUtils.isEmpty(content.body)) {
+            return;
+        }
+
+        Intent intent = new Intent(getApplicationContext(), getMainActivityClass());
+        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); // getIntent可能是null
+        if (content.extra != null) {
+            intent.putExtra(NotificationContent.ExtraKey,content.extra); // 程序在后台的情况下,点击通知将程序唤醒到前台时,并不能取得extra
+        }
+
+        /**
+         *
+         * requestCode: 需要保证不同,否则id不通的intent取到的extra也是同一个
+         * */
+        int requestCode = content.id;
+        PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), requestCode, intent,FLAG_UPDATE_CURRENT);
+
+        //1.获取系统通知的管理者
+        NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+        Notification noti = null;
+        long[] vibrates = { 0, 1000, 1000, 1000 };
+
+//        Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+        Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+
+            /**
+             * Oreo不用Priority了,用importance
+             * IMPORTANCE_NONE 关闭通知
+             * IMPORTANCE_MIN 开启通知,不会弹出,但没有提示音,状态栏中无显示
+             * IMPORTANCE_LOW 开启通知,不会弹出,不发出提示音,状态栏中显示
+             * IMPORTANCE_DEFAULT 开启通知,不会弹出,发出提示音,状态栏中显示
+             * IMPORTANCE_HIGH 开启通知,会弹出,发出提示音,状态栏中显示
+             */
+            NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
+            // 震动
+            channel.enableVibration(true);
+            channel.setVibrationPattern(vibrates);
+
+            channel.enableLights(true);
+
+            channel.setSound(soundUri, Notification.AUDIO_ATTRIBUTES_DEFAULT);
+
+            nm.createNotificationChannel(channel);
+
+            noti = new NotificationCompat.Builder(this, channelId)
+                    .setContentTitle(content.title)
+                    .setContentText(content.body)
+                    .setSmallIcon(content.smallIcon)
+                    .setLargeIcon(BitmapFactory.decodeResource(getResources(),content.largeIcon))
+                    .setContentIntent(contentIntent)
+                    .setVisibility(VISIBILITY_PUBLIC)
+                    .setSound(soundUri)
+                    .setLights(0xff00bbff,500,200)
+                    .build();
+        } else {
+
+            noti = new Notification.Builder(this)
+                    .setContentTitle(content.title)
+                    .setContentText(content.body)
+                    .setSmallIcon(content.smallIcon)
+                    .setLargeIcon(BitmapFactory.decodeResource(getResources(),content.largeIcon))
+                    .setContentIntent(contentIntent)
+                    .setVisibility(VISIBILITY_PUBLIC)
+                    .setSound(soundUri)
+                    .setLights(0xff00bbff,500,20)
+                    .build();
+
+        }
+
+        /**
+         * vibrate属性是一个长整型的数组,用于设置手机静止和振动的时长,以毫秒为单位。
+         * 参数中下标为0的值表示手机静止的时长,下标为1的值表示手机振动的时长, 下标为2的值又表示手机静止的时长,以此类推。
+         */
+        noti.vibrate = vibrates;
+
+        noti.flags |= Notification.FLAG_AUTO_CANCEL;
+        nm.notify(content.id, noti);
+    }
+
+    // endregion
+}

+ 20 - 0
ApexDrivers/RAUtilsLibrary/src/main/java/com/usai/redant/rautils/receiver/BootCompleteBroadcastReceiver.java

@@ -3,6 +3,7 @@ package com.usai.redant.rautils.receiver;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Build;
 import android.util.Log;
 
 import com.usai.redant.rautils.utils.dbgUtil;
@@ -48,6 +49,25 @@ public abstract class BootCompleteBroadcastReceiver extends BroadcastReceiver {
         }
     }
 
+    public void startService(Context context, Intent intent, Class serviceCls) {
+
+        Intent intentService = new Intent();
+        intentService.setClass(context, serviceCls);
+        if (intent.getExtras() != null) {
+            intentService.putExtras(intent.getExtras());
+        }
+
+        intentService.setAction(intent.getAction());
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+
+            context.startForegroundService(intentService);
+        } else {
+
+            context.startService(intentService);
+        }
+    }
+
     protected abstract void OnBootComplete(Context context, Intent intent);
     protected abstract void OnLockedBootComplete(Context context, Intent intent);
 }

+ 47 - 1
ApexDrivers/apexcrm/src/main/AndroidManifest.xml

@@ -18,6 +18,9 @@
         android:supportsRtl="true"
         android:theme="@style/AppTheme"
         tools:replace="android:theme,android:icon,android:roundIcon">
+
+        <!-- Provider -->
+
         <provider
             android:name="android.support.v4.content.FileProvider"
             android:authorities="com.usai.apex.apex.crm.fileprovider"
@@ -28,7 +31,50 @@
                 android:resource="@xml/apex_crm_provider_paths" />
         </provider>
 
-        <activity android:name=".MainActivity">
+
+        <!-- Service -->
+
+        <service android:name=".service.CRMService"
+                 android:enabled="true"
+                 android:exported="true"
+                 android:directBootAware="true"
+                 android:label="ApexCRM Background Service"
+            />
+
+        <!-- Receiver -->
+
+        <receiver android:name=".receiver.AlarmReceiver"
+                  android:directBootAware="true"
+                  android:enabled="true"
+                  android:exported="true"
+                  android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
+            <intent-filter>
+
+                <action android:name="REDANT.BROADCAST.ACTION_REDANT_INIT_ALARM" />
+                <action android:name="REDANT.BROADCAST.ACTION_REDANT_ALARM" />
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name=".receiver.BootReceiver"
+                  android:directBootAware="true"
+                  android:enabled="true"
+                  android:exported="false"
+                  android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
+
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>
+            </intent-filter>
+
+        </receiver>
+
+        <!-- Activity -->
+
+        <activity android:name=".MainActivity"
+            android:launchMode="singleTask"
+            >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <action android:name="android.intent.action.VIEW" />

+ 100 - 3
ApexDrivers/apexcrm/src/main/java/com/usai/apex/apexcrm/MainActivity.java

@@ -31,6 +31,7 @@ import android.widget.ProgressBar;
 import android.widget.RelativeLayout;
 import android.widget.Toast;
 
+import com.usai.apex.apexcrm.application.ApexCRMApp;
 import com.usai.apex.apexcrm.dataProvider.DataProvider;
 import com.usai.redant.rautils.infinitephoto.InfinitePhotoActivity;
 import com.usai.redant.rautils.actionsheet.ActionSheet;
@@ -144,9 +145,9 @@ public class MainActivity extends AppCompatActivity implements RAWebView.WebView
 
 
 //            String url = "http://www.dcloud.io/hellomui/";
-//            String url = "http://192.168.1.151:8080/MyWeb/html/test.html";
+            String url = "http://192.168.1.151:8080/MyWeb/html/test.html";
 //            String url = "http://192.168.1.108:8081/j/crm/mobile/login";
-            String url = "https://ra.apexshipping.com/apexcrm/crm/mobile/login";
+//            String url = "https://ra.apexshipping.com/apexcrm/crm/mobile/login";
             Intent intent = getIntent();
             if (intent != null) {
                 String tmpUrl = intent.getStringExtra("url");
@@ -845,7 +846,7 @@ public class MainActivity extends AppCompatActivity implements RAWebView.WebView
                     String urlStr = json.getString("url");
                     String dir = FileManager.SDApplicationTempFolder(self);
 
-                    urlStr = "http://192.168.0.130/ios.pdf";
+//                    urlStr = "http://192.168.0.130/ios.pdf";
 
                     DataProvider.GET_Download(urlStr, dir, new DataProvider.DataProviderCompletion() {
                         @Override
@@ -1088,6 +1089,16 @@ public class MainActivity extends AppCompatActivity implements RAWebView.WebView
             }
             return null;
         }
+
+        @Override
+        public void Login(String user, String password) {
+            ApexCRMApp.sharedCRM().login(user, password);
+        }
+
+        @Override
+        public void Logout() {
+            ApexCRMApp.sharedCRM().logout();
+        }
     };
 
     private static String base64(String path) {
@@ -1099,6 +1110,7 @@ public class MainActivity extends AppCompatActivity implements RAWebView.WebView
 
     private boolean initialize = false; // 首页加载完成
     private boolean error = false;
+    private boolean loading = false;
 
     @Override
     public void onPageStarted(WebView view, String url, Bitmap favicon) {
@@ -1107,6 +1119,7 @@ public class MainActivity extends AppCompatActivity implements RAWebView.WebView
 
         mURL = url;
         synchronized (self) {
+            loading = true;
             if (!initialize) {
                 mProgressbar.setVisibility(View.VISIBLE);
                 error = false;
@@ -1122,10 +1135,16 @@ public class MainActivity extends AppCompatActivity implements RAWebView.WebView
         Log.d(TAG, "onPageFinished: 0");
         
        synchronized (self) {
+           loading = false;
            if (!initialize && !error) {
                initialize = true;
            }
            mProgressbar.setVisibility(View.GONE);
+
+           if (!error) {
+               handleNotificationByJS(notificationId);
+               notificationId = -1;
+           }
        }
 
 
@@ -1163,4 +1182,82 @@ public class MainActivity extends AppCompatActivity implements RAWebView.WebView
     }
 
     // endregion
+
+    // region Notification
+
+    public void readNotificationNow(int notificationId) {
+        if (!ApexCRMApp.sharedCRM().isLogin()) {
+
+            new AlertDialog.Builder(self)
+                    .setTitle("Warning")
+                    .setMessage("you should login first")
+                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+
+                        }
+                    })
+                    .show();
+
+            return;
+        }
+
+        handleNotificationByJS(notificationId);
+    }
+
+    private void handleNotificationByJS(int notificationId) {
+        if (notificationId == -1) {
+            return;
+        }
+        String user = ApexCRMApp.sharedCRM().getUser();
+        String password = ApexCRMApp.sharedCRM().getPassword();
+        String js = String.format("javascript:showPageForNotification(%s, %s, %d)", user, password, notificationId);
+        mWebView.evaluateJavascript(js, new ValueCallback<String>() {
+            @Override
+            public void onReceiveValue(String value) {
+                Log.d(TAG, "onReceiveValue: " + value);
+            }
+        });
+    }
+
+    private final static String NotificationIdKey = "NotificationIdKey";
+    public static void startActivityForNotification(Activity activity, int id) {
+        if (activity != null) {
+
+            Intent intent = new Intent(activity, MainActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+            intent.putExtra(NotificationIdKey, id);
+            activity.startActivity(intent);
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+
+        setIntent(intent);
+    }
+
+    private int notificationId = -1;
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        Intent intent = getIntent();
+        if (intent.hasExtra(NotificationIdKey)) {
+
+            notificationId = intent.getIntExtra(NotificationIdKey, -1);
+            intent.removeExtra(NotificationIdKey);
+
+            // 如果webView正在加载,那么在加载完成回调中处理通知
+            // 否则立即处理通知
+            if (!loading) {
+                handleNotificationByJS(notificationId);
+                this.notificationId = -1;
+            }
+        }
+    }
+
+    // endregion
 }

+ 18 - 0
ApexDrivers/apexcrm/src/main/java/com/usai/apex/apexcrm/RAJSInterface.java

@@ -23,6 +23,8 @@ public class RAJSInterface extends Object {
         void RequestAppVersion(String msg);
         void CleanCache(String msg);
         String FileBase64(String msg);
+        void Login(String user, String password);
+        void Logout();
     }
 
     private RAJSInterfaceDelegate delegate;
@@ -159,6 +161,22 @@ public class RAJSInterface extends Object {
         return null;
     }
 
+    @android.webkit.JavascriptInterface
+    public void login(String user, String password) {
+
+        if (delegate != null) {
+            delegate.Login(user, password);
+        }
+    }
+
+    @android.webkit.JavascriptInterface
+    public void logout() {
+
+        if (delegate != null) {
+            delegate.Logout();
+        }
+    }
+
     // endregion
 
     private static boolean jsonValueIsNull(JSONObject json, String key) {

+ 234 - 2
ApexDrivers/apexcrm/src/main/java/com/usai/apex/apexcrm/application/ApexCRMApp.java

@@ -1,13 +1,245 @@
 package com.usai.apex.apexcrm.application;
 
-import android.app.Application;
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
 
+import com.usai.apex.apexcrm.MainActivity;
+import com.usai.apex.apexcrm.R;
+import com.usai.apex.apexcrm.receiver.AlarmReceiver;
+import com.usai.apex.apexcrm.service.CRMService;
+import com.usai.redant.rautils.application.ApexApplication;
+import com.usai.redant.rautils.receiver.RABroadcast;
+import com.usai.redant.rautils.utils.AESUtil;
 import com.usai.redant.rautils.utils.RAProviderHelper;
 
-public class ApexCRMApp extends Application implements RAProviderHelper.ProviderHelperDelegate {
+import org.json.JSONObject;
 
+public class ApexCRMApp extends ApexApplication implements RAProviderHelper.ProviderHelperDelegate {
+
+    private final static String PreferenceKey = "ApexCRM";
+    private final static String SecretKey = "usai";
+
+    // region Service
+    public static String CHANNEL_ID = "ApexCRM";
+    public static String CHANNEL_NAME = "ApexCRM";
+
+    // endregion
+
+    // region File Provider
     @Override
     public String getProviderAuthorities() {
         return "com.usai.apex.apex.crm.fileprovider";
     }
+    // endregion
+
+    // region Activity Life
+
+    @Override
+    public void applicationDidEnterBackground() {
+        super.applicationDidEnterBackground();
+    }
+
+    @Override
+    public void applicationDidEnterForeground() {
+        super.applicationDidEnterForeground();
+
+        //notification
+        Intent intent = new Intent(RABroadcast.ACTION_REDANT_INIT_ALARM);
+        intent.setClass(ApexCRMApp.this, AlarmReceiver.class);
+        sendBroadcast(intent);
+    }
+
+    // endregion
+
+    // region Override
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        startService(CRMService.class);
+        initAlarm(AlarmReceiver.class);
+    }
+
+    @Override
+    public Class getMainActivityClass() {
+        return MainActivity.class;
+    }
+
+    // endregion
+
+    // region Getter
+
+    public static ApexCRMApp sharedCRM() {
+        return (ApexCRMApp)sharedApplication();
+    }
+
+    // endregion
+
+    // region User
+
+    private String user;
+    private String password;
+
+    public String getUser() {
+        return user;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public void login(String user, String password) {
+        setUser(user);
+        setPassword(password);
+    }
+
+    public void logout() {
+        setUser(null);
+        setPassword(null);
+    }
+
+    public boolean isLogin() {
+        return user != null && password != null;
+    }
+
+    // endregion
+
+    // region Notification
+    private volatile long notificationID;
+    public void setNotificationID(long id) {
+        notificationID = id;
+
+        if (user == null) {
+            return;
+        }
+
+        SharedPreferences pref = sharedPreferences(PreferenceKey);
+        SharedPreferences.Editor editor = pref.edit();
+        String key = user + "_notification_id";
+        try {
+
+            editor.putLong(key, notificationID);
+
+        } catch (Exception e) {
+            editor.putString(key, null);
+            e.printStackTrace();
+        }
+        editor.commit();
+    }
+
+    public long getNotificationID() {
+
+        if (notificationID == 0) {
+
+            SharedPreferences pref = sharedPreferences(PreferenceKey);
+            String key = user + "_notification_id";
+            long id = pref.getLong(key, 0);
+            notificationID = id;
+        }
+
+        return notificationID;
+    }
+
+    public void receiveNotificationOnMainThread(final JSONObject notification) {
+        new Handler(Looper.getMainLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                receiveNotification(notification);
+            }
+        });
+    }
+
+    private void receiveNotification(JSONObject notification) {
+
+        if (notification != null) {
+
+            JSONObject aps = notification.optJSONObject("aps");
+            if (aps != null) {
+
+                final int id = aps.optInt("id");
+                boolean isActive = !isBackground(); // 程序是否在前台
+                if (isActive) {
+
+                    // 弹窗提示
+                    AlertDialog.Builder builder = new AlertDialog.Builder(getCurrentActivity());
+                    builder.setTitle("Warning");
+                    builder.setMessage("you have a message, read it now?");
+                    builder.setNegativeButton("Cancel",null);
+                    builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            readNotificationNow(id);
+                        }
+                    });
+                    builder.show();
+
+                } else {
+                    // 发通知
+
+                    JSONObject alert = aps.optJSONObject("alert");
+                    String title = null,body = null;
+                    if (alert != null) {
+
+                        title = alert.optString("title");
+                        body = alert.optString("body");
+                    }
+
+                    NotificationContent notificationContent = new NotificationContent(id, title, body, R.drawable.small_icon_clear, R.drawable.large_notification_icon_clear , aps.toString());
+
+                    showNotification(notificationContent, CHANNEL_ID, CHANNEL_NAME);
+                }
+
+            }
+        }
+    }
+
+    private void readNotificationNow(int notificationID) {
+
+        Activity activity = getCurrentActivity();
+
+        if (activity instanceof MainActivity) {
+
+            MainActivity mainActivity = (MainActivity)activity;
+            mainActivity.readNotificationNow(notificationID);
+
+        } else {
+
+            MainActivity.startActivityForNotification(activity, notificationID);
+        }
+    }
+
+    // endregion
+
+    // region Private
+
+    public String encryptString(String string) {
+        if (string == null) {
+            return null;
+        }
+        return AESUtil.encrypt256(SecretKey,string);
+    }
+
+    public String decryptString(String string) {
+        if (string == null) {
+            return null;
+        }
+        return AESUtil.decrypt256(SecretKey, string);
+    }
+
+    // endregion
+
 }

+ 153 - 0
ApexDrivers/apexcrm/src/main/java/com/usai/apex/apexcrm/dataProvider/DataProvider.java

@@ -1,20 +1,38 @@
 package com.usai.apex.apexcrm.dataProvider;
 
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import com.usai.apex.apexcrm.application.ApexCRMApp;
 import com.usai.redant.rautils.operationqueue.OperationQueue;
 import com.usai.redant.rautils.utils.Network;
+import com.usai.redant.rautils.utils.RAUtil;
+import com.usai.redant.rautils.utils.dbgUtil;
 
+import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.io.File;
+import java.util.Locale;
 
 import static com.usai.redant.rautils.utils.Network.RESULT_TRUE;
+import static com.usai.redant.rautils.utils.Network.isNetworkAvailable;
 
 public class DataProvider {
 
+    public static final int PUSH_TIME_OUT_INTERVAL = 5 * 1000;
+    // region URL
+
+    private static final String URL_PULL_NOTIFICATION = "http://192.168.1.151:8080/MyWeb/Test";
+
+    // endregion
+
     public interface DataProviderCompletion {
         void completion(Object object);
     }
 
+    // region Download
+
     public static void GET_Download(final String url, final String destDir, final DataProviderCompletion completion) {
 
         OperationQueue.sharedQueue().addOperationTask(new OperationQueue.OperationBackgroundCallBack() {
@@ -68,5 +86,140 @@ public class DataProvider {
         });
 
     }
+    // endregion
+
+    // region Get Json
+
+    private static Bundle prepareParams(Bundle params) {
+        if (params == null) {
+            params = new Bundle();
+        }
+
+        String password = params.getString("password");
+
+        String user = params.getString("name");
+        if (user == null) {
+            user = ApexCRMApp.sharedCRM().getUser();
+            if (!TextUtils.isEmpty(user)) {
+                params.putString("name",ApexCRMApp.sharedCRM().encryptString(user));
+            }
+        }
+
+        if (password == null) {
+            password = ApexCRMApp.sharedCRM().getPassword();
+            if (!TextUtils.isEmpty(password)) {
+                params.putString("password",ApexCRMApp.sharedCRM().encryptString(password));
+            }
+        }
+
+        Locale curLocale = ApexCRMApp.sharedApplication().getResources().getConfiguration().locale;
+        String languageCode = curLocale.getLanguage();
+        if (languageCode != null) {
+            params.putString("language",languageCode);
+        }
+
+        params.putString("platform","android");
+
+        return params;
+    }
+
+    private static JSONObject handleJson(String jsonStr) {
+
+        if (jsonStr == null || jsonStr.isEmpty()) {
+            return handleNullJson();
+        }
+
+        try {
+            JSONObject json = new JSONObject(jsonStr);
+            String msg = json.optString("msg");
+            if (msg != null) {
+                msg = "Sorry, something is wrong";
+            }
+            json.put("err_msg",msg);
+
+            return json;
+        } catch (JSONException e) {
+            e.printStackTrace();
+            return handleNullJson();
+        }
+    }
+
+    private static JSONObject handleNullJson() {
+        JSONObject json = new JSONObject();
+        try {
+            json.put("result", Network.RESULT_FALSE);
+            json.put("err_msg", "Sorry, something is wrong");
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+        return json;
+    }
+
+    private static String getJson(String url, Bundle params) {
+
+        return getJSON(url, params, com.usai.redant.rautils.utils.Network.SO_TIMEOUT);
+    }
+
+    private static String getJSON(String url, Bundle params, int timeout) {
+
+        params = prepareParams(params);
+
+        dbgUtil.fileLog(ApexCRMApp.sharedApplication(), "getJSON(String url, Bundle params, int timeout) params " + params.toString());
+        dbgUtil.fileLog(ApexCRMApp.sharedApplication(), "getJSON(String url, Bundle params, int timeout) network available:" + (isNetworkAvailable(ApexCRMApp.sharedApplication())));
+
+        return Network.getJson(url,params,timeout);
+    }
+
+    // endregion
+
+    // region Notification
+
+    public static void pullNotification(final DataProviderCompletion completion) {
+
+        if (!ApexCRMApp.sharedCRM().isLogin()) {
+            if (completion != null) {
+                JSONObject json = new JSONObject();
+                try {
+                    json.put("result", Network.RESULT_FALSE);
+                    json.put("err_msg", "should login first");
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+
+                completion.completion(null);
+            }
+            return;
+        }
+
+        final long notificationId = ApexCRMApp.sharedCRM().getNotificationID();
+        final String deviceId = RAUtil.getDeviceId(ApexCRMApp.sharedCRM().getApplicationContext());
+
+        OperationQueue.sharedQueue().addOperationTask(new OperationQueue.OperationBackgroundCallBack() {
+
+            @Override
+            public Object operationDoInBackground() {
+
+                Bundle params = new Bundle();
+                params.putString("token", deviceId);
+                params.putLong("id", notificationId);
+
+                return getJSON(URL_PULL_NOTIFICATION, params, PUSH_TIME_OUT_INTERVAL);
+            }
+
+        }, new OperationQueue.OperationCompletionCallBack() {
+
+            @Override
+            public void operationCompletion(Object object) {
+
+                if (completion != null) {
+                    String jsonStr = (String)object;
+                    JSONObject json = handleJson(jsonStr);
+                    completion.completion(json);
+                }
+            }
+
+        }, null);
+    }
 
+    // end region
 }

+ 181 - 0
ApexDrivers/apexcrm/src/main/java/com/usai/apex/apexcrm/receiver/AlarmReceiver.java

@@ -0,0 +1,181 @@
+package com.usai.apex.apexcrm.receiver;
+
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.usai.apex.apexcrm.application.ApexCRMApp;
+import com.usai.apex.apexcrm.dataProvider.DataProvider;
+import com.usai.redant.rautils.operationqueue.OperationQueue;
+import com.usai.redant.rautils.receiver.RABroadcast;
+import com.usai.redant.rautils.utils.dbgUtil;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import static com.usai.redant.rautils.utils.Network.RESULT_TRUE;
+
+public class AlarmReceiver extends com.usai.redant.rautils.receiver.AlarmReceiver {
+
+    private final static String TAG = "CRM Alarm Receiver";
+    
+    // region Override
+    @Override
+    protected void InitAlarm(Context context, Intent intent) {
+
+        int alarm_timeInterval = aggressive_alarm_timeInterval;
+        if(ApexCRMApp.sharedApplication().isBackground()) {
+            alarm_timeInterval = normal_alarm_timeInterval;
+        }
+        dbgUtil.fileLog(context, TAG + " InitAlarm ");
+
+
+        // 启动完成
+
+        Intent iAlarm = new Intent(RABroadcast.ACTION_REDANT_ALARM);
+        iAlarm.setClass(context, AlarmReceiver.class);
+
+        PendingIntent sender = PendingIntent.getBroadcast(context, 0, iAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
+
+        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        
+        if(am==null) {
+            dbgUtil.fileLog(context, TAG + " init alarm Alarm Manager am == null");
+            return;
+        }
+
+        am.cancel(sender);
+
+        
+        dbgUtil.fileLog(context, TAG + " setup up alarm");
+        
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            
+            am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), sender);
+            dbgUtil.fileLog(context, TAG + " init alarm Alarm Manager am.setExactAndAllowWhileIdle");
+
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            
+            am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), sender);
+            dbgUtil.fileLog(context, TAG + " init alarm Alarm Manager am.setExact");
+
+        } else {
+            
+            am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), alarm_timeInterval, sender);
+            dbgUtil.fileLog(context, TAG + " init alarm Alarm Manager am.setRepeating");
+        }
+    }
+
+    @Override
+    protected void CancelAlarm(Context context, Intent intent) {
+        cancelalarm(context);
+    }
+
+    @Override
+    protected void AlarmProc(Context context, Intent intent) {
+
+        int alarm_timeInterval = aggressive_alarm_timeInterval;
+        if(ApexCRMApp.sharedApplication().isBackground()) {
+            alarm_timeInterval = normal_alarm_timeInterval;
+        }
+
+        dbgUtil.fileLog(context, TAG + " AlarmProc ");
+
+        check_push(context);
+
+
+        Intent iAlarm = new Intent(RABroadcast.ACTION_REDANT_ALARM);
+
+        iAlarm.setClass(context, AlarmReceiver.class);
+        PendingIntent sender = PendingIntent.getBroadcast(context, 0, iAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
+
+
+        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        
+        if(am==null) {
+            dbgUtil.fileLog(context, TAG + " Alarm Process Alarm Manager am == null");
+            return;
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + alarm_timeInterval, sender);
+            dbgUtil.fileLog(context, TAG + " Alarm Process am.setExactAndAllowWhileIdle");
+
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            
+            am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + alarm_timeInterval, sender);
+            dbgUtil.fileLog(context, TAG + " Alarm Process am.setExact");
+        } else {
+
+            dbgUtil.fileLog(context, TAG + " Alarm Process else");
+        }
+    }
+    
+    // endregion
+    
+    // region Cancel
+
+    private void cancelalarm(Context context) {
+        
+        Intent iAlarm = new Intent(RABroadcast.ACTION_REDANT_ALARM);
+
+
+        iAlarm.setClass(context, AlarmReceiver.class);
+
+        PendingIntent sender = PendingIntent.getBroadcast(context, 0, iAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
+
+        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+        if(am==null)
+            return;
+
+        am.cancel(sender);
+    }
+    
+    // endregion
+    
+    // region Push
+    
+    private void check_push(final Context context) {
+
+        dbgUtil.fileLog(context, TAG + " Check Push");
+        DataProvider.pullNotification(new DataProvider.DataProviderCompletion() {
+            @Override
+            public void completion(Object object) {
+
+                JSONObject json = (JSONObject) object;
+                dbgUtil.fileLog(context, TAG + " Get Push " + (json == null ? "null" : json.toString()));
+
+                if (json != null) {
+
+                    int result = json.optInt("result", 0);
+                    if (result == RESULT_TRUE) {
+
+                        long notificationId = json.optLong("notificationId");
+                        ApexCRMApp.sharedCRM().setNotificationID(notificationId);
+
+                        JSONArray notifications = json.optJSONArray("notifications");
+                        if (notifications != null) {
+
+                            for (int i = 0; i < notifications.length(); i++) {
+                                JSONObject notification = notifications.optJSONObject(i);
+                                if (notification != null) {
+                                    ApexCRMApp.sharedCRM().receiveNotificationOnMainThread(notification);
+                                }
+                            }
+
+                        }
+
+                    }
+                }
+            }
+        });
+
+    }
+    
+    // endregion
+}

+ 25 - 0
ApexDrivers/apexcrm/src/main/java/com/usai/apex/apexcrm/receiver/BootReceiver.java

@@ -0,0 +1,25 @@
+package com.usai.apex.apexcrm.receiver;
+
+import android.content.Context;
+import android.content.Intent;
+
+import com.usai.apex.apexcrm.service.CRMService;
+import com.usai.redant.rautils.receiver.BootCompleteBroadcastReceiver;
+import com.usai.redant.rautils.utils.dbgUtil;
+
+public class BootReceiver extends BootCompleteBroadcastReceiver {
+
+    @Override
+    protected void OnBootComplete(Context context, Intent intent) {
+
+        dbgUtil.fileLog(context,"ApexCRM: OnBootComplete");
+        startService(context, intent, CRMService.class);
+    }
+
+    @Override
+    protected void OnLockedBootComplete(Context context, Intent intent) {
+
+        dbgUtil.fileLog(context,"ApexCRM: OnLockedBootComplete");
+        startService(context, intent, CRMService.class);
+    }
+}

+ 16 - 0
ApexDrivers/apexcrm/src/main/java/com/usai/apex/apexcrm/service/CRMService.java

@@ -0,0 +1,16 @@
+package com.usai.apex.apexcrm.service;
+
+import com.usai.apex.apexcrm.application.ApexCRMApp;
+import com.usai.redant.rautils.service.RAService;
+
+public class CRMService extends RAService {
+
+
+
+    @Override
+    protected void Setup() {
+
+        CHANNEL_ID = ApexCRMApp.CHANNEL_ID;
+        CHANNEL_NAME = ApexCRMApp.CHANNEL_NAME;
+    }
+}

BIN
ApexDrivers/apexcrm/src/main/res/drawable/large_notification_icon_clear.png


BIN
ApexDrivers/apexcrm/src/main/res/drawable/small_icon_clear.png