Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e767f44 authored by Xiao-Long Chen's avatar Xiao-Long Chen Committed by Danny Baumann
Browse files

Re-add dialer lookup.



Author: Xiao-Long Chen <chenxiaolong@cxl.epac.to>
Date:   Mon Sep 12 09:34:02 2016 +0200

    Re-add dialer lookup.

    BUGBASH-612: do not send phone numbers to non-ssl sites for reverse/forward/people lookups

    Change-Id: I677460ad5767b8698ee24d6d43ff159aee55387a

Author: Joey <joey@lineageos.org>
Date:   Wed Mar 28 21:11:16 2018 +0200

    Dialer: comply with EU's GDPR

    Disable lookup by default and add a disclaimer for the feature

    Change-Id: If7a181952304dbaee736762bdfd5819eddc5f89b
    Signed-off-by: default avatarJoey <joey@lineageos.org>

Change-Id: I4ff90a678618fa8c7b5970dff3dd246b0c87135c
parent c436a5b5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
	libbackup \
	libphonenumber \
	volley \
	org.lineageos.platform.internal

LOCAL_STATIC_ANDROID_LIBRARIES := \
	android-support-core-ui \
+6 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import com.android.dialer.blocking.FilteredNumberCompat;
import com.android.dialer.common.LogUtil;
import com.android.dialer.compat.telephony.TelephonyManagerCompat;
import com.android.dialer.configprovider.ConfigProviderComponent;
import com.android.dialer.lookup.LookupSettingsFragment;
import com.android.dialer.proguard.UsedByReflection;
import com.android.dialer.util.PermissionsUtil;
import com.android.dialer.voicemail.settings.VoicemailSettingsFragment;
@@ -113,6 +114,11 @@ public class DialerSettingsActivity extends AppCompatPreferenceActivity {
    quickResponseSettingsHeader.intent = quickResponseSettingsIntent;
    target.add(quickResponseSettingsHeader);

    final Header lookupSettingsHeader = new Header();
    lookupSettingsHeader.titleRes = R.string.lookup_settings_label;
    lookupSettingsHeader.fragment = LookupSettingsFragment.class.getName();
    target.add(lookupSettingsHeader);

    TelephonyManager telephonyManager =
        (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

+59 −1
Original line number Diff line number Diff line
@@ -16,15 +16,34 @@

package com.android.dialer.binary.aosp;

import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.android.contacts.common.extensions.PhoneDirectoryExtender;
import com.android.contacts.common.extensions.PhoneDirectoryExtenderFactory;
import com.android.dialer.binary.common.DialerApplication;
import com.android.dialer.inject.ContextModule;
import com.android.dialer.lookup.LookupCacheService;
import com.android.dialer.lookup.LookupProvider;
import com.android.dialer.lookup.LookupSettings;
import com.android.dialer.lookup.ReverseLookupService;
import com.android.dialer.phonenumbercache.CachedNumberLookupService;
import com.android.dialer.phonenumbercache.PhoneNumberCacheBindings;
import com.android.dialer.phonenumbercache.PhoneNumberCacheBindingsFactory;
import com.android.incallui.bindings.InCallUiBindings;
import com.android.incallui.bindings.InCallUiBindingsFactory;
import com.android.incallui.bindings.InCallUiBindingsStub;
import com.android.incallui.bindings.PhoneNumberService;

import java.util.List;

/**
 * The application class for the AOSP Dialer. This is a version of the Dialer app that has no
 * dependency on Google Play Services.
 */
public class AospDialerApplication extends DialerApplication {
public class AospDialerApplication extends DialerApplication implements
    PhoneNumberCacheBindingsFactory, PhoneDirectoryExtenderFactory, InCallUiBindingsFactory {

  /** Returns a new instance of the root component for the AOSP Dialer. */
  @Override
@@ -32,4 +51,43 @@ public class AospDialerApplication extends DialerApplication {
  protected Object buildRootComponent() {
    return DaggerAospDialerRootComponent.builder().contextModule(new ContextModule(this)).build();
  }

  @Override
  public PhoneDirectoryExtender newPhoneDirectoryExtender() {
    return new PhoneDirectoryExtender() {
      @Override
      public boolean isEnabled(Context context) {
        return LookupSettings.isForwardLookupEnabled(AospDialerApplication.this)
            || LookupSettings.isPeopleLookupEnabled(AospDialerApplication.this);
      }

      @Override
      @Nullable
      public Uri getContentUri() {
        return LookupProvider.NEARBY_AND_PEOPLE_LOOKUP_URI;
      }
    };
  }

  @Override
  public InCallUiBindings newInCallUiBindings() {
    return new InCallUiBindingsStub() {
      @Override
      @Nullable
      public PhoneNumberService newPhoneNumberService(Context context) {
        return new ReverseLookupService(context);
      }
    };
  }

  @Override
  public PhoneNumberCacheBindings newPhoneNumberCacheBindings() {
    return new PhoneNumberCacheBindings() {
      @Override
      @Nullable
      public CachedNumberLookupService getCachedNumberLookupService() {
        return new LookupCacheService();
      }
    };
  }
}
+31 −0
Original line number Diff line number Diff line
<!--
  ~ Copyright (C) 2017 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License
  -->

<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.android.dialer.lookup">

  <uses-sdk android:minSdkVersion="23"/>
  <uses-permission android:name="lineageos.permission.WRITE_SETTINGS"/>

  <application>
    <provider android:name="com.android.dialer.lookup.LookupProvider"
      android:authorities="com.android.dialer.lookup"
      android:exported="false"
      android:multiprocess="false" />

  </application>
</manifest>
+475 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 Xiao-Long Chen <chillermillerlong@hotmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.dialer.lookup;

import android.content.ContentResolver;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.DisplayNameSources;
import android.text.TextUtils;
import android.util.Log;

import com.android.contacts.common.util.Constants;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.R;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.w3c.dom.Text;

import java.sql.Struct;
import java.util.ArrayList;

public class ContactBuilder {
  private static final String TAG = ContactBuilder.class.getSimpleName();

  private static final boolean DEBUG = false;

  /** Default photo for businesses if no other image is found */
  public static final String PHOTO_URI_BUSINESS = new Uri.Builder()
      .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
      .authority("com.android.dialer")
      .appendPath(String.valueOf(R.drawable.ic_places_picture_180_holo_light))
      .build()
      .toString();

  private final ArrayList<Address> addresses = new ArrayList<>();
  private final ArrayList<PhoneNumber> phoneNumbers = new ArrayList<>();
  private final ArrayList<WebsiteUrl> websites = new ArrayList<>();

  private final long directoryId;
  private Name name;
  private final String normalizedNumber;
  private final String formattedNumber;
  private Uri photoUri;

  public static ContactBuilder forForwardLookup(String number) {
      return new ContactBuilder(DirectoryId.NEARBY, null, number);
  }

  public static ContactBuilder forPeopleLookup(String number) {
      return new ContactBuilder(DirectoryId.PEOPLE, null, number);
  }

  public static ContactBuilder forReverseLookup(String normalizedNumber, String formattedNumber) {
      return new ContactBuilder(DirectoryId.NULL, normalizedNumber, formattedNumber);
  }

  private ContactBuilder(long directoryId, String normalizedNumber, String formattedNumber) {
    this.directoryId = directoryId;
    this.normalizedNumber = normalizedNumber;
    this.formattedNumber = formattedNumber;
  }

  public ContactBuilder(Uri encodedContactUri) throws JSONException {
    String jsonData = encodedContactUri.getEncodedFragment();
    String directoryIdStr = encodedContactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
    long directoryId = DirectoryId.DEFAULT;

    if (!TextUtils.isEmpty(directoryIdStr)) {
      try {
        directoryId = Long.parseLong(directoryIdStr);
      } catch (NumberFormatException e) {
        Log.e(TAG, "Error parsing directory id of uri " + encodedContactUri, e);
      }
    }

    this.directoryId = directoryId;
    this.formattedNumber = null;
    this.normalizedNumber = null;

    try {
      // name
      JSONObject json = new JSONObject(jsonData);
      JSONObject contact = json.optJSONObject(Contacts.CONTENT_ITEM_TYPE);
      JSONObject nameObj = contact.optJSONObject(StructuredName.CONTENT_ITEM_TYPE);
      name = new Name(nameObj);

      if (contact != null) {
        // numbers
        if (contact.has(Phone.CONTENT_ITEM_TYPE)) {
          String phoneData = contact.getString(Phone.CONTENT_ITEM_TYPE);
          Object phoneObject = new JSONTokener(phoneData).nextValue();
          JSONArray phoneNumbersJson;
          if (phoneObject instanceof JSONObject) {
            phoneNumbersJson = new JSONArray();
            phoneNumbersJson.put(phoneObject);
          } else {
            phoneNumbersJson = contact.getJSONArray(Phone.CONTENT_ITEM_TYPE);
          }
          for (int i = 0; i < phoneNumbersJson.length(); ++i) {
            JSONObject phoneObj = phoneNumbersJson.getJSONObject(i);
            phoneNumbers.add(new PhoneNumber(phoneObj));
          }
        }

        // address
        if (contact.has(StructuredPostal.CONTENT_ITEM_TYPE)) {
          JSONArray addressesJson = contact.getJSONArray(StructuredPostal.CONTENT_ITEM_TYPE);
          for (int i = 0; i < addressesJson.length(); ++i) {
            JSONObject addrObj = addressesJson.getJSONObject(i);
            addresses.add(new Address(addrObj));
          }
        }

        // websites
        if (contact.has(Website.CONTENT_ITEM_TYPE)) {
          JSONArray websitesJson = contact.getJSONArray(Website.CONTENT_ITEM_TYPE);
          for (int i = 0; i < websitesJson.length(); ++i) {
            JSONObject websiteObj = websitesJson.getJSONObject(i);
            final WebsiteUrl websiteUrl = new WebsiteUrl(websiteObj);
            if (!TextUtils.isEmpty(websiteUrl.url)) {
              websites.add(new WebsiteUrl(websiteObj));
            }
          }
        }
      }
    } catch(JSONException e) {
      Log.e(TAG, "Error parsing encoded fragment of uri " + encodedContactUri, e);
      throw e;
    }
  }

  public ContactBuilder addAddress(Address address) {
    if (DEBUG) Log.d(TAG, "Adding address");
    if (address != null) {
      addresses.add(address);
    }
    return this;
  }

  public ContactBuilder addPhoneNumber(PhoneNumber phoneNumber) {
    if (DEBUG) Log.d(TAG, "Adding phone number");
    if (phoneNumber != null) {
      phoneNumbers.add(phoneNumber);
    }
    return this;
  }

  public ContactBuilder addWebsite(WebsiteUrl website) {
    if (DEBUG) Log.d(TAG, "Adding website");
    if (website != null) {
      websites.add(website);
    }
    return this;
  }

  public ContactBuilder setName(Name name) {
    if (DEBUG) Log.d(TAG, "Setting name");
    if (name != null) {
      this.name = name;
    }
    return this;
  }

  public ContactBuilder setPhotoUri(String photoUri) {
    if (photoUri != null) {
      setPhotoUri(Uri.parse(photoUri));
    }
    return this;
  }

  public ContactBuilder setPhotoUri(Uri photoUri) {
    if (DEBUG) Log.d(TAG, "Setting photo URI");
    this.photoUri = photoUri;
    return this;
  }

  public ContactInfo build() {
    if (name == null) {
      throw new IllegalStateException("Name has not been set");
    }

    // Use the incoming call's phone number if no other phone number
    // is specified. The reverse lookup source could present the phone
    // number differently (eg. without the area code).
    if (phoneNumbers.isEmpty()) {
      PhoneNumber pn = new PhoneNumber();
      // Use the formatted number where possible
      pn.number = formattedNumber != null
              ? formattedNumber : normalizedNumber;
      pn.type = Phone.TYPE_MAIN;
      addPhoneNumber(pn);
    }

    try {
      JSONObject contact = new JSONObject();

      // Insert the name
      contact.put(StructuredName.CONTENT_ITEM_TYPE, name.getJsonObject());

      // Insert phone numbers
      JSONArray phoneNumbersJson = new JSONArray();
      for (PhoneNumber number : phoneNumbers) {
        phoneNumbersJson.put(number.getJsonObject());
      }
      contact.put(Phone.CONTENT_ITEM_TYPE, phoneNumbersJson);

      // Insert addresses if there are any
      if (!addresses.isEmpty()) {
        JSONArray addressesJson = new JSONArray();
        for (Address address : addresses) {
          addressesJson.put(address.getJsonObject());
        }
        contact.put(StructuredPostal.CONTENT_ITEM_TYPE, addressesJson);
      }

      // Insert websites if there are any
      if (!websites.isEmpty()) {
        JSONArray websitesJson = new JSONArray();
        for (WebsiteUrl site : websites) {
          websitesJson.put(site.getJsonObject());
        }
        contact.put(Website.CONTENT_ITEM_TYPE, websitesJson);
      }

      ContactInfo info = new ContactInfo();
      info.name = name.displayName;
      info.normalizedNumber = normalizedNumber;
      info.number = phoneNumbers.get(0).number;
      info.type = phoneNumbers.get(0).type;
      info.label = phoneNumbers.get(0).label;
      info.photoUri = photoUri;

      String json = new JSONObject()
          .put(Contacts.DISPLAY_NAME, name.displayName)
          .put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.ORGANIZATION)
          .put(Directory.EXPORT_SUPPORT, Directory.EXPORT_SUPPORT_ANY_ACCOUNT)
          .put(Contacts.CONTENT_ITEM_TYPE, contact)
          .toString();

      if (json != null) {
        info.lookupUri = Contacts.CONTENT_LOOKUP_URI
            .buildUpon()
            .appendPath(Constants.LOOKUP_URI_ENCODED)
            .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
                String.valueOf(directoryId))
            .encodedFragment(json)
            .build();
      }

      return info;
    } catch (JSONException e) {
      Log.e(TAG, "Failed to build contact", e);
      return null;
    }
  }

  // android.provider.ContactsContract.CommonDataKinds.StructuredPostal
  public static class Address {
    public String formattedAddress;
    public int type;
    public String label;
    public String street;
    public String poBox;
    public String neighborhood;
    public String city;
    public String region;
    public String postCode;
    public String country;

    public static Address createFormattedHome(String address) {
      if (address == null) {
        return null;
      }
      Address a = new Address();
      a.formattedAddress = address;
      a.type = StructuredPostal.TYPE_HOME;
      return a;
    }

    public JSONObject getJsonObject() throws JSONException {
      JSONObject json = new JSONObject();
      json.putOpt(StructuredPostal.FORMATTED_ADDRESS, formattedAddress);
      json.put(StructuredPostal.TYPE, type);
      json.putOpt(StructuredPostal.LABEL, label);
      json.putOpt(StructuredPostal.STREET, street);
      json.putOpt(StructuredPostal.POBOX, poBox);
      json.putOpt(StructuredPostal.NEIGHBORHOOD, neighborhood);
      json.putOpt(StructuredPostal.CITY, city);
      json.putOpt(StructuredPostal.REGION, region);
      json.putOpt(StructuredPostal.POSTCODE, postCode);
      json.putOpt(StructuredPostal.COUNTRY, country);
      return json;
    }

    public Address() {}

    public Address(JSONObject json) throws JSONException {
      if (json.has(StructuredPostal.FORMATTED_ADDRESS)) {
        formattedAddress = json.getString(StructuredPostal.FORMATTED_ADDRESS);
      }
    }

    public String toString() {
      return "formattedAddress: " + formattedAddress + "; " +
          "type: " + type + "; " +
          "label: " + label + "; " +
          "street: " + street + "; " +
          "poBox: " + poBox + "; " +
          "neighborhood: " + neighborhood + "; " +
          "city: " + city + "; " +
          "region: " + region + "; " +
          "postCode: " + postCode + "; " +
          "country: " + country;
    }
  }

  // android.provider.ContactsContract.CommonDataKinds.StructuredName
  public static class Name {
    public String displayName;
    public String givenName;
    public String familyName;
    public String prefix;
    public String middleName;
    public String suffix;
    public String phoneticGivenName;
    public String phoneticMiddleName;
    public String phoneticFamilyName;

    public static Name createDisplayName(String displayName) {
      Name name = new Name();
      name.displayName = displayName;
      return name;
    }

    public JSONObject getJsonObject() throws JSONException {
      JSONObject json = new JSONObject();
      json.putOpt(StructuredName.DISPLAY_NAME, displayName);
      json.putOpt(StructuredName.GIVEN_NAME, givenName);
      json.putOpt(StructuredName.FAMILY_NAME, familyName);
      json.putOpt(StructuredName.PREFIX, prefix);
      json.putOpt(StructuredName.MIDDLE_NAME, middleName);
      json.putOpt(StructuredName.SUFFIX, suffix);
      json.putOpt(StructuredName.PHONETIC_GIVEN_NAME, phoneticGivenName);
      json.putOpt(StructuredName.PHONETIC_MIDDLE_NAME, phoneticMiddleName);
      json.putOpt(StructuredName.PHONETIC_FAMILY_NAME, phoneticFamilyName);
      return json;
    }

    public Name(JSONObject json) throws JSONException {
      if (json != null) {
        displayName = json.optString(StructuredName.DISPLAY_NAME, null);
      }
    }

    public Name() {}

    public String toString() {
      return "displayName: " + displayName + "; " +
          "givenName: " + givenName + "; " +
          "familyName: " + familyName + "; " +
          "prefix: " + prefix + "; " +
          "middleName: " + middleName + "; " +
          "suffix: " + suffix + "; " +
          "phoneticGivenName: " + phoneticGivenName + "; " +
          "phoneticMiddleName: " + phoneticMiddleName + "; " +
          "phoneticFamilyName: " + phoneticFamilyName;
    }
  }

  // android.provider.ContactsContract.CommonDataKinds.Phone
  public static class PhoneNumber {
    public String number;
    public int type;
    public String label;

    public static PhoneNumber createMainNumber(String number) {
      PhoneNumber n = new PhoneNumber();
      n.number = number;
      n.type = Phone.TYPE_MAIN;
      return n;
    }

    public JSONObject getJsonObject() throws JSONException {
      JSONObject json = new JSONObject();
      json.put(Phone.NUMBER, number);
      json.put(Phone.TYPE, type);
      json.putOpt(Phone.LABEL, label);
      return json;
    }

    public PhoneNumber(JSONObject json) throws JSONException {
      number = json.getString(Phone.NUMBER);
      type = json.getInt(Phone.TYPE);
      if (json.has(Phone.LABEL)) {
        label = json.getString(Phone.LABEL);
      }
    }

    public PhoneNumber() {}

    public String toString() {
      return "number: " + number + "; " +
          "type: " + type + "; " +
          "label: " + label;
    }
  }

  // android.provider.ContactsContract.CommonDataKinds.Website
  public static class WebsiteUrl {
    public String url;
    public int type;
    public String label;

    public static WebsiteUrl createProfile(String url) {
      if (url == null) {
        return null;
      }
      WebsiteUrl u = new WebsiteUrl();
      u.url = url;
      u.type = Website.TYPE_PROFILE;
      return u;
    }

    public JSONObject getJsonObject() throws JSONException {
      JSONObject json = new JSONObject();
      json.put(Website.URL, url);
      json.put(Website.TYPE, type);
      json.putOpt(Website.LABEL, label);
      return json;
    }

    public WebsiteUrl() {}

    public WebsiteUrl(JSONObject json) throws JSONException {
      if (json.has(Website.URL)) {
        url = json.getString(Website.URL);
      }
      if (json.has(Website.TYPE)) {
        type = json.getInt(Website.TYPE);
      }
      if (json.has(Website.LABEL)) {
        label = json.getString(Website.LABEL);
      }
    }

    public String toString() {
      return "url: " + url + "; " +
          "type: " + type + "; " +
          "label: " + label;
    }
  }
}
Loading