1f715fd998b172c4e8658715a26a41c69144380beChris Wren/*
2f715fd998b172c4e8658715a26a41c69144380beChris Wren * Copyright (C) 2014 The Android Open Source Project
3f715fd998b172c4e8658715a26a41c69144380beChris Wren *
4f715fd998b172c4e8658715a26a41c69144380beChris Wren * Licensed under the Apache License, Version 2.0 (the "License");
5f715fd998b172c4e8658715a26a41c69144380beChris Wren * you may not use this file except in compliance with the License.
6f715fd998b172c4e8658715a26a41c69144380beChris Wren * You may obtain a copy of the License at
7f715fd998b172c4e8658715a26a41c69144380beChris Wren *
8f715fd998b172c4e8658715a26a41c69144380beChris Wren *      http://www.apache.org/licenses/LICENSE-2.0
9f715fd998b172c4e8658715a26a41c69144380beChris Wren *
10f715fd998b172c4e8658715a26a41c69144380beChris Wren * Unless required by applicable law or agreed to in writing, software
11f715fd998b172c4e8658715a26a41c69144380beChris Wren * distributed under the License is distributed on an "AS IS" BASIS,
12f715fd998b172c4e8658715a26a41c69144380beChris Wren * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f715fd998b172c4e8658715a26a41c69144380beChris Wren * See the License for the specific language governing permissions and
14f715fd998b172c4e8658715a26a41c69144380beChris Wren * limitations under the License.
15f715fd998b172c4e8658715a26a41c69144380beChris Wren */
16f715fd998b172c4e8658715a26a41c69144380beChris Wrenpackage com.android.example.notificationlistener;
17f715fd998b172c4e8658715a26a41c69144380beChris Wren
18f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.app.AlertDialog;
19f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.app.ListActivity;
20f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.content.BroadcastReceiver;
21f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.content.Context;
22f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.content.DialogInterface;
23f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.content.Intent;
24f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.content.IntentFilter;
25f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.os.Bundle;
26f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.provider.Settings.Secure;
27f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.service.notification.StatusBarNotification;
28f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.support.v4.content.LocalBroadcastManager;
29f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.util.Log;
30f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.view.View;
31f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.view.ViewGroup;
32f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.widget.BaseAdapter;
33f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.widget.Button;
34f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.widget.FrameLayout;
35f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport android.widget.TextView;
36f715fd998b172c4e8658715a26a41c69144380beChris Wren
37f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport java.util.HashMap;
38f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport java.util.HashSet;
39f715fd998b172c4e8658715a26a41c69144380beChris Wrenimport java.util.List;
40f715fd998b172c4e8658715a26a41c69144380beChris Wren
41f715fd998b172c4e8658715a26a41c69144380beChris Wrenpublic class NotificationListenerActivity extends ListActivity {
42f715fd998b172c4e8658715a26a41c69144380beChris Wren    private static final String LISTENER_PATH = "com.android.example.notificationlistener/" +
43f715fd998b172c4e8658715a26a41c69144380beChris Wren            "com.android.example.notificationlistener.Listener";
44f715fd998b172c4e8658715a26a41c69144380beChris Wren    private static final String TAG = "NotificationListenerActivity";
45f715fd998b172c4e8658715a26a41c69144380beChris Wren
46f715fd998b172c4e8658715a26a41c69144380beChris Wren    private Button mLaunchButton;
47f715fd998b172c4e8658715a26a41c69144380beChris Wren    private TextView mEmptyText;
48f715fd998b172c4e8658715a26a41c69144380beChris Wren    private StatusAdaptor mStatusAdaptor;
49f715fd998b172c4e8658715a26a41c69144380beChris Wren    private final BroadcastReceiver mRefreshListener = new BroadcastReceiver() {
50f715fd998b172c4e8658715a26a41c69144380beChris Wren        @Override
51f715fd998b172c4e8658715a26a41c69144380beChris Wren        public void onReceive(Context context, Intent intent) {
52f715fd998b172c4e8658715a26a41c69144380beChris Wren            Log.i(TAG, "update tickle");
53f715fd998b172c4e8658715a26a41c69144380beChris Wren            updateList(intent.getStringExtra(Listener.EXTRA_KEY));
54f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
55f715fd998b172c4e8658715a26a41c69144380beChris Wren    };
56f715fd998b172c4e8658715a26a41c69144380beChris Wren
57f715fd998b172c4e8658715a26a41c69144380beChris Wren    @Override
58f715fd998b172c4e8658715a26a41c69144380beChris Wren    public void onCreate(Bundle savedInstanceState) {
59f715fd998b172c4e8658715a26a41c69144380beChris Wren        super.onCreate(savedInstanceState);
60f715fd998b172c4e8658715a26a41c69144380beChris Wren        setTitle(R.string.long_app_name);
61f715fd998b172c4e8658715a26a41c69144380beChris Wren        setContentView(R.layout.main);
62f715fd998b172c4e8658715a26a41c69144380beChris Wren        mLaunchButton = (Button) findViewById(R.id.launch_settings);
63f715fd998b172c4e8658715a26a41c69144380beChris Wren        mEmptyText = (TextView) findViewById(android.R.id.empty);
64f715fd998b172c4e8658715a26a41c69144380beChris Wren        mStatusAdaptor = new StatusAdaptor(this);
65f715fd998b172c4e8658715a26a41c69144380beChris Wren        setListAdapter(mStatusAdaptor);
66f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
67f715fd998b172c4e8658715a26a41c69144380beChris Wren
68f715fd998b172c4e8658715a26a41c69144380beChris Wren    @Override
69f715fd998b172c4e8658715a26a41c69144380beChris Wren    protected void onStop() {
70f715fd998b172c4e8658715a26a41c69144380beChris Wren        LocalBroadcastManager.getInstance(this).unregisterReceiver(mRefreshListener);
71f715fd998b172c4e8658715a26a41c69144380beChris Wren        super.onStop();
72f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
73f715fd998b172c4e8658715a26a41c69144380beChris Wren
74f715fd998b172c4e8658715a26a41c69144380beChris Wren    @Override
75f715fd998b172c4e8658715a26a41c69144380beChris Wren    public void onStart() {
76f715fd998b172c4e8658715a26a41c69144380beChris Wren        super.onStart();
77f715fd998b172c4e8658715a26a41c69144380beChris Wren        final IntentFilter intentFilter = new IntentFilter(Listener.ACTION_REFRESH);
78f715fd998b172c4e8658715a26a41c69144380beChris Wren        LocalBroadcastManager.getInstance(this).registerReceiver(mRefreshListener, intentFilter);
79f715fd998b172c4e8658715a26a41c69144380beChris Wren        updateList(null);
80f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
81f715fd998b172c4e8658715a26a41c69144380beChris Wren
82f715fd998b172c4e8658715a26a41c69144380beChris Wren    @Override
83f715fd998b172c4e8658715a26a41c69144380beChris Wren    public void onResume() {
84f715fd998b172c4e8658715a26a41c69144380beChris Wren        super.onResume();
85f715fd998b172c4e8658715a26a41c69144380beChris Wren        checkEnabled();
86f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
87f715fd998b172c4e8658715a26a41c69144380beChris Wren
88f715fd998b172c4e8658715a26a41c69144380beChris Wren    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
89f715fd998b172c4e8658715a26a41c69144380beChris Wren        checkEnabled();
90f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
91f715fd998b172c4e8658715a26a41c69144380beChris Wren
92f715fd998b172c4e8658715a26a41c69144380beChris Wren    private void checkEnabled() {
93f715fd998b172c4e8658715a26a41c69144380beChris Wren        String listeners = Secure.getString(getContentResolver(),
94f715fd998b172c4e8658715a26a41c69144380beChris Wren                "enabled_notification_listeners");
95f715fd998b172c4e8658715a26a41c69144380beChris Wren        if (listeners != null && listeners.contains(LISTENER_PATH)) {
96f715fd998b172c4e8658715a26a41c69144380beChris Wren            mLaunchButton.setText(R.string.launch_to_disable);
97f715fd998b172c4e8658715a26a41c69144380beChris Wren            mEmptyText.setText(R.string.waiting_for_content);
98f715fd998b172c4e8658715a26a41c69144380beChris Wren        } else {
99f715fd998b172c4e8658715a26a41c69144380beChris Wren            mLaunchButton.setText(R.string.launch_to_enable);
100f715fd998b172c4e8658715a26a41c69144380beChris Wren            mEmptyText.setText(R.string.nothing_to_see);
101f715fd998b172c4e8658715a26a41c69144380beChris Wren            AlertDialog.Builder builder = new AlertDialog.Builder(this);
102f715fd998b172c4e8658715a26a41c69144380beChris Wren            builder.setMessage(R.string.explanation)
103f715fd998b172c4e8658715a26a41c69144380beChris Wren                    .setTitle(R.string.disabled);
104f715fd998b172c4e8658715a26a41c69144380beChris Wren            builder.setPositiveButton(R.string.enable_it, new DialogInterface.OnClickListener() {
105f715fd998b172c4e8658715a26a41c69144380beChris Wren                public void onClick(DialogInterface dialog, int id) {
106f715fd998b172c4e8658715a26a41c69144380beChris Wren                    launchSettings(null);
107f715fd998b172c4e8658715a26a41c69144380beChris Wren                }
108f715fd998b172c4e8658715a26a41c69144380beChris Wren            });
109f715fd998b172c4e8658715a26a41c69144380beChris Wren            builder.setNegativeButton(R.string.cancel, null);
110f715fd998b172c4e8658715a26a41c69144380beChris Wren            builder.create().show();
111f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
112f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
113f715fd998b172c4e8658715a26a41c69144380beChris Wren
114f715fd998b172c4e8658715a26a41c69144380beChris Wren    public void launchSettings(View v) {
115f715fd998b172c4e8658715a26a41c69144380beChris Wren        startActivityForResult(
116f715fd998b172c4e8658715a26a41c69144380beChris Wren                new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"), 0);
117f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
118f715fd998b172c4e8658715a26a41c69144380beChris Wren
119f715fd998b172c4e8658715a26a41c69144380beChris Wren    public void dismiss(View v) {
120f715fd998b172c4e8658715a26a41c69144380beChris Wren        Log.d(TAG, "clicked dismiss ");
121f715fd998b172c4e8658715a26a41c69144380beChris Wren        Object tag = v.getTag();
122f715fd998b172c4e8658715a26a41c69144380beChris Wren        if (tag instanceof StatusBarNotification) {
123f715fd998b172c4e8658715a26a41c69144380beChris Wren            StatusBarNotification sbn = (StatusBarNotification) tag;
124f715fd998b172c4e8658715a26a41c69144380beChris Wren            Log.d(TAG, "  on " + sbn.getKey());
125f715fd998b172c4e8658715a26a41c69144380beChris Wren            LocalBroadcastManager.getInstance(this).
126f715fd998b172c4e8658715a26a41c69144380beChris Wren                    sendBroadcast(new Intent(Listener.ACTION_DISMISS)
127f715fd998b172c4e8658715a26a41c69144380beChris Wren                            .putExtra(Listener.EXTRA_KEY, sbn.getKey()));
128f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
129f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
130f715fd998b172c4e8658715a26a41c69144380beChris Wren
131f715fd998b172c4e8658715a26a41c69144380beChris Wren    public void launch(View v) {
132f715fd998b172c4e8658715a26a41c69144380beChris Wren        Log.d(TAG, "clicked launch");
133f715fd998b172c4e8658715a26a41c69144380beChris Wren        Object tag = v.getTag();
134f715fd998b172c4e8658715a26a41c69144380beChris Wren        if (tag instanceof StatusBarNotification) {
135f715fd998b172c4e8658715a26a41c69144380beChris Wren            StatusBarNotification sbn = (StatusBarNotification) tag;
136f715fd998b172c4e8658715a26a41c69144380beChris Wren            Log.d(TAG, "  on " + sbn.getKey());
137f715fd998b172c4e8658715a26a41c69144380beChris Wren            LocalBroadcastManager.getInstance(this).
138f715fd998b172c4e8658715a26a41c69144380beChris Wren                    sendBroadcast(new Intent(Listener.ACTION_LAUNCH)
139f715fd998b172c4e8658715a26a41c69144380beChris Wren                            .putExtra(Listener.EXTRA_KEY, sbn.getKey()));
140f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
141f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
142f715fd998b172c4e8658715a26a41c69144380beChris Wren
143f715fd998b172c4e8658715a26a41c69144380beChris Wren    private void updateList(String key) {
144f715fd998b172c4e8658715a26a41c69144380beChris Wren        if (mStatusAdaptor.requiresInitialization()) {
145f715fd998b172c4e8658715a26a41c69144380beChris Wren            final List<StatusBarNotification> notifications = Listener.getNotifications();
146f715fd998b172c4e8658715a26a41c69144380beChris Wren            if (notifications != null) {
147f715fd998b172c4e8658715a26a41c69144380beChris Wren                mStatusAdaptor.init(notifications);
148f715fd998b172c4e8658715a26a41c69144380beChris Wren            }
149f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
150f715fd998b172c4e8658715a26a41c69144380beChris Wren        mStatusAdaptor.update(key);
151f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
152f715fd998b172c4e8658715a26a41c69144380beChris Wren
153f715fd998b172c4e8658715a26a41c69144380beChris Wren    private class StatusAdaptor extends BaseAdapter {
154f715fd998b172c4e8658715a26a41c69144380beChris Wren        private final Context mContext;
155f715fd998b172c4e8658715a26a41c69144380beChris Wren        private List<StatusBarNotification> mNotifications;
156f715fd998b172c4e8658715a26a41c69144380beChris Wren        private HashMap<String, Long> mKeyToId;
157f715fd998b172c4e8658715a26a41c69144380beChris Wren        private HashSet<String> mKeys;
158f715fd998b172c4e8658715a26a41c69144380beChris Wren        private long mNextId;
159f715fd998b172c4e8658715a26a41c69144380beChris Wren        private HashMap<String, View> mRecycledViews;
160f715fd998b172c4e8658715a26a41c69144380beChris Wren        private String mUpdateKey;
161f715fd998b172c4e8658715a26a41c69144380beChris Wren
162f715fd998b172c4e8658715a26a41c69144380beChris Wren        public StatusAdaptor(Context context) {
163f715fd998b172c4e8658715a26a41c69144380beChris Wren            mContext = context;
164f715fd998b172c4e8658715a26a41c69144380beChris Wren            mKeyToId = new HashMap<String, Long>();
165f715fd998b172c4e8658715a26a41c69144380beChris Wren            mKeys = new HashSet<String>();
166f715fd998b172c4e8658715a26a41c69144380beChris Wren            mNextId = 0;
167f715fd998b172c4e8658715a26a41c69144380beChris Wren            mRecycledViews = new HashMap<String, View>();
168f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
169f715fd998b172c4e8658715a26a41c69144380beChris Wren
170f715fd998b172c4e8658715a26a41c69144380beChris Wren        @Override
171f715fd998b172c4e8658715a26a41c69144380beChris Wren        public int getCount() {
172f715fd998b172c4e8658715a26a41c69144380beChris Wren            return mNotifications == null ? 0 : mNotifications.size();
173f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
174f715fd998b172c4e8658715a26a41c69144380beChris Wren
175f715fd998b172c4e8658715a26a41c69144380beChris Wren        @Override
176f715fd998b172c4e8658715a26a41c69144380beChris Wren        public Object getItem(int position) {
177f715fd998b172c4e8658715a26a41c69144380beChris Wren            return mNotifications.get(position);
178f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
179f715fd998b172c4e8658715a26a41c69144380beChris Wren
180f715fd998b172c4e8658715a26a41c69144380beChris Wren        @Override
181f715fd998b172c4e8658715a26a41c69144380beChris Wren        public boolean hasStableIds() {
182f715fd998b172c4e8658715a26a41c69144380beChris Wren            return true;
183f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
184f715fd998b172c4e8658715a26a41c69144380beChris Wren
185f715fd998b172c4e8658715a26a41c69144380beChris Wren        @Override
186f715fd998b172c4e8658715a26a41c69144380beChris Wren        public long getItemId(int position) {
187f715fd998b172c4e8658715a26a41c69144380beChris Wren            final StatusBarNotification sbn = mNotifications.get(position);
188f715fd998b172c4e8658715a26a41c69144380beChris Wren            final String key = sbn.getKey();
189f715fd998b172c4e8658715a26a41c69144380beChris Wren            if (!mKeyToId.containsKey(key)) {
190f715fd998b172c4e8658715a26a41c69144380beChris Wren                mKeyToId.put(key, mNextId);
191f715fd998b172c4e8658715a26a41c69144380beChris Wren                mNextId ++;
192f715fd998b172c4e8658715a26a41c69144380beChris Wren            }
193f715fd998b172c4e8658715a26a41c69144380beChris Wren            return mKeyToId.get(key);
194f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
195f715fd998b172c4e8658715a26a41c69144380beChris Wren
196f715fd998b172c4e8658715a26a41c69144380beChris Wren        @Override
197f715fd998b172c4e8658715a26a41c69144380beChris Wren        public View getView(int position, View view, ViewGroup list) {
198f715fd998b172c4e8658715a26a41c69144380beChris Wren            if (view == null) {
199f715fd998b172c4e8658715a26a41c69144380beChris Wren                view = View.inflate(mContext, R.layout.item, null);
200f715fd998b172c4e8658715a26a41c69144380beChris Wren            }
201f715fd998b172c4e8658715a26a41c69144380beChris Wren            FrameLayout container = (FrameLayout) view.findViewById(R.id.remote_view);
202f715fd998b172c4e8658715a26a41c69144380beChris Wren            View dismiss = view.findViewById(R.id.dismiss);
203f715fd998b172c4e8658715a26a41c69144380beChris Wren            StatusBarNotification sbn = mNotifications.get(position);
204f715fd998b172c4e8658715a26a41c69144380beChris Wren            View child;
205f715fd998b172c4e8658715a26a41c69144380beChris Wren            if (container.getTag() instanceof StatusBarNotification &&
206f715fd998b172c4e8658715a26a41c69144380beChris Wren                    container.getChildCount() > 0) {
207f715fd998b172c4e8658715a26a41c69144380beChris Wren                // recycle the view
208f715fd998b172c4e8658715a26a41c69144380beChris Wren                StatusBarNotification old = (StatusBarNotification) container.getTag();
209f715fd998b172c4e8658715a26a41c69144380beChris Wren                if (sbn.getKey().equals(mUpdateKey)) {
210f715fd998b172c4e8658715a26a41c69144380beChris Wren                    //this view is out of date, discard it
211f715fd998b172c4e8658715a26a41c69144380beChris Wren                    mUpdateKey = null;
212f715fd998b172c4e8658715a26a41c69144380beChris Wren                } else {
213f715fd998b172c4e8658715a26a41c69144380beChris Wren                    View content = container.getChildAt(0);
214f715fd998b172c4e8658715a26a41c69144380beChris Wren                    container.removeView(content);
215f715fd998b172c4e8658715a26a41c69144380beChris Wren                    mRecycledViews.put(old.getKey(), content);
216f715fd998b172c4e8658715a26a41c69144380beChris Wren                }
217f715fd998b172c4e8658715a26a41c69144380beChris Wren            }
218f715fd998b172c4e8658715a26a41c69144380beChris Wren            child = mRecycledViews.get(sbn.getKey());
219f715fd998b172c4e8658715a26a41c69144380beChris Wren            if (child == null) {
220f715fd998b172c4e8658715a26a41c69144380beChris Wren                child = sbn.getNotification().contentView.apply(mContext, null);
221f715fd998b172c4e8658715a26a41c69144380beChris Wren            }
222f715fd998b172c4e8658715a26a41c69144380beChris Wren            container.setTag(sbn);
223f715fd998b172c4e8658715a26a41c69144380beChris Wren            container.removeAllViews();
224f715fd998b172c4e8658715a26a41c69144380beChris Wren            container.addView(child);
225f715fd998b172c4e8658715a26a41c69144380beChris Wren            dismiss.setVisibility(sbn.isClearable() ? View.VISIBLE : View.GONE);
226f715fd998b172c4e8658715a26a41c69144380beChris Wren            dismiss.setTag(sbn);
227f715fd998b172c4e8658715a26a41c69144380beChris Wren            return view;
228f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
229f715fd998b172c4e8658715a26a41c69144380beChris Wren
230f715fd998b172c4e8658715a26a41c69144380beChris Wren        public void update(String key) {
231f715fd998b172c4e8658715a26a41c69144380beChris Wren            if (mNotifications != null) {
232f715fd998b172c4e8658715a26a41c69144380beChris Wren                synchronized (mNotifications) {
233f715fd998b172c4e8658715a26a41c69144380beChris Wren                    mKeys.clear();
234f715fd998b172c4e8658715a26a41c69144380beChris Wren                    for (int i = 0; i < mNotifications.size(); i++) {
235f715fd998b172c4e8658715a26a41c69144380beChris Wren                        mKeys.add(mNotifications.get(i).getKey());
236f715fd998b172c4e8658715a26a41c69144380beChris Wren                    }
237f715fd998b172c4e8658715a26a41c69144380beChris Wren                    mKeyToId.keySet().retainAll(mKeys);
238f715fd998b172c4e8658715a26a41c69144380beChris Wren                }
239f715fd998b172c4e8658715a26a41c69144380beChris Wren                if (key == null) {
240f715fd998b172c4e8658715a26a41c69144380beChris Wren                    mRecycledViews.clear();
241f715fd998b172c4e8658715a26a41c69144380beChris Wren                } else {
242f715fd998b172c4e8658715a26a41c69144380beChris Wren                    mUpdateKey = key;
243f715fd998b172c4e8658715a26a41c69144380beChris Wren                    mRecycledViews.remove(key);
244f715fd998b172c4e8658715a26a41c69144380beChris Wren                }
245f715fd998b172c4e8658715a26a41c69144380beChris Wren                Log.d(TAG, "notifyDataSetChanged");
246f715fd998b172c4e8658715a26a41c69144380beChris Wren                notifyDataSetChanged();
247f715fd998b172c4e8658715a26a41c69144380beChris Wren            } else {
248f715fd998b172c4e8658715a26a41c69144380beChris Wren                Log.d(TAG, "missed and update");
249f715fd998b172c4e8658715a26a41c69144380beChris Wren            }
250f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
251f715fd998b172c4e8658715a26a41c69144380beChris Wren
252f715fd998b172c4e8658715a26a41c69144380beChris Wren        public boolean requiresInitialization() {
253f715fd998b172c4e8658715a26a41c69144380beChris Wren            return mNotifications == null;
254f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
255f715fd998b172c4e8658715a26a41c69144380beChris Wren
256f715fd998b172c4e8658715a26a41c69144380beChris Wren        public void init(List<StatusBarNotification> notifications) {
257f715fd998b172c4e8658715a26a41c69144380beChris Wren            mNotifications = notifications;
258f715fd998b172c4e8658715a26a41c69144380beChris Wren        }
259f715fd998b172c4e8658715a26a41c69144380beChris Wren    }
260f715fd998b172c4e8658715a26a41c69144380beChris Wren}
261