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

Commit 740da475 authored by Adam Powell's avatar Adam Powell
Browse files

Don't register more receivers and observers for every DateTimeView

SystemUI uses several of these per notification, so be a little more
conservative and track individual views to update per process instead.

Bug 16902706

Change-Id: Ib77a8e7727d027cae39d5e6f431cac1d1ff8a121
parent f3a1007a
Loading
Loading
Loading
Loading
+85 −41
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.widget.RemoteViews.RemoteView;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

//
@@ -62,8 +63,8 @@ public class DateTimeView extends TextView {
    int mLastDisplay = -1;
    DateFormat mLastFormat;

    private boolean mAttachedToWindow;
    private long mUpdateTimeMillis;
    private static final ThreadLocal<ReceiverInfo> sReceiverInfo = new ThreadLocal<ReceiverInfo>();

    public DateTimeView(Context context) {
        super(context);
@@ -76,15 +77,21 @@ public class DateTimeView extends TextView {
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        registerReceivers();
        mAttachedToWindow = true;
        ReceiverInfo ri = sReceiverInfo.get();
        if (ri == null) {
            ri = new ReceiverInfo();
            sReceiverInfo.set(ri);
        }
        ri.addView(this);
    }
        
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        unregisterReceivers();
        mAttachedToWindow = false;
        final ReceiverInfo ri = sReceiverInfo.get();
        if (ri != null) {
            ri.removeView(this);
        }
    }

    @android.view.RemotableViewMethod
@@ -204,32 +211,19 @@ public class DateTimeView extends TextView {
        }
    }

    private void registerReceivers() {
        Context context = getContext();

        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_TIME_TICK);
        filter.addAction(Intent.ACTION_TIME_CHANGED);
        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
        context.registerReceiver(mBroadcastReceiver, filter);

        Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT);
        context.getContentResolver().registerContentObserver(uri, true, mContentObserver);
    }

    private void unregisterReceivers() {
        Context context = getContext();
        context.unregisterReceiver(mBroadcastReceiver);
        context.getContentResolver().unregisterContentObserver(mContentObserver);
    void clearFormatAndUpdate() {
        mLastFormat = null;
        update();
    }

    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    private static class ReceiverInfo {
        private final ArrayList<DateTimeView> mAttachedViews = new ArrayList<DateTimeView>();
        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (Intent.ACTION_TIME_TICK.equals(action)) {
                if (System.currentTimeMillis() < mUpdateTimeMillis) {
                    if (System.currentTimeMillis() < getSoonestUpdateTime()) {
                        // The update() function takes a few milliseconds to run because of
                        // all of the time conversions it needs to do, so we can't do that
                        // every minute.
@@ -237,16 +231,66 @@ public class DateTimeView extends TextView {
                    }
                }
                // ACTION_TIME_CHANGED can also signal a change of 12/24 hr. format.
            mLastFormat = null;
            update();
                updateAll();
            }
        };

    private ContentObserver mContentObserver = new ContentObserver(new Handler()) {
        private final ContentObserver mObserver = new ContentObserver(new Handler()) {
            @Override
            public void onChange(boolean selfChange) {
            mLastFormat = null;
            update();
                updateAll();
            }
        };

        public void addView(DateTimeView v) {
            final boolean register = mAttachedViews.isEmpty();
            mAttachedViews.add(v);
            if (register) {
                register(v.getContext().getApplicationContext());
            }
        }

        public void removeView(DateTimeView v) {
            mAttachedViews.remove(v);
            if (mAttachedViews.isEmpty()) {
                unregister(v.getContext().getApplicationContext());
            }
        }

        void updateAll() {
            final int count = mAttachedViews.size();
            for (int i = 0; i < count; i++) {
                mAttachedViews.get(i).clearFormatAndUpdate();
            }
        }

        long getSoonestUpdateTime() {
            long result = Long.MAX_VALUE;
            final int count = mAttachedViews.size();
            for (int i = 0; i < count; i++) {
                final long time = mAttachedViews.get(i).mUpdateTimeMillis;
                if (time < result) {
                    result = time;
                }
            }
            return result;
        }

        void register(Context context) {
            final IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_TIME_TICK);
            filter.addAction(Intent.ACTION_TIME_CHANGED);
            filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
            context.registerReceiver(mReceiver, filter);

            final Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT);
            context.getContentResolver().registerContentObserver(uri, true, mObserver);
        }

        void unregister(Context context) {
            context.unregisterReceiver(mReceiver);
            context.getContentResolver().unregisterContentObserver(mObserver);
        }
    }
}