Skip to content

Commit 78cb5d9

Browse files
committed
Use WeakReference for caching DisplayManagerCompat instances
Relnote: Fixed Context leak in DisplayManagerCompat Fixes: 279625765 Test: DisplayManagerCompatTest Change-Id: I3409b324301609dba940ef5894ff349b0f229d13
1 parent defa023 commit 78cb5d9

File tree

2 files changed

+70
-5
lines changed

2 files changed

+70
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2023 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+
*/
16+
17+
package androidx.core.hardware.display
18+
19+
import android.content.Context
20+
import androidx.test.ext.junit.runners.AndroidJUnit4
21+
import androidx.test.filters.SmallTest
22+
import androidx.test.platform.app.InstrumentationRegistry
23+
import org.junit.Assert.assertNotNull
24+
import org.junit.Assert.assertSame
25+
import org.junit.Before
26+
import org.junit.Test
27+
import org.junit.runner.RunWith
28+
29+
@SmallTest
30+
@RunWith(AndroidJUnit4::class)
31+
class DisplayManagerCompatTest {
32+
33+
private lateinit var context: Context
34+
35+
@Before
36+
fun setup() {
37+
context = InstrumentationRegistry.getInstrumentation().context
38+
}
39+
40+
@Test
41+
fun testGetInstance() {
42+
val displayManagerA = DisplayManagerCompat.getInstance(context)
43+
assertNotNull(displayManagerA)
44+
45+
val displayManagerB = DisplayManagerCompat.getInstance(context)
46+
assertSame(displayManagerA, displayManagerB)
47+
}
48+
49+
@Test
50+
fun testGetDisplay() {
51+
val displayManager = DisplayManagerCompat.getInstance(context)
52+
assertNotNull(displayManager)
53+
54+
val displays = displayManager.displays
55+
assertNotNull(displays)
56+
57+
// If this device has displays, make sure we can obtain them. This is objectively an
58+
// integration test, but it's the best we can do given the platform's testability.
59+
displays.forEach { display ->
60+
val actualDisplay = displayManager.getDisplay(display.displayId)
61+
assertNotNull(actualDisplay)
62+
}
63+
}
64+
}

core/core/src/main/java/androidx/core/hardware/display/DisplayManagerCompat.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@
2727
import androidx.annotation.Nullable;
2828
import androidx.annotation.RequiresApi;
2929

30+
import java.lang.ref.WeakReference;
3031
import java.util.WeakHashMap;
3132

3233
/**
3334
* Helper for accessing features in {@link android.hardware.display.DisplayManager}.
3435
*/
3536
@SuppressWarnings("unused")
3637
public final class DisplayManagerCompat {
37-
private static final WeakHashMap<Context, DisplayManagerCompat> sInstances =
38+
private static final WeakHashMap<Context, WeakReference<DisplayManagerCompat>> sInstances =
3839
new WeakHashMap<>();
3940

4041
/**
@@ -63,12 +64,12 @@ private DisplayManagerCompat(Context context) {
6364
@NonNull
6465
public static DisplayManagerCompat getInstance(@NonNull Context context) {
6566
synchronized (sInstances) {
66-
DisplayManagerCompat instance = sInstances.get(context);
67-
if (instance == null) {
68-
instance = new DisplayManagerCompat(context);
67+
WeakReference<DisplayManagerCompat> instance = sInstances.get(context);
68+
if (instance == null || instance.get() == null) {
69+
instance = new WeakReference<>(new DisplayManagerCompat(context));
6970
sInstances.put(context, instance);
7071
}
71-
return instance;
72+
return instance.get();
7273
}
7374
}
7475

0 commit comments

Comments
 (0)