1/*
2 * Copyright (c) 2015, Motorola Mobility LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *     - Redistributions of source code must retain the above copyright
8 *       notice, this list of conditions and the following disclaimer.
9 *     - Redistributions in binary form must reproduce the above copyright
10 *       notice, this list of conditions and the following disclaimer in the
11 *       documentation and/or other materials provided with the distribution.
12 *     - Neither the name of Motorola Mobility nor the
13 *       names of its contributors may be used to endorse or promote products
14 *       derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 * DAMAGE.
27 */
28
29package com.android.service.ims.presence;
30
31import android.content.Intent;
32import android.os.IBinder;
33import android.os.RemoteException;
34import android.app.Service;
35import android.os.SystemProperties;
36import android.os.Handler;
37import android.os.Looper;
38import android.os.Message;
39import android.os.HandlerThread;
40import android.os.Process;
41import java.util.ArrayList;
42import android.content.ContentValues;
43import android.text.TextUtils;
44
45import com.android.ims.internal.Logger;
46import com.android.ims.RcsManager.ResultCode;
47import com.android.ims.RcsPresence;
48import com.android.ims.RcsPresenceInfo;
49
50/**
51 * This service essentially plays the role of a "worker thread", allowing us to store
52 * presence information.
53 */
54public class PersistService extends Service {
55    private Logger logger = Logger.getLogger(this.getClass().getName());
56
57    private static final int MESSAGE_PRESENCE_CHANGED = 1;
58    private static final int MESSAGE_PUBLISH_STATE_CHANGED = 2;
59
60    private int mVltProvisionErrorCount = 0;
61    private Looper mServiceLooper = null;
62    private ServiceHandler mServiceHandler = null;
63    private EABContactManager mEABContactManager = null;
64
65    @Override
66    public void onCreate() {
67        mEABContactManager = new EABContactManager(getContentResolver(), getPackageName());
68
69        // separate thread because the service normally runs in the process's
70        // main thread, which we don't want to block.
71        HandlerThread thread = new HandlerThread("PersistServiceThread",
72                Process.THREAD_PRIORITY_BACKGROUND);
73        thread.start();
74
75        mServiceLooper = thread.getLooper();
76        mServiceHandler = new ServiceHandler(mServiceLooper);
77    }
78
79    @Override
80    public int onStartCommand(Intent intent, int flags, int startId) {
81        if(intent == null) {
82            return Service.START_NOT_STICKY;
83        }
84
85        if(RcsPresence.ACTION_PRESENCE_CHANGED.equals(intent.getAction())) {
86            Message msg = mServiceHandler.obtainMessage(MESSAGE_PRESENCE_CHANGED);
87            msg.arg1 = startId;
88            msg.obj = intent;
89            mServiceHandler.sendMessage(msg);
90            return Service.START_NOT_STICKY;
91        } else if(RcsPresence.ACTION_PUBLISH_STATE_CHANGED.equals(intent.getAction())) {
92            Message msg = mServiceHandler.obtainMessage(MESSAGE_PUBLISH_STATE_CHANGED);
93            msg.arg1 = startId;
94            msg.obj = intent;
95            mServiceHandler.sendMessage(msg);
96            return Service.START_NOT_STICKY;
97        } else {
98            logger.debug("unknown intent=" + intent);
99        }
100
101        return Service.START_NOT_STICKY;
102    }
103
104    @Override
105    public void onDestroy() {
106        mServiceLooper.quit();
107    }
108
109    @Override
110    public IBinder onBind(Intent intent) {
111        return null;
112    }
113
114    private final class ServiceHandler extends Handler {
115        public ServiceHandler(Looper looper) {
116            super(looper);
117        }
118
119        /**
120         * Handler to save the presence information.
121         */
122        @Override
123        public void handleMessage(Message msg) {
124            super.handleMessage(msg);
125            logger.print( "Thread=" + Thread.currentThread().getName() + " received "
126                    + msg);
127            if(msg == null){
128                logger.error("msg=null");
129                return;
130            }
131
132            int serviceId = msg.arg1;
133            Intent intent = (Intent)msg.obj;
134            logger.print("handleMessage serviceId: " + serviceId + " intent: " + intent);
135            switch (msg.what) {
136                case MESSAGE_PRESENCE_CHANGED:
137                    if (intent != null) {
138                        if (RcsPresence.ACTION_PRESENCE_CHANGED.equals(intent.getAction())) {
139                            handlePresence(intent);
140                        } else {
141                            logger.debug("I don't care about intent: " + intent);
142                        }
143                        intent.setComponent(null);
144                        sendBroadcast(intent);
145                    }
146                break;
147
148                case MESSAGE_PUBLISH_STATE_CHANGED:
149                    if (intent != null) {
150                        if (RcsPresence.ACTION_PUBLISH_STATE_CHANGED.equals(intent.getAction())) {
151                            int publishState = intent.getIntExtra(RcsPresence.EXTRA_PUBLISH_STATE,
152                                    RcsPresence.PublishState.PUBLISH_STATE_200_OK);
153                            handlePublishState(publishState);
154                        } else {
155                            logger.debug("I don't care about intent: " + intent);
156                        }
157                    }
158                break;
159
160                default:
161                    logger.debug("unknown message:" + msg);
162            }
163        }
164    }
165
166    private void handlePublishState(int publishState) {
167        if(publishState == RcsPresence.PublishState.PUBLISH_STATE_VOLTE_PROVISION_ERROR) {
168            mVltProvisionErrorCount += 1;
169            if(mVltProvisionErrorCount >= 3){
170                if(mEABContactManager != null) {
171                    mEABContactManager.updateAllCapabilityToUnknown();
172                    logger.print("updateAllCapabilityToUnknown for publish 403 error");
173                    Intent intent = new Intent(RcsPresence.ACTION_PRESENCE_CHANGED);
174                    sendBroadcast(intent);
175                } else {
176                    logger.error("mEABContactManager is null");
177                }
178            }
179        } else if(publishState == RcsPresence.PublishState.PUBLISH_STATE_RCS_PROVISION_ERROR){
180            mVltProvisionErrorCount = 0;
181            if(mEABContactManager != null) {
182                mEABContactManager.updateAllVtCapabilityToUnknown();
183                logger.print("updateAllVtCapabilityToUnknown for publish 404 error");
184                Intent intent = new Intent(RcsPresence.ACTION_PRESENCE_CHANGED);
185                sendBroadcast(intent);
186            } else {
187                logger.error("mEABContactManager is null");
188            }
189        } else {
190            mVltProvisionErrorCount = 0;
191        }
192    }
193
194    private void handlePresence(Intent intent) {
195        if(intent == null) {
196            return;
197        }
198
199        // save the presence information.
200        ArrayList<RcsPresenceInfo> rcsPresenceInfoList = intent.getParcelableArrayListExtra(
201                RcsPresence.EXTRA_PRESENCE_INFO_LIST);
202        boolean updateLastTimestamp = intent.getBooleanExtra("updateLastTimestamp", true);
203        logger.print("updateLastTimestamp=" + updateLastTimestamp +
204                " RcsPresenceInfoList=" + rcsPresenceInfoList);
205        for(int i=0; i< rcsPresenceInfoList.size(); i++){
206            RcsPresenceInfo rcsPresenceInfoTmp = rcsPresenceInfoList.get(i);
207            if((rcsPresenceInfoTmp != null) && !TextUtils.isEmpty(
208                    rcsPresenceInfoTmp.getContactNumber())){
209                mEABContactManager.update(rcsPresenceInfoTmp, updateLastTimestamp);
210            }
211        }
212    }
213}
214
215
216