Home | History | Annotate | Download | only in spam
      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.NotificationManager;
     20 import android.app.Service;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.os.IBinder;
     24 import android.provider.CallLog;
     25 import android.support.annotation.Nullable;
     26 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler;
     27 import com.android.dialer.common.LogUtil;
     28 import com.android.dialer.location.GeoUtil;
     29 import com.android.dialer.logging.ContactLookupResult;
     30 import com.android.dialer.logging.DialerImpression;
     31 import com.android.dialer.logging.Logger;
     32 import com.android.dialer.logging.ReportingLocation;
     33 import com.android.dialer.spam.Spam;
     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_ID = "service_notification_id";
     51   private static final String EXTRA_CONTACT_LOOKUP_RESULT_TYPE =
     52       "service_contact_lookup_result_type";
     53   /** Creates an intent to start this service. */
     54   public static Intent createServiceIntent(
     55       Context context, DialerCall call, String action, int notificationId) {
     56     Intent intent = new Intent(context, SpamNotificationService.class);
     57     intent.setAction(action);
     58     intent.putExtra(EXTRA_PHONE_NUMBER, call.getNumber());
     59     intent.putExtra(EXTRA_CALL_ID, call.getUniqueCallId());
     60     intent.putExtra(EXTRA_CALL_START_TIME_MILLIS, call.getTimeAddedMs());
     61     intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId);
     62     intent.putExtra(EXTRA_CONTACT_LOOKUP_RESULT_TYPE, call.getLogState().contactLookupResult);
     63     return intent;
     64   }
     65 
     66   @Nullable
     67   @Override
     68   public IBinder onBind(Intent intent) {
     69     // Return null because clients cannot bind to this service
     70     return null;
     71   }
     72 
     73   @Override
     74   public int onStartCommand(Intent intent, int flags, int startId) {
     75     LogUtil.d(TAG, "onStartCommand");
     76     if (intent == null) {
     77       LogUtil.d(TAG, "Null intent");
     78       stopSelf();
     79       // Return {@link #START_NOT_STICKY} so service is not restarted.
     80       return START_NOT_STICKY;
     81     }
     82     String number = intent.getStringExtra(EXTRA_PHONE_NUMBER);
     83     int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, 1);
     84     String countryIso = GeoUtil.getCurrentCountryIso(this);
     85     ContactLookupResult.Type contactLookupResultType =
     86         ContactLookupResult.Type.forNumber(intent.getIntExtra(EXTRA_CONTACT_LOOKUP_RESULT_TYPE, 0));
     87 
     88     ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE))
     89         .cancel(number, notificationId);
     90 
     91     switch (intent.getAction()) {
     92       case SpamNotificationActivity.ACTION_MARK_NUMBER_AS_SPAM:
     93         logCallImpression(
     94             intent, DialerImpression.Type.SPAM_NOTIFICATION_SERVICE_ACTION_MARK_NUMBER_AS_SPAM);
     95         Spam.get(this)
     96             .reportSpamFromAfterCallNotification(
     97                 number,
     98                 countryIso,
     99                 CallLog.Calls.INCOMING_TYPE,
    100                 ReportingLocation.Type.FEEDBACK_PROMPT,
    101                 contactLookupResultType);
    102         new FilteredNumberAsyncQueryHandler(this).blockNumber(null, number, countryIso);
    103         break;
    104       case SpamNotificationActivity.ACTION_MARK_NUMBER_AS_NOT_SPAM:
    105         logCallImpression(
    106             intent, DialerImpression.Type.SPAM_NOTIFICATION_SERVICE_ACTION_MARK_NUMBER_AS_NOT_SPAM);
    107         Spam.get(this)
    108             .reportNotSpamFromAfterCallNotification(
    109                 number,
    110                 countryIso,
    111                 CallLog.Calls.INCOMING_TYPE,
    112                 ReportingLocation.Type.FEEDBACK_PROMPT,
    113                 contactLookupResultType);
    114         break;
    115       default: // fall out
    116     }
    117     // TODO: call stopSelf() after async tasks complete (b/28441936)
    118     stopSelf();
    119     return START_NOT_STICKY;
    120   }
    121 
    122   @Override
    123   public void onDestroy() {
    124     super.onDestroy();
    125     LogUtil.d(TAG, "onDestroy");
    126   }
    127 
    128   private void logCallImpression(Intent intent, DialerImpression.Type impression) {
    129     Logger.get(this)
    130         .logCallImpression(
    131             impression,
    132             intent.getStringExtra(EXTRA_CALL_ID),
    133             intent.getLongExtra(EXTRA_CALL_START_TIME_MILLIS, 0));
    134   }
    135 }
    136