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

Commit 32dccbc2 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Watch for profile changes and push to user manager

If the contacts Me Profile changes, push a copy of the photo to
user manager for user by the user switcher.

Also use an async task to load the profile data.

Change-Id: Ie784114622038ff14e3feb70f2ff51c372eecb3f
parent b6d7c9c6
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@
    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
    <uses-permission android:name="android.permission.COPY_PROTECTED_DATA" />
    <uses-permission android:name="android.permission.MANAGE_USERS" />
    <uses-permission android:name="android.permission.READ_PROFILE" />

    <application android:label="@string/settings_label"
            android:icon="@mipmap/ic_launcher_settings"
@@ -1489,5 +1490,12 @@
            </intent-filter>
        </receiver>

        <!-- Watch for ContactsContract.Profile changes and update the user's photo.  -->
        <receiver android:name=".users.ProfileUpdateReceiver">
            <intent-filter>
                <action android:name="android.provider.Contacts.PROFILE_CHANGED" />
            </intent-filter>
        </receiver>

    </application>
</manifest>
+82 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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.
 */

package com.android.settings.users;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Profile;
import android.util.Log;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Watches for changes to Me Profile in Contacts and writes the photo to the User Manager.
 */
public class ProfileUpdateReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, Intent intent) {
        // Profile changed, lets get the photo and write to user manager
        new Thread() {
            public void run() {
                copyProfilePhoto(context, null);
            }
        }.start();
    }

    /* Used by UserSettings as well. Call this on a non-ui thread. */
    static boolean copyProfilePhoto(Context context, UserInfo user) {
        Uri contactUri = Profile.CONTENT_URI;

        InputStream avatarDataStream = Contacts.openContactPhotoInputStream(
                    context.getContentResolver(),
                    contactUri, true);
        // If there's no profile photo, assign a default avatar
        if (avatarDataStream == null) {
            return false;
        }
        int userId = user != null ? user.id : UserHandle.myUserId();
        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
        ParcelFileDescriptor fd = um.setUserIcon(userId);
        FileOutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
        byte[] buffer = new byte[4096];
        int readSize;
        try {
            while ((readSize = avatarDataStream.read(buffer)) > 0) {
                os.write(buffer, 0, readSize);
            }
            return true;
        } catch (IOException ioe) {
            Log.e("copyProfilePhoto", "Error copying profile photo " + ioe);
        } finally {
            try {
                os.close();
                avatarDataStream.close();
            } catch (IOException ioe) { }
        }
        return false;
    }
}
+36 −53
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -98,10 +99,10 @@ public class UserSettings extends SettingsPreferenceFragment
    private EditTextPreference mNicknamePreference;
    private int mRemovingUserId = -1;
    private boolean mAddingUser;
    private boolean mProfileExists;

    private final Object mUserLock = new Object();
    private UserManager mUserManager;
    private boolean mProfileChanged;

    private Handler mHandler = new Handler() {
        @Override
@@ -114,13 +115,6 @@ public class UserSettings extends SettingsPreferenceFragment
        }
    };

    private ContentObserver mProfileObserver = new ContentObserver(mHandler) {
        @Override
        public void onChange(boolean selfChange) {
            mProfileChanged = true;
        }
    };

    private BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {

        @Override
@@ -143,11 +137,8 @@ public class UserSettings extends SettingsPreferenceFragment
        mNicknamePreference = (EditTextPreference) findPreference(KEY_USER_NICKNAME);
        mNicknamePreference.setOnPreferenceChangeListener(this);
        mNicknamePreference.setSummary(mUserManager.getUserInfo(UserHandle.myUserId()).name);
        loadProfile(false);
        loadProfile();
        setHasOptionsMenu(true);
        // Register to watch for profile changes
        getActivity().getContentResolver().registerContentObserver(
                ContactsContract.Profile.CONTENT_URI, false, mProfileObserver);
        getActivity().registerReceiver(mUserChangeReceiver,
                new IntentFilter(Intent.ACTION_USER_REMOVED));
    }
@@ -155,17 +146,13 @@ public class UserSettings extends SettingsPreferenceFragment
    @Override
    public void onResume() {
        super.onResume();
        if (mProfileChanged) {
            loadProfile(true);
            mProfileChanged = false;
        }
        loadProfile();
        updateUserList();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        getActivity().getContentResolver().unregisterContentObserver(mProfileObserver);
        getActivity().unregisterReceiver(mUserChangeReceiver);
    }

@@ -198,13 +185,29 @@ public class UserSettings extends SettingsPreferenceFragment
        }
    }

    private void loadProfile(boolean force) {
    private void loadProfile() {
        mProfileExists = false;
        new AsyncTask<Void, Void, String>() {
            @Override
            protected void onPostExecute(String result) {
                finishLoadProfile(result);
            }

            @Override
            protected String doInBackground(Void... values) {
                UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId());
        if (force || user.iconPath == null || user.iconPath.equals("")) {
                if (user.iconPath == null || user.iconPath.equals("")) {
                    assignProfilePhoto(user);
                }
                String profileName = getProfileName();
                return profileName;
            }
        }.execute();
    }

    private void finishLoadProfile(String profileName) {
        mMePreference.setTitle(profileName);
        setPhotoId(mMePreference, mUserManager.getUserInfo(UserHandle.myUserId()));
    }

    private void onAddUserClicked() {
@@ -343,37 +346,10 @@ public class UserSettings extends SettingsPreferenceFragment
        getActivity().invalidateOptionsMenu();
    }

    /* TODO: Put this in an AsyncTask */
    private void assignProfilePhoto(final UserInfo user) {
        // If the contact is "me", then use my local profile photo. Otherwise, build a
        // uri to get the avatar of the contact.
        Uri contactUri = Profile.CONTENT_URI;

        InputStream avatarDataStream = Contacts.openContactPhotoInputStream(
                    getActivity().getContentResolver(),
                    contactUri, true);
        // If there's no profile photo, assign a default avatar
        if (avatarDataStream == null) {
        if (!ProfileUpdateReceiver.copyProfilePhoto(getActivity(), user)) {
            assignDefaultPhoto(user);
            setPhotoId(mMePreference, user);
            return;
        }

        ParcelFileDescriptor fd = mUserManager.setUserIcon(user.id);
        FileOutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
        byte[] buffer = new byte[4096];
        int readSize;
        try {
            while ((readSize = avatarDataStream.read(buffer)) > 0) {
                os.write(buffer, 0, readSize);
        }
            os.close();
            avatarDataStream.close();
        } catch (IOException ioe) {
            Log.e(TAG, "Error copying profile photo " + ioe);
        }

        setPhotoId(mMePreference, user);
    }

    private String getProfileName() {
@@ -387,6 +363,7 @@ public class UserSettings extends SettingsPreferenceFragment

        try {
            if (cursor.moveToFirst()) {
                mProfileExists = true;
                return cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
            }
        } finally {
@@ -421,8 +398,14 @@ public class UserSettings extends SettingsPreferenceFragment
    @Override
    public boolean onPreferenceClick(Preference pref) {
        if (pref == mMePreference) {
            Intent editProfile = new Intent(Intent.ACTION_EDIT);
            editProfile.setData(ContactsContract.Profile.CONTENT_URI);
            Intent editProfile;
            if (!mProfileExists) {
                editProfile = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
                // TODO: Make this a proper API
                editProfile.putExtra("newLocalProfile", true);
            } else {
                editProfile = new Intent(Intent.ACTION_EDIT, ContactsContract.Profile.CONTENT_URI);
            }
            // To make sure that it returns back here when done
            // TODO: Make this a proper API
            editProfile.putExtra("finishActivityOnSaveCompleted", true);