1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.support.v4.content;
17
18import org.junit.Before;
19import org.junit.Test;
20
21import android.content.Context;
22import android.content.pm.PackageManager;
23import android.content.res.ColorStateList;
24import android.graphics.drawable.Drawable;
25import android.os.Build;
26import android.support.v4.BaseInstrumentationTestCase;
27import android.support.v4.ThemedYellowActivity;
28import android.support.v4.test.R;
29import android.support.v4.testutils.TestUtils;
30import android.test.suitebuilder.annotation.SmallTest;
31import android.util.DisplayMetrics;
32
33import static org.junit.Assert.assertEquals;
34
35@SmallTest
36public class ContextCompatTest extends BaseInstrumentationTestCase<ThemedYellowActivity> {
37    private Context mContext;
38
39    public ContextCompatTest() {
40        super(ThemedYellowActivity.class);
41    }
42
43    @Before
44    public void setup() {
45        mContext = mActivityTestRule.getActivity();
46    }
47
48    @Test
49    public void testGetColor() throws Throwable {
50        assertEquals("Unthemed color load", 0xFFFF8090,
51                ContextCompat.getColor(mContext, R.color.text_color));
52
53        if (Build.VERSION.SDK_INT >= 23) {
54            // The following test is only expected to pass on v23+ devices. The result of
55            // calling theme-aware getColor() in pre-v23 is undefined.
56            assertEquals("Themed yellow color load",
57                    ContextCompat.getColor(mContext, R.color.simple_themed_selector),
58                    0xFFF0B000);
59        }
60    }
61
62    @Test
63    public void testGetColorStateList() throws Throwable {
64        ColorStateList unthemedColorStateList =
65                ContextCompat.getColorStateList(mContext, R.color.complex_unthemed_selector);
66        assertEquals("Unthemed color state list load: default", 0xFF70A0C0,
67                unthemedColorStateList.getDefaultColor());
68        assertEquals("Unthemed color state list load: focused", 0xFF70B0F0,
69                unthemedColorStateList.getColorForState(
70                        new int[]{android.R.attr.state_focused}, 0));
71        assertEquals("Unthemed color state list load: pressed", 0xFF6080B0,
72                unthemedColorStateList.getColorForState(
73                        new int[]{android.R.attr.state_pressed}, 0));
74
75        if (Build.VERSION.SDK_INT >= 23) {
76            // The following tests are only expected to pass on v23+ devices. The result of
77            // calling theme-aware getColorStateList() in pre-v23 is undefined.
78            ColorStateList themedYellowColorStateList =
79                    ContextCompat.getColorStateList(mContext, R.color.complex_themed_selector);
80            assertEquals("Themed yellow color state list load: default", 0xFFF0B000,
81                    themedYellowColorStateList.getDefaultColor());
82            assertEquals("Themed yellow color state list load: focused", 0xFFF0A020,
83                    themedYellowColorStateList.getColorForState(
84                            new int[]{android.R.attr.state_focused}, 0));
85            assertEquals("Themed yellow color state list load: pressed", 0xFFE0A040,
86                    themedYellowColorStateList.getColorForState(
87                            new int[]{android.R.attr.state_pressed}, 0));
88        }
89    }
90
91    @Test
92    public void testGetDrawable() throws Throwable {
93        Drawable unthemedDrawable =
94                ContextCompat.getDrawable(mContext, R.drawable.test_drawable_red);
95        TestUtils.assertAllPixelsOfColor("Unthemed drawable load",
96                unthemedDrawable, mContext.getResources().getColor(R.color.test_red));
97
98        if (Build.VERSION.SDK_INT >= 23) {
99            // The following test is only expected to pass on v23+ devices. The result of
100            // calling theme-aware getDrawable() in pre-v23 is undefined.
101            Drawable themedYellowDrawable =
102                    ContextCompat.getDrawable(mContext, R.drawable.themed_drawable);
103            TestUtils.assertAllPixelsOfColor("Themed yellow drawable load",
104                    themedYellowDrawable, 0xFFF0B000);
105        }
106    }
107
108    @Test
109    public void testDrawableConfigurationWorkaround() throws Throwable {
110        final int expectedWidth = scaleFromDensity(7, DisplayMetrics.DENSITY_LOW,
111                mContext.getResources().getDisplayMetrics().densityDpi);
112
113        // Ensure we retrieve the correct drawable configuration. Specifically,
114        // this tests a workaround for a bug in drawable configuration that
115        // exists on API < 16 for references to drawables.
116        Drawable referencedDrawable = ContextCompat.getDrawable(mContext,
117                R.drawable.aliased_drawable);
118        assertEquals("Drawable configuration does not match DisplayMetrics",
119                expectedWidth, referencedDrawable.getIntrinsicWidth());
120    }
121
122    private static int scaleFromDensity(int size, int sdensity, int tdensity) {
123        if (sdensity == tdensity) {
124            return size;
125        }
126
127        // Scale by tdensity / sdensity, rounding up.
128        return ((size * tdensity) + (sdensity >> 1)) / sdensity;
129    }
130
131    @Test(expected = IllegalArgumentException.class)
132    public void testCheckSelfPermissionNull() {
133        ContextCompat.checkSelfPermission(mContext, null);
134    }
135
136    @Test
137    public void testCheckSelfPermission() {
138        assertEquals("Vibrate permission granted", PackageManager.PERMISSION_GRANTED,
139                ContextCompat.checkSelfPermission(mContext,
140                        android.Manifest.permission.VIBRATE));
141        assertEquals("Wake lock permission granted", PackageManager.PERMISSION_GRANTED,
142                ContextCompat.checkSelfPermission(mContext,
143                        android.Manifest.permission.WAKE_LOCK));
144
145        if (Build.VERSION.SDK_INT >= 23) {
146            // As documented in http://developer.android.com/training/permissions/requesting.html
147            // starting in Android M (v23) dangerous permissions are not granted automactically
148            // to apps targeting SDK 23 even if those are defined in the manifest.
149            // This is why the following permissions are expected to be denied.
150            assertEquals("Read contacts permission granted", PackageManager.PERMISSION_DENIED,
151                    ContextCompat.checkSelfPermission(mContext,
152                            android.Manifest.permission.READ_CONTACTS));
153            assertEquals("Write contacts permission granted", PackageManager.PERMISSION_DENIED,
154                    ContextCompat.checkSelfPermission(mContext,
155                            android.Manifest.permission.WRITE_CONTACTS));
156        } else {
157            // And on older devices declared dangerous permissions are expected to be granted.
158            assertEquals("Read contacts permission denied", PackageManager.PERMISSION_GRANTED,
159                    ContextCompat.checkSelfPermission(mContext,
160                            android.Manifest.permission.READ_CONTACTS));
161            assertEquals("Write contacts permission denied", PackageManager.PERMISSION_GRANTED,
162                    ContextCompat.checkSelfPermission(mContext,
163                            android.Manifest.permission.WRITE_CONTACTS));
164        }
165
166        // The following permissions (normal and dangerous) are expected to be denied as they are
167        // not declared in our manifest.
168        assertEquals("Access network state permission denied", PackageManager.PERMISSION_DENIED,
169                ContextCompat.checkSelfPermission(mContext,
170                        android.Manifest.permission.ACCESS_NETWORK_STATE));
171        assertEquals("Bluetooth permission denied", PackageManager.PERMISSION_DENIED,
172                ContextCompat.checkSelfPermission(mContext,
173                        android.Manifest.permission.BLUETOOTH));
174        assertEquals("Call phone permission denied", PackageManager.PERMISSION_DENIED,
175                ContextCompat.checkSelfPermission(mContext,
176                        android.Manifest.permission.CALL_PHONE));
177        assertEquals("Delete packages permission denied", PackageManager.PERMISSION_DENIED,
178                ContextCompat.checkSelfPermission(mContext,
179                        android.Manifest.permission.DELETE_PACKAGES));
180    }
181}