IntentTile.java revision ee43cdfa43b09a79e66d81f6673a79bc26427343
1bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock/*
2bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * Copyright (C) 2014 The Android Open Source Project
3bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock *
4bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
5bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * you may not use this file except in compliance with the License.
6bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * You may obtain a copy of the License at
7bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock *
8bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
9bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock *
10bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * Unless required by applicable law or agreed to in writing, software
11bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
12bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * See the License for the specific language governing permissions and
14bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock * limitations under the License.
15bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock */
16bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
17bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockpackage com.android.systemui.qs.tiles;
18bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
19bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.app.PendingIntent;
20bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.content.BroadcastReceiver;
21bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.content.Context;
22bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.content.Intent;
23bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.content.IntentFilter;
24bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.graphics.Bitmap;
25bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.graphics.BitmapFactory;
26bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.graphics.drawable.BitmapDrawable;
27bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.graphics.drawable.Drawable;
28bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.os.UserHandle;
29bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.text.TextUtils;
30bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport android.util.Log;
31bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
32457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wrenimport com.android.internal.logging.MetricsLogger;
33bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockimport com.android.systemui.qs.QSTile;
34bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
352d695813b44690ca146f95939acb00f0c14dac29John Spurlockimport java.util.Arrays;
362d695813b44690ca146f95939acb00f0c14dac29John Spurlockimport java.util.Objects;
372d695813b44690ca146f95939acb00f0c14dac29John Spurlock
38bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlockpublic class IntentTile extends QSTile<QSTile.State> {
39bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    public static final String PREFIX = "intent(";
40bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
41bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    private PendingIntent mOnClick;
42bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    private String mOnClickUri;
43c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock    private PendingIntent mOnLongClick;
44c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock    private String mOnLongClickUri;
45bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    private int mCurrentUserId;
46457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren    private String mIntentPackage;
47bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
48bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    private IntentTile(Host host, String action) {
49bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        super(host);
50bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        mContext.registerReceiver(mReceiver, new IntentFilter(action));
51bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    }
52bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
53bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    @Override
54bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    protected void handleDestroy() {
55bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        super.handleDestroy();
56bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        mContext.unregisterReceiver(mReceiver);
57bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    }
58bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
59bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    public static QSTile<?> create(Host host, String spec) {
60bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        if (spec == null || !spec.startsWith(PREFIX) || !spec.endsWith(")")) {
61bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            throw new IllegalArgumentException("Bad intent tile spec: " + spec);
62bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        }
63bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        final String action = spec.substring(PREFIX.length(), spec.length() - 1);
64bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        if (action.isEmpty()) {
65bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            throw new IllegalArgumentException("Empty intent tile spec action");
66bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        }
67bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        return new IntentTile(host, action);
68bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    }
69bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
70bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    @Override
71bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    public void setListening(boolean listening) {
72bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    }
73bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
74bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    @Override
75bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    protected State newTileState() {
76bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        return new State();
77bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    }
78bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
79bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    @Override
80bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    protected void handleUserSwitch(int newUserId) {
81bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        super.handleUserSwitch(newUserId);
82bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        mCurrentUserId = newUserId;
83bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    }
84bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
85bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    @Override
86bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    protected void handleClick() {
879e7283f6a31bc2beb75c84c6173968a46582c563Chris Wren        MetricsLogger.action(mContext, getMetricsCategory(), mIntentPackage);
88c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock        sendIntent("click", mOnClick, mOnClickUri);
89c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock    }
90c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock
91c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock    @Override
92c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock    protected void handleLongClick() {
93c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock        sendIntent("long-click", mOnLongClick, mOnLongClickUri);
94c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock    }
95c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock
96c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock    private void sendIntent(String type, PendingIntent pi, String uri) {
97bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        try {
98c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock            if (pi != null) {
99ee43cdfa43b09a79e66d81f6673a79bc26427343Jason Monk                if (pi.isActivity()) {
100ee43cdfa43b09a79e66d81f6673a79bc26427343Jason Monk                    getHost().startActivityDismissingKeyguard(pi.getIntent());
101ee43cdfa43b09a79e66d81f6673a79bc26427343Jason Monk                } else {
102ee43cdfa43b09a79e66d81f6673a79bc26427343Jason Monk                    pi.send();
103ee43cdfa43b09a79e66d81f6673a79bc26427343Jason Monk                }
104c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock            } else if (uri != null) {
105c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock                final Intent intent = Intent.parseUri(uri, Intent.URI_INTENT_SCHEME);
106bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock                mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
107bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            }
108bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        } catch (Throwable t) {
109c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock            Log.w(TAG, "Error sending " + type + " intent", t);
110bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        }
111bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    }
112bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock
113bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    @Override
114bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    protected void handleUpdateState(State state, Object arg) {
115bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        if (!(arg instanceof Intent)) return;
116bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        final Intent intent = (Intent) arg;
117bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        state.visible = intent.getBooleanExtra("visible", true);
118bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        state.contentDescription = intent.getStringExtra("contentDescription");
119bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        state.label = intent.getStringExtra("label");
120bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        state.icon = null;
121bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        final byte[] iconBitmap = intent.getByteArrayExtra("iconBitmap");
122bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        if (iconBitmap != null) {
123bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            try {
1242d695813b44690ca146f95939acb00f0c14dac29John Spurlock                state.icon = new BytesIcon(iconBitmap);
125bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            } catch (Throwable t) {
126bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock                Log.w(TAG, "Error loading icon bitmap, length " + iconBitmap.length, t);
127bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            }
128bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        } else {
129bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            final int iconId = intent.getIntExtra("iconId", 0);
130bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            if (iconId != 0) {
131bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock                final String iconPackage = intent.getStringExtra("iconPackage");
132bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock                if (!TextUtils.isEmpty(iconPackage)) {
1332d695813b44690ca146f95939acb00f0c14dac29John Spurlock                    state.icon = new PackageDrawableIcon(iconPackage, iconId);
134bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock                } else {
1352d695813b44690ca146f95939acb00f0c14dac29John Spurlock                    state.icon = ResourceIcon.get(iconId);
136bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock                }
137bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            }
138bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        }
139bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        mOnClick = intent.getParcelableExtra("onClick");
140bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        mOnClickUri = intent.getStringExtra("onClickUri");
141c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock        mOnLongClick = intent.getParcelableExtra("onLongClick");
142c247b8f7270dd70ecc36977fcc0530217879f665John Spurlock        mOnLongClickUri = intent.getStringExtra("onLongClickUri");
143457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren        mIntentPackage = intent.getStringExtra("package");
1449e7283f6a31bc2beb75c84c6173968a46582c563Chris Wren        mIntentPackage = mIntentPackage == null ? "" : mIntentPackage;
145457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren    }
146457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren
147457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren    @Override
148457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren    public int getMetricsCategory() {
149457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren        return MetricsLogger.QS_INTENT;
150457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren    }
151457a21cdeac04565a0c40ad8c43a928c1182ddd1Chris Wren
152bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
153bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        @Override
154bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        public void onReceive(Context context, Intent intent) {
155bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock            refreshState(intent);
156bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock        }
157bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock    };
1582d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1592d695813b44690ca146f95939acb00f0c14dac29John Spurlock    private static class BytesIcon extends Icon {
1602d695813b44690ca146f95939acb00f0c14dac29John Spurlock        private final byte[] mBytes;
1612d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1622d695813b44690ca146f95939acb00f0c14dac29John Spurlock        public BytesIcon(byte[] bytes) {
1632d695813b44690ca146f95939acb00f0c14dac29John Spurlock            mBytes = bytes;
1642d695813b44690ca146f95939acb00f0c14dac29John Spurlock        }
1652d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1662d695813b44690ca146f95939acb00f0c14dac29John Spurlock        @Override
1672d695813b44690ca146f95939acb00f0c14dac29John Spurlock        public Drawable getDrawable(Context context) {
1682d695813b44690ca146f95939acb00f0c14dac29John Spurlock            final Bitmap b = BitmapFactory.decodeByteArray(mBytes, 0, mBytes.length);
1692d695813b44690ca146f95939acb00f0c14dac29John Spurlock            return new BitmapDrawable(context.getResources(), b);
1702d695813b44690ca146f95939acb00f0c14dac29John Spurlock        }
1712d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1722d695813b44690ca146f95939acb00f0c14dac29John Spurlock        @Override
1732d695813b44690ca146f95939acb00f0c14dac29John Spurlock        public boolean equals(Object o) {
1742d695813b44690ca146f95939acb00f0c14dac29John Spurlock            return o instanceof BytesIcon && Arrays.equals(((BytesIcon) o).mBytes, mBytes);
1752d695813b44690ca146f95939acb00f0c14dac29John Spurlock        }
1762d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1772d695813b44690ca146f95939acb00f0c14dac29John Spurlock        @Override
1782d695813b44690ca146f95939acb00f0c14dac29John Spurlock        public String toString() {
1792d695813b44690ca146f95939acb00f0c14dac29John Spurlock            return String.format("BytesIcon[len=%s]", mBytes.length);
1802d695813b44690ca146f95939acb00f0c14dac29John Spurlock        }
1812d695813b44690ca146f95939acb00f0c14dac29John Spurlock    }
1822d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1832d695813b44690ca146f95939acb00f0c14dac29John Spurlock    private class PackageDrawableIcon extends Icon {
1842d695813b44690ca146f95939acb00f0c14dac29John Spurlock        private final String mPackage;
1852d695813b44690ca146f95939acb00f0c14dac29John Spurlock        private final int mResId;
1862d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1872d695813b44690ca146f95939acb00f0c14dac29John Spurlock        public PackageDrawableIcon(String pkg, int resId) {
1882d695813b44690ca146f95939acb00f0c14dac29John Spurlock            mPackage = pkg;
1892d695813b44690ca146f95939acb00f0c14dac29John Spurlock            mResId = resId;
1902d695813b44690ca146f95939acb00f0c14dac29John Spurlock        }
1912d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1922d695813b44690ca146f95939acb00f0c14dac29John Spurlock        @Override
1932d695813b44690ca146f95939acb00f0c14dac29John Spurlock        public boolean equals(Object o) {
1942d695813b44690ca146f95939acb00f0c14dac29John Spurlock            if (!(o instanceof PackageDrawableIcon)) return false;
1952d695813b44690ca146f95939acb00f0c14dac29John Spurlock            final PackageDrawableIcon other = (PackageDrawableIcon) o;
1962d695813b44690ca146f95939acb00f0c14dac29John Spurlock            return Objects.equals(other.mPackage, mPackage) && other.mResId == mResId;
1972d695813b44690ca146f95939acb00f0c14dac29John Spurlock        }
1982d695813b44690ca146f95939acb00f0c14dac29John Spurlock
1992d695813b44690ca146f95939acb00f0c14dac29John Spurlock        @Override
2002d695813b44690ca146f95939acb00f0c14dac29John Spurlock        public Drawable getDrawable(Context context) {
2012d695813b44690ca146f95939acb00f0c14dac29John Spurlock            try {
2022d695813b44690ca146f95939acb00f0c14dac29John Spurlock                return context.createPackageContext(mPackage, 0).getDrawable(mResId);
2032d695813b44690ca146f95939acb00f0c14dac29John Spurlock            } catch (Throwable t) {
2042d695813b44690ca146f95939acb00f0c14dac29John Spurlock                Log.w(TAG, "Error loading package drawable pkg=" + mPackage + " id=" + mResId, t);
2052d695813b44690ca146f95939acb00f0c14dac29John Spurlock                return null;
2062d695813b44690ca146f95939acb00f0c14dac29John Spurlock            }
2072d695813b44690ca146f95939acb00f0c14dac29John Spurlock        }
2082d695813b44690ca146f95939acb00f0c14dac29John Spurlock
2092d695813b44690ca146f95939acb00f0c14dac29John Spurlock        @Override
2102d695813b44690ca146f95939acb00f0c14dac29John Spurlock        public String toString() {
2112d695813b44690ca146f95939acb00f0c14dac29John Spurlock            return String.format("PackageDrawableIcon[pkg=%s,id=0x%08x]", mPackage, mResId);
2122d695813b44690ca146f95939acb00f0c14dac29John Spurlock        }
2132d695813b44690ca146f95939acb00f0c14dac29John Spurlock    }
214bceed060f0090a4f86418c4515128d5ec8ebdd4aJohn Spurlock}
215