• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.incallui.spam;
18 
19 import android.app.Service;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.IBinder;
23 import android.provider.CallLog;
24 import android.support.annotation.Nullable;
25 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
26 import com.android.dialer.common.LogUtil;
27 import com.android.dialer.location.GeoUtil;
28 import com.android.dialer.logging.ContactLookupResult;
29 import com.android.dialer.logging.DialerImpression;
30 import com.android.dialer.logging.Logger;
31 import com.android.dialer.logging.ReportingLocation;
32 import com.android.dialer.notification.DialerNotificationManager;
33 import com.android.dialer.spam.SpamComponent;
34 import com.android.incallui.call.DialerCall;
35 
36 /**
37  * This service determines if the device is locked/unlocked and takes an action based on the state.
38  * A service is used to to determine this, as opposed to an activity, because the user must unlock
39  * the device before a notification can start an activity. This is not the case for a service, and
40  * intents can be sent to this service even from the lock screen. This allows users to quickly
41  * report a number as spam or not spam from their lock screen.
42  */
43 public class SpamNotificationService extends Service {
44 
45   private static final String TAG = "SpamNotificationSvc";
46 
47   private static final String EXTRA_PHONE_NUMBER = "service_phone_number";
48   private static final String EXTRA_CALL_ID = "service_call_id";
49   private static final String EXTRA_CALL_START_TIME_MILLIS = "service_call_start_time_millis";
50   private static final String EXTRA_NOTIFICATION_TAG = "service_notification_tag";
51   private static final String EXTRA_NOTIFICATION_ID = "service_notification_id";
52   private static final String EXTRA_CONTACT_LOOKUP_RESULT_TYPE =
53       "service_contact_lookup_result_type";
54   /** Creates an intent to start this service. */
createServiceIntent( Context context, DialerCall call, String action, String notificationTag, int notificationId)55   public static Intent createServiceIntent(
56       Context context, DialerCall call, String action, String notificationTag, int notificationId) {
57     Intent intent = new Intent(context, SpamNotificationService.class);
58     intent.setAction(action);
59     intent.putExtra(EXTRA_PHONE_NUMBER, call.getNumber());
60     intent.putExtra(EXTRA_CALL_ID, call.getUniqueCallId());
61     intent.putExtra(EXTRA_CALL_START_TIME_MILLIS, call.getTimeAddedMs());
62     intent.putExtra(EXTRA_NOTIFICATION_TAG, notificationTag);
63     intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId);
64     intent.putExtra(
65         EXTRA_CONTACT_LOOKUP_RESULT_TYPE, call.getLogState().contactLookupResult.getNumber());
66     return intent;
67   }
68 
69   @Nullable
70   @Override
onBind(Intent intent)71   public IBinder onBind(Intent intent) {
72     // Return null because clients cannot bind to this service
73     return null;
74   }
75 
76   @Override
onStartCommand(Intent intent, int flags, int startId)77   public int onStartCommand(Intent intent, int flags, int startId) {
78     LogUtil.d(TAG, "onStartCommand");
79     if (intent == null) {
80       LogUtil.d(TAG, "Null intent");
81       stopSelf();
82       // Return {@link #START_NOT_STICKY} so service is not restarted.
83       return START_NOT_STICKY;
84     }
85     String number = intent.getStringExtra(EXTRA_PHONE_NUMBER);
86     String notificationTag = intent.getStringExtra(EXTRA_NOTIFICATION_TAG);
87     int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, 1);
88     String countryIso = GeoUtil.getCurrentCountryIso(this);
89     ContactLookupResult.Type contactLookupResultType =
90         ContactLookupResult.Type.forNumber(intent.getIntExtra(EXTRA_CONTACT_LOOKUP_RESULT_TYPE, 0));
91 
92     DialerNotificationManager.cancel(this, notificationTag, notificationId);
93 
94     switch (intent.getAction()) {
95       case SpamNotificationActivity.ACTION_MARK_NUMBER_AS_SPAM:
96         logCallImpression(
97             intent, DialerImpression.Type.SPAM_NOTIFICATION_SERVICE_ACTION_MARK_NUMBER_AS_SPAM);
98         SpamComponent.get(this)
99             .spam()
100             .reportSpamFromAfterCallNotification(
101                 number,
102                 countryIso,
103                 CallLog.Calls.INCOMING_TYPE,
104                 ReportingLocation.Type.FEEDBACK_PROMPT,
105                 contactLookupResultType);
106         new FilteredNumberAsyncQueryHandler(this).blockNumber(null, number, countryIso);
107         break;
108       case SpamNotificationActivity.ACTION_MARK_NUMBER_AS_NOT_SPAM:
109         logCallImpression(
110             intent, DialerImpression.Type.SPAM_NOTIFICATION_SERVICE_ACTION_MARK_NUMBER_AS_NOT_SPAM);
111         SpamComponent.get(this)
112             .spam()
113             .reportNotSpamFromAfterCallNotification(
114                 number,
115                 countryIso,
116                 CallLog.Calls.INCOMING_TYPE,
117                 ReportingLocation.Type.FEEDBACK_PROMPT,
118                 contactLookupResultType);
119         break;
120       default: // fall out
121     }
122     // TODO: call stopSelf() after async tasks complete (a bug)
123     stopSelf();
124     return START_NOT_STICKY;
125   }
126 
127   @Override
onDestroy()128   public void onDestroy() {
129     super.onDestroy();
130     LogUtil.d(TAG, "onDestroy");
131   }
132 
logCallImpression(Intent intent, DialerImpression.Type impression)133   private void logCallImpression(Intent intent, DialerImpression.Type impression) {
134     Logger.get(this)
135         .logCallImpression(
136             impression,
137             intent.getStringExtra(EXTRA_CALL_ID),
138             intent.getLongExtra(EXTRA_CALL_START_TIME_MILLIS, 0));
139   }
140 }
141