├── src
├── test
│ ├── resources
│ │ └── logger
│ │ │ └── debug
│ └── java
│ │ └── android
│ │ └── os
│ │ ├── BaseTestHandler.kt
│ │ └── HandlerTest.kt
└── main
│ └── java
│ └── android
│ ├── os
│ ├── HandlerThread.java
│ ├── internal
│ │ ├── Delayed.java
│ │ ├── DelayQueue.java
│ │ └── PriorityQueue.java
│ ├── Looper.java
│ ├── utils
│ │ └── Logger.java
│ ├── MessageQueue.java
│ ├── Handler.java
│ └── Message.java
│ └── app
│ └── ActivityThread.java
├── settings.gradle
├── gradle
└── wrapper
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── README.md
├── LICENSE
├── gradlew.bat
└── gradlew
/src/test/resources/logger/debug:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'portable-android-handler'
2 |
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/src/test/java/android/os/BaseTestHandler.kt:
--------------------------------------------------------------------------------
1 | package android.os
2 |
3 | import android.os.utils.*
4 |
5 | class BaseTestHandler(looper: Looper = Looper.myLooper()) : Handler(looper) {
6 | override fun handleMessage(msg: Message) {
7 | super.handleMessage(msg)
8 | Logger.debug(msg)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
25 | .idea
26 | build
27 | *.iml
28 | out
29 | .gradle
30 |
31 | local.properties
32 | jcenter.properties
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | GROUP=com.bennyhuo
2 | VERSION_NAME=1.0
3 | POM_ARTIFACT_ID=portable-android-handler
4 |
5 | POM_NAME=PortableAndroidHandler
6 |
7 | POM_URL=https://github.com/bennyhuo/PortableAndroidHandler
8 | POM_DESCRIPTION=Pure Java implementation of Android Handler.
9 |
10 | POM_SCM_URL=https://github.com/bennyhuo/PortableAndroidHandler
11 | POM_SCM_CONNECTION=scm:git:git://github.com/bennyhuo/PortableAndroidHandler.git
12 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com:bennyhuo/PortableAndroidHandler.git
13 |
14 | POM_LICENCE_NAME=MIT License
15 | POM_LICENCE_URL=https://github.com/bennyhuo/PortableAndroidHandler/blob/master/LICENSE
16 | POM_LICENCE_DIST=repo
17 |
18 | POM_DEVELOPER_ID=bennyhuo
19 | POM_DEVELOPER_NAME=Benny Huo
20 | POM_DEVELOPER_URL=https://github.com/bennyhuo/
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PortableAndroidHandler
2 | Pure Java implementation of Android Handler. This is helpful to test Android Handler based logic in a pure Java project.
3 |
4 | Use `DelayQueue` internal to implement the `MessageQuue`.
5 |
6 | The project is still working, and most of the Android Handler related apis will be completed later on.
7 |
8 | ## Usage
9 |
10 | It has been deployed to mavenCentral:
11 |
12 | ```
13 | implementation("com.bennyhuo:portable-android-handler:1.0")
14 | ```
15 |
16 | First you should setup your own looper thread like what Android does in `ActivityThread`:
17 |
18 | ``` java
19 | Looper.prepare();
20 | // Create a new Thread to use your handler here.
21 | Looper.loop();
22 | //unreachable unless you quit the looper.
23 | ```
24 |
25 | ## Reference
26 |
27 | This library is mentioned in my Android Interview Tutorials: [破解Android高级面试](https://s.imooc.com/SBS30PR)
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Bennyhuo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/java/android/os/HandlerThread.java:
--------------------------------------------------------------------------------
1 | package android.os;
2 |
3 | public class HandlerThread extends Thread {
4 | Looper mLooper;
5 | private Handler mHandler;
6 |
7 | public HandlerThread(String name) { super(name); }
8 | protected void onLooperPrepared() { }
9 |
10 | @Override
11 | public void run() {
12 | Looper.prepare();
13 | synchronized (this) {
14 | mLooper = Looper.myLooper();
15 | notifyAll();
16 | }
17 | onLooperPrepared();
18 | Looper.loop();
19 | }
20 |
21 | public Looper getLooper() {
22 | if (!isAlive()) return null;
23 | synchronized (this) {
24 | while (isAlive() && mLooper == null)
25 | try { wait(); } catch (InterruptedException e) { }
26 | }
27 | return mLooper;
28 | }
29 |
30 | public Handler getThreadHandler() {
31 | if (mHandler == null) mHandler = new Handler(getLooper());
32 | return mHandler;
33 | }
34 |
35 | public boolean quit() {
36 | Looper looper = getLooper();
37 | if (looper != null) {
38 | looper.quit();
39 | return true;
40 | }
41 | return false;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/android/os/internal/Delayed.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
3 | *
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | */
24 |
25 | /*
26 | *
27 | *
28 | *
29 | *
30 | *
31 | * Written by Doug Lea with assistance from members of JCP JSR-166
32 | * Expert Group and released to the public domain, as explained at
33 | * http://creativecommons.org/publicdomain/zero/1.0/
34 | */
35 |
36 | package android.os.internal;
37 |
38 | import java.util.concurrent.TimeUnit;
39 |
40 | /**
41 | * A mix-in style interface for marking objects that should be
42 | * acted upon after a given delay.
43 | *
44 | *
An implementation of this interface must define a
45 | * {@code compareTo} method that provides an ordering consistent with
46 | * its {@code getDelay} method.
47 | *
48 | * @since 1.5
49 | * @author Doug Lea
50 | */
51 | public interface Delayed extends Comparable {
52 |
53 | /**
54 | * Returns the remaining delay associated with this object, in the
55 | * given time unit.
56 | *
57 | * @param unit the time unit
58 | * @return the remaining delay; zero or negative values indicate
59 | * that the delay has already elapsed
60 | */
61 | long getDelay(TimeUnit unit);
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/android/app/ActivityThread.java:
--------------------------------------------------------------------------------
1 | package android.app;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.os.Message;
6 |
7 | public class ActivityThread {
8 |
9 | private Handler handler = new Handler() {
10 | @Override
11 | public void handleMessage(Message msg) {
12 | System.out.println(msg);
13 | }
14 | };
15 |
16 | private void attach(){
17 | Thread otherThread = new Thread() {
18 | @Override
19 | public void run() {
20 | super.run();
21 |
22 | for (int i = 0; i < 5; i++) {
23 | try {
24 | sleep(2000);
25 | } catch (InterruptedException e) {
26 | e.printStackTrace();
27 | }
28 | for (int j = 0; j < 5; j++) {
29 | Message msg = new Message();
30 | msg.what = i * 5 + j;
31 | msg.obj = "[" + i + ", " + j + "]";
32 | handler.sendMessageDelayed(msg, (long) (Math.random() * 10000));
33 | }
34 | }
35 | }
36 | };
37 | otherThread.start();
38 | }
39 |
40 | public static void main(String... args) {
41 | Looper.prepareMainLooper();
42 | ActivityThread activityThread = new ActivityThread();
43 | activityThread.attach();
44 | Looper.loop();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/android/os/HandlerTest.kt:
--------------------------------------------------------------------------------
1 | package android.os
2 |
3 | import android.os.utils.*
4 | import org.junit.*
5 |
6 | class HandlerTest {
7 | private lateinit var looper: Looper
8 |
9 | @Test
10 | fun test() {
11 | Looper.prepare()
12 | looper = Looper.myLooper()
13 |
14 | val workingThread = Thread(Runnable {
15 | testRemove()
16 | looper.quitSafely()
17 | }, "Working-Thread")
18 | workingThread.start()
19 |
20 | Looper.loop()
21 | }
22 |
23 | fun testRemove() {
24 | val token = Any()
25 | val r = Runnable {
26 | Logger.debug("Runnable called!")
27 | }
28 | val handler = BaseTestHandler(looper)
29 |
30 | val msg = Message().also {
31 | it.obj = token
32 | it.who = "msg"
33 | }
34 |
35 | val msg1= Message().also {
36 | it.what = 1
37 | it.who = "msg1"
38 | }
39 |
40 | val msg2 = Message().also {
41 | it.callback = r
42 | it.who = "msg2"
43 | }
44 |
45 | val msg3 = Message().also {
46 | it.callback = r
47 | it.obj = token
48 | it.who = "msg3"
49 | }
50 |
51 | val msg4= Message().also {
52 | it.what = 1
53 | it.obj = token
54 | it.who = "msg4"
55 | }
56 |
57 | handler.sendMessage(msg)
58 | handler.sendMessage(msg1)
59 | handler.sendMessage(msg2)
60 | handler.sendMessageDelayed(msg3, 10)
61 | handler.sendMessageDelayed(msg4, 100)
62 | //handler.removeMessages(1)
63 | //handler.removeCallbacksAndMessages(token)
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/android/os/Looper.java:
--------------------------------------------------------------------------------
1 | package android.os;
2 |
3 | public final class Looper {
4 |
5 | private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
6 |
7 | private static Looper sMainLooper;
8 |
9 | private MessageQueue messageQueue;
10 |
11 | public static void prepare() {
12 | if (THREAD_LOCAL.get() != null) {
13 | throw new RuntimeException("Only one Looper may be created per thread");
14 | }
15 | THREAD_LOCAL.set(new Looper());
16 | }
17 |
18 | public static void prepareMainLooper() {
19 | prepare();
20 | synchronized (Looper.class) {
21 | if (sMainLooper != null) {
22 | throw new IllegalStateException("The main Looper has already been prepared.");
23 | }
24 | sMainLooper = myLooper();
25 | }
26 | }
27 |
28 | public static Looper getMainLooper() {
29 | synchronized (Looper.class) {
30 | return sMainLooper;
31 | }
32 | }
33 |
34 | public static Looper myLooper() {
35 | return THREAD_LOCAL.get();
36 | }
37 |
38 | private Looper() {
39 | messageQueue = new MessageQueue();
40 | }
41 |
42 | public MessageQueue getQueue() {
43 | return messageQueue;
44 | }
45 |
46 | public static void loop() {
47 | Looper me = myLooper();
48 | if (me == null) {
49 | throw new RuntimeException("No looper");
50 | }
51 | MessageQueue queue = me.messageQueue;
52 | while(true) {
53 | Message msg = queue.next();
54 | if (msg == null) {
55 | return;
56 | }
57 | msg.target.dispatchMessage(msg);
58 | msg.recycleUnchecked();
59 | }
60 | }
61 |
62 | public void quit(){
63 | messageQueue.quit(false);
64 | }
65 |
66 | public void quitSafely() {
67 | messageQueue.quit(true);
68 | }
69 | }
--------------------------------------------------------------------------------
/src/main/java/android/os/utils/Logger.java:
--------------------------------------------------------------------------------
1 | package android.os.utils;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 |
6 | public class Logger {
7 | private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
8 |
9 | private static final boolean DEBUG;
10 |
11 | static {
12 | boolean isDebug = false;
13 | try {
14 | isDebug = Logger.class.getClassLoader().getResource("logger/debug") != null;
15 | } catch (Exception e) {
16 | e.printStackTrace();
17 | }
18 | DEBUG = isDebug;
19 | }
20 |
21 | public static void debug(Object msg, Object ... args){
22 | if(DEBUG){
23 | StackTraceElement ste = new Throwable().getStackTrace()[1];
24 | StringBuilder sb = new StringBuilder();
25 | sb.append(SIMPLE_DATE_FORMAT.format(new Date())).append(" [").append(Thread.currentThread().getName()).append("] ")
26 | .append(build(String.format(String.valueOf(msg), args),ste));
27 | System.out.println(sb);
28 | }
29 | }
30 |
31 | private static String build(String log, StackTraceElement ste) {
32 | StringBuilder buf = new StringBuilder();
33 | if (ste.isNativeMethod()) {
34 | buf.append("(Native Method)");
35 | } else {
36 | String fName = ste.getFileName();
37 |
38 | if (fName == null) {
39 | buf.append("(Unknown Source)");
40 | } else {
41 | int lineNum = ste.getLineNumber();
42 | buf.append('(');
43 | buf.append(fName);
44 | if (lineNum >= 0) {
45 | buf.append(':');
46 | buf.append(lineNum);
47 | }
48 | buf.append("):");
49 | }
50 | }
51 | buf.append(log);
52 | return buf.toString();
53 | }
54 |
55 | public static void main(String... args) {
56 | debug("Output nothing.");
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/src/main/java/android/os/MessageQueue.java:
--------------------------------------------------------------------------------
1 | package android.os;
2 |
3 | import android.os.internal.DelayQueue;
4 | import android.os.utils.Logger;
5 |
6 | import java.util.function.Predicate;
7 |
8 | public class MessageQueue {
9 | private static final Message POISON = new Message();
10 |
11 | private volatile boolean isQuited = false;
12 |
13 | private DelayQueue queue = new DelayQueue<>();
14 |
15 | public void enqueueMessage(Message msg) {
16 | if(isQuited){
17 | msg.recycle();
18 | return;
19 | }
20 | queue.add(msg);
21 | msg.markInUse();
22 | }
23 |
24 | public Message next() {
25 | try {
26 | Message next = queue.take();
27 | if (next == POISON) {
28 | return null;
29 | }
30 | return next;
31 | } catch (InterruptedException e) {
32 | e.printStackTrace();
33 | }
34 | return null;
35 | }
36 |
37 | void removeMessages(Handler h, int what, Object object) {
38 | if (h == null) {
39 | return;
40 | }
41 | queue.removeIf(new Predicate() {
42 | @Override
43 | public boolean test(Message message) {
44 | boolean shouldRemove = message.target == h && message.what == what && (object == null || message.obj == object);
45 | if(shouldRemove){
46 | message.recycleUnchecked();
47 | }
48 | return shouldRemove;
49 | }
50 | });
51 | }
52 |
53 | void removeMessages(Handler h, Runnable r, Object object) {
54 | if (h == null || r == null) {
55 | return;
56 | }
57 | queue.removeIf(new Predicate() {
58 | @Override
59 | public boolean test(Message message) {
60 | boolean shouldRemove = message.target == h && message.callback == r && (object == null || message.obj == object);
61 | if(shouldRemove){
62 | message.recycleUnchecked();
63 | }
64 | return shouldRemove;
65 | }
66 | });
67 | }
68 |
69 | void removeCallbacksAndMessages(Handler h, Object object) {
70 | if (h == null) {
71 | return;
72 | }
73 |
74 | queue.removeIf(new Predicate() {
75 | @Override
76 | public boolean test(Message message) {
77 | boolean shouldRemove = message.target == h && (object == null || message.obj == object);
78 | if(shouldRemove){
79 | message.recycleUnchecked();
80 | }
81 | return shouldRemove;
82 | }
83 | });
84 | }
85 |
86 | void quit(boolean safe) {
87 | if (isQuited) return;
88 | isQuited = true;
89 | Logger.debug("Quit, messages in queue: " + queue.size());
90 | if (!safe) {
91 | queue.clear();
92 | }
93 | // Tell looper to quit.
94 | POISON.when = System.currentTimeMillis();
95 | POISON.who = "KILLER";
96 | Logger.debug("Feed poison: %s", POISON);
97 | queue.offer(POISON);
98 | }
99 | }
--------------------------------------------------------------------------------
/src/main/java/android/os/Handler.java:
--------------------------------------------------------------------------------
1 | package android.os;
2 |
3 | public class Handler {
4 | private MessageQueue mQueue;
5 | private Callback mCallback;
6 |
7 | public Handler() {
8 | this(Looper.myLooper());
9 | }
10 |
11 | public Handler(Looper looper) {
12 | this(looper, null);
13 | }
14 |
15 | public Handler(Looper looper, Callback callback) {
16 | this.mQueue = looper.getQueue();
17 | this.mCallback = callback;
18 | }
19 |
20 | public final void sendMessage(Message msg) {
21 | sendMessageDelayed(msg, 0L);
22 | }
23 |
24 | public final void sendMessageDelayed(Message msg, long delay) {
25 | msg.target = this;
26 | delay = Math.max(delay, 0L);
27 | msg.when = System.currentTimeMillis() + delay;
28 | mQueue.enqueueMessage(msg);
29 | }
30 |
31 | public final void post(Runnable r) {
32 | postDelayed(r, 0L);
33 | }
34 |
35 | public final void postDelayed(Runnable r, long delay) {
36 | Message msg = new Message();
37 | msg.callback = r;
38 | sendMessageDelayed(msg, delay);
39 | }
40 |
41 | public void handleMessage(Message msg) {
42 |
43 | }
44 |
45 | private void handleCallback(Message msg) {
46 | msg.callback.run();
47 | }
48 |
49 | public final void dispatchMessage(Message msg) {
50 | if (msg.callback != null) {
51 | handleCallback(msg);
52 | } else {
53 | if (mCallback != null) {
54 | if (mCallback.handleMessage(msg)) {
55 | return;
56 | }
57 | }
58 | handleMessage(msg);
59 | }
60 | }
61 |
62 | /**
63 | * Remove any pending posts of messages with code 'what' that are in the
64 | * message queue.
65 | */
66 | public final void removeMessages(int what) {
67 | mQueue.removeMessages(this, what, null);
68 | }
69 |
70 | /**
71 | * Remove any pending posts of messages with code 'what' and whose obj is
72 | * 'object' that are in the message queue. If object is null,
73 | * all messages will be removed.
74 | */
75 | public final void removeMessages(int what, Object object) {
76 | mQueue.removeMessages(this, what, object);
77 | }
78 |
79 | /**
80 | * Remove any pending posts of callbacks and sent messages whose
81 | * obj is token. If token is null,
82 | * all callbacks and messages will be removed.
83 | */
84 | public final void removeCallbacksAndMessages(Object token) {
85 | mQueue.removeCallbacksAndMessages(this, token);
86 | }
87 |
88 | /**
89 | * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
90 | * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
91 | * If you don't want that facility, just call Message.obtain() instead.
92 | */
93 | public final Message obtainMessage()
94 | {
95 | return Message.obtain(this);
96 | }
97 |
98 | /**
99 | * Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
100 | *
101 | * @param what Value to assign to the returned Message.what field.
102 | * @return A Message from the global message pool.
103 | */
104 | public final Message obtainMessage(int what)
105 | {
106 | return Message.obtain(this, what);
107 | }
108 |
109 | /**
110 | *
111 | * Same as {@link #obtainMessage()}, except that it also sets the what and obj members
112 | * of the returned Message.
113 | *
114 | * @param what Value to assign to the returned Message.what field.
115 | * @param obj Value to assign to the returned Message.obj field.
116 | * @return A Message from the global message pool.
117 | */
118 | public final Message obtainMessage(int what, Object obj)
119 | {
120 | return Message.obtain(this, what, obj);
121 | }
122 |
123 | /**
124 | *
125 | * Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned
126 | * Message.
127 | * @param what Value to assign to the returned Message.what field.
128 | * @param arg1 Value to assign to the returned Message.arg1 field.
129 | * @param arg2 Value to assign to the returned Message.arg2 field.
130 | * @return A Message from the global message pool.
131 | */
132 | public final Message obtainMessage(int what, int arg1, int arg2)
133 | {
134 | return Message.obtain(this, what, arg1, arg2);
135 | }
136 |
137 | /**
138 | *
139 | * Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the
140 | * returned Message.
141 | * @param what Value to assign to the returned Message.what field.
142 | * @param arg1 Value to assign to the returned Message.arg1 field.
143 | * @param arg2 Value to assign to the returned Message.arg2 field.
144 | * @param obj Value to assign to the returned Message.obj field.
145 | * @return A Message from the global message pool.
146 | */
147 | public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
148 | {
149 | return Message.obtain(this, what, arg1, arg2, obj);
150 | }
151 |
152 | /**
153 | * Callback interface you can use when instantiating a Handler to avoid
154 | * having to implement your own subclass of Handler.
155 | */
156 | public interface Callback {
157 | /**
158 | * @param msg A {@link android.os.Message Message} object
159 | * @return True if no further handling is desired
160 | */
161 | public boolean handleMessage(Message msg);
162 | }
163 | }
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/src/main/java/android/os/Message.java:
--------------------------------------------------------------------------------
1 | package android.os;
2 |
3 | import android.os.internal.Delayed;
4 |
5 | import java.text.DateFormat;
6 | import java.text.SimpleDateFormat;
7 | import java.util.Date;
8 | import java.util.LinkedList;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | public final class Message implements Delayed {
12 |
13 | private static final DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
14 |
15 | private static final Object sPoolSync = new Object();
16 |
17 | /*package*/ static final int FLAG_IN_USE = 1 << 0;
18 |
19 | /** Flags to clear in the copyFrom method */
20 | /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
21 |
22 | /*package*/ int flags;
23 |
24 | private static LinkedList sPool = new LinkedList<>();
25 | private static final int MAX_POOL_SIZE = 50;
26 |
27 | Handler target;
28 | public int what;
29 | public int arg1;
30 | public int arg2;
31 | public Object obj;
32 |
33 | long when;
34 |
35 | /**
36 | * for TEST
37 | */
38 | String who;
39 |
40 | Runnable callback;
41 |
42 | /**
43 | * Return the targeted delivery time of this message, in milliseconds.
44 | */
45 | public long getWhen() {
46 | return when;
47 | }
48 |
49 | public void setTarget(Handler target) {
50 | this.target = target;
51 | }
52 |
53 | /**
54 | * Retrieve the a {@link android.os.Handler Handler} implementation that
55 | * will receive this message. The object must implement
56 | * {@link android.os.Handler#handleMessage(android.os.Message)
57 | * Handler.handleMessage()}. Each Handler has its own name-space for
58 | * message codes, so you do not need to
59 | * worry about yours conflicting with other handlers.
60 | */
61 | public Handler getTarget() {
62 | return target;
63 | }
64 |
65 | /**
66 | * Retrieve callback object that will execute when this message is handled.
67 | * This object must implement Runnable. This is called by
68 | * the target {@link Handler} that is receiving this Message to
69 | * dispatch it. If
70 | * not set, the message will be dispatched to the receiving Handler's
71 | * {@link Handler#handleMessage(Message)}.
72 | */
73 | public Runnable getCallback() {
74 | return callback;
75 | }
76 |
77 | /**
78 | * Sends this Message to the Handler specified by {@link #getTarget}.
79 | * Throws a null pointer exception if this field has not been set.
80 | */
81 | public void sendToTarget() {
82 | target.sendMessage(this);
83 | }
84 |
85 | /*package*/ void markInUse() {
86 | flags |= FLAG_IN_USE;
87 | }
88 |
89 | /*package*/ boolean isInUse() {
90 | return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
91 | }
92 |
93 | /**
94 | * Make this message like o. Performs a shallow copy of the data field.
95 | * Does not copy the linked list fields, nor the timestamp or
96 | * target/callback of the original message.
97 | */
98 | public void copyFrom(Message o) {
99 | this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM;
100 | this.what = o.what;
101 | this.arg1 = o.arg1;
102 | this.arg2 = o.arg2;
103 | this.obj = o.obj;
104 | }
105 |
106 | /**
107 | * Return a Message instance to the global pool.
108 | *
109 | * You MUST NOT touch the Message after calling this function because it has
110 | * effectively been freed. It is an error to recycle a message that is currently
111 | * enqueued or that is in the process of being delivered to a Handler.
112 | *
113 | */
114 | public void recycle() {
115 | if (isInUse()) {
116 | throw new IllegalStateException("This message cannot be recycled because it "
117 | + "is still in use.");
118 | }
119 | recycleUnchecked();
120 | }
121 |
122 | /**
123 | * Recycles a Message that may be in-use.
124 | * Used internally by the MessageQueue and Looper when disposing of queued Messages.
125 | */
126 | void recycleUnchecked() {
127 | // Mark the message as in use while it remains in the recycled object pool.
128 | // Clear out all other details.
129 | flags = FLAG_IN_USE;
130 | what = 0;
131 | arg1 = 0;
132 | arg2 = 0;
133 | obj = null;
134 | when = 0;
135 | target = null;
136 | callback = null;
137 |
138 | synchronized (sPoolSync) {
139 | if (sPool.size() < MAX_POOL_SIZE) {
140 | sPool.addLast(this);
141 | }
142 | }
143 | }
144 |
145 | /**
146 | * Return a new Message instance from the global pool. Allows us to
147 | * avoid allocating new objects in many cases.
148 | */
149 | public static Message obtain() {
150 | synchronized (sPoolSync) {
151 | if (!sPool.isEmpty()) {
152 | Message m = sPool.removeFirst();
153 | m.flags = 0; // clear in-use flag
154 | return m;
155 | }
156 | }
157 | return new Message();
158 | }
159 |
160 | /**
161 | * Same as {@link #obtain()}, but copies the values of an existing
162 | * message (including its target) into the new one.
163 | * @param orig Original message to copy.
164 | * @return A Message object from the global pool.
165 | */
166 | public static Message obtain(Message orig) {
167 | Message m = obtain();
168 | m.what = orig.what;
169 | m.arg1 = orig.arg1;
170 | m.arg2 = orig.arg2;
171 | m.obj = orig.obj;
172 | m.target = orig.target;
173 | m.callback = orig.callback;
174 |
175 | return m;
176 | }
177 |
178 | /**
179 | * Same as {@link #obtain()}, but sets the value for the target member on the Message returned.
180 | * @param h Handler to assign to the returned Message object's target member.
181 | * @return A Message object from the global pool.
182 | */
183 | public static Message obtain(Handler h) {
184 | Message m = obtain();
185 | m.target = h;
186 |
187 | return m;
188 | }
189 |
190 | /**
191 | * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on
192 | * the Message that is returned.
193 | * @param h Handler to assign to the returned Message object's target member.
194 | * @param callback Runnable that will execute when the message is handled.
195 | * @return A Message object from the global pool.
196 | */
197 | public static Message obtain(Handler h, Runnable callback) {
198 | Message m = obtain();
199 | m.target = h;
200 | m.callback = callback;
201 |
202 | return m;
203 | }
204 |
205 | /**
206 | * Same as {@link #obtain()}, but sets the values for both target and
207 | * what members on the Message.
208 | * @param h Value to assign to the target member.
209 | * @param what Value to assign to the what member.
210 | * @return A Message object from the global pool.
211 | */
212 | public static Message obtain(Handler h, int what) {
213 | Message m = obtain();
214 | m.target = h;
215 | m.what = what;
216 |
217 | return m;
218 | }
219 |
220 | /**
221 | * Same as {@link #obtain()}, but sets the values of the target, what, and obj
222 | * members.
223 | * @param h The target value to set.
224 | * @param what The what value to set.
225 | * @param obj The object method to set.
226 | * @return A Message object from the global pool.
227 | */
228 | public static Message obtain(Handler h, int what, Object obj) {
229 | Message m = obtain();
230 | m.target = h;
231 | m.what = what;
232 | m.obj = obj;
233 |
234 | return m;
235 | }
236 |
237 | /**
238 | * Same as {@link #obtain()}, but sets the values of the target, what,
239 | * arg1, and arg2 members.
240 | *
241 | * @param h The target value to set.
242 | * @param what The what value to set.
243 | * @param arg1 The arg1 value to set.
244 | * @param arg2 The arg2 value to set.
245 | * @return A Message object from the global pool.
246 | */
247 | public static Message obtain(Handler h, int what, int arg1, int arg2) {
248 | Message m = obtain();
249 | m.target = h;
250 | m.what = what;
251 | m.arg1 = arg1;
252 | m.arg2 = arg2;
253 |
254 | return m;
255 | }
256 |
257 | /**
258 | * Same as {@link #obtain()}, but sets the values of the target, what,
259 | * arg1, arg2, and obj members.
260 | *
261 | * @param h The target value to set.
262 | * @param what The what value to set.
263 | * @param arg1 The arg1 value to set.
264 | * @param arg2 The arg2 value to set.
265 | * @param obj The obj value to set.
266 | * @return A Message object from the global pool.
267 | */
268 | public static Message obtain(Handler h, int what,
269 | int arg1, int arg2, Object obj) {
270 | Message m = obtain();
271 | m.target = h;
272 | m.what = what;
273 | m.arg1 = arg1;
274 | m.arg2 = arg2;
275 | m.obj = obj;
276 |
277 | return m;
278 | }
279 |
280 | @Override
281 | public long getDelay(TimeUnit unit) {
282 | return unit.convert(when - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
283 | }
284 |
285 | @Override
286 | public int compareTo(Delayed o) {
287 | if (o instanceof Message) {
288 | return (int) (when - ((Message) o).when);
289 | } else {
290 | return (int) (getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
291 | }
292 | }
293 |
294 | @Override
295 | public String toString() {
296 | return "Message[" + who + "]{" +
297 | "what=" + what +
298 | ", obj=" + obj +
299 | ", when=" + dateFormat.format(new Date(when)) +
300 | '}';
301 | }
302 | }
--------------------------------------------------------------------------------
/src/main/java/android/os/internal/DelayQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
3 | *
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | */
24 |
25 | /*
26 | *
27 | *
28 | *
29 | *
30 | *
31 | * Written by Doug Lea with assistance from members of JCP JSR-166
32 | * Expert Group and released to the public domain, as explained at
33 | * http://creativecommons.org/publicdomain/zero/1.0/
34 | */
35 |
36 | package android.os.internal;
37 |
38 | import java.util.AbstractQueue;
39 | import java.util.Collection;
40 | import java.util.Iterator;
41 | import java.util.NoSuchElementException;
42 | import java.util.Objects;
43 | import java.util.concurrent.BlockingQueue;
44 | import java.util.concurrent.TimeUnit;
45 | import java.util.concurrent.locks.Condition;
46 | import java.util.concurrent.locks.ReentrantLock;
47 | import java.util.function.Predicate;
48 |
49 | import static java.util.concurrent.TimeUnit.NANOSECONDS;
50 |
51 | /**
52 | * An unbounded {@linkplain BlockingQueue blocking queue} of
53 | * {@code Delayed} elements, in which an element can only be taken
54 | * when its delay has expired. The head of the queue is that
55 | * {@code Delayed} element whose delay expired furthest in the
56 | * past. If no delay has expired there is no head and {@code poll}
57 | * will return {@code null}. Expiration occurs when an element's
58 | * {@code getDelay(TimeUnit.NANOSECONDS)} method returns a value less
59 | * than or equal to zero. Even though unexpired elements cannot be
60 | * removed using {@code take} or {@code poll}, they are otherwise
61 | * treated as normal elements. For example, the {@code size} method
62 | * returns the count of both expired and unexpired elements.
63 | * This queue does not permit null elements.
64 | *
65 | * This class and its iterator implement all of the
66 | * optional methods of the {@link Collection} and {@link
67 | * Iterator} interfaces. The Iterator provided in method {@link
68 | * #iterator()} is not guaranteed to traverse the elements of
69 | * the DelayQueue in any particular order.
70 | *
71 | *
This class is a member of the
72 | *
73 | * Java Collections Framework.
74 | *
75 | * @since 1.5
76 | * @author Doug Lea
77 | * @param the type of elements held in this collection
78 | */
79 | public class DelayQueue extends AbstractQueue
80 | implements BlockingQueue {
81 |
82 | private final transient ReentrantLock lock = new ReentrantLock();
83 | private final PriorityQueue q = new PriorityQueue();
84 |
85 | /**
86 | * Thread designated to wait for the element at the head of
87 | * the queue. This variant of the Leader-Follower pattern
88 | * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
89 | * minimize unnecessary timed waiting. When a thread becomes
90 | * the leader, it waits only for the next delay to elapse, but
91 | * other threads await indefinitely. The leader thread must
92 | * signal some other thread before returning from take() or
93 | * poll(...), unless some other thread becomes leader in the
94 | * interim. Whenever the head of the queue is replaced with
95 | * an element with an earlier expiration time, the leader
96 | * field is invalidated by being reset to null, and some
97 | * waiting thread, but not necessarily the current leader, is
98 | * signalled. So waiting threads must be prepared to acquire
99 | * and lose leadership while waiting.
100 | */
101 | private Thread leader = null;
102 |
103 | /**
104 | * Condition signalled when a newer element becomes available
105 | * at the head of the queue or a new thread may need to
106 | * become leader.
107 | */
108 | private final Condition available = lock.newCondition();
109 |
110 | /**
111 | * Creates a new {@code DelayQueue} that is initially empty.
112 | */
113 | public DelayQueue() {}
114 |
115 | /**
116 | * Creates a {@code DelayQueue} initially containing the elements of the
117 | * given collection of {@link Delayed} instances.
118 | *
119 | * @param c the collection of elements to initially contain
120 | * @throws NullPointerException if the specified collection or any
121 | * of its elements are null
122 | */
123 | public DelayQueue(Collection extends E> c) {
124 | this.addAll(c);
125 | }
126 |
127 | /**
128 | * Inserts the specified element into this delay queue.
129 | *
130 | * @param e the element to add
131 | * @return {@code true} (as specified by {@link Collection#add})
132 | * @throws NullPointerException if the specified element is null
133 | */
134 | public boolean add(E e) {
135 | return offer(e);
136 | }
137 |
138 | /**
139 | * Inserts the specified element into this delay queue.
140 | *
141 | * @param e the element to add
142 | * @return {@code true}
143 | * @throws NullPointerException if the specified element is null
144 | */
145 | public boolean offer(E e) {
146 | final ReentrantLock lock = this.lock;
147 | lock.lock();
148 | try {
149 | q.offer(e);
150 | if (q.peek() == e) {
151 | leader = null;
152 | available.signal();
153 | }
154 | return true;
155 | } finally {
156 | lock.unlock();
157 | }
158 | }
159 |
160 | /**
161 | * Inserts the specified element into this delay queue. As the queue is
162 | * unbounded this method will never block.
163 | *
164 | * @param e the element to add
165 | * @throws NullPointerException {@inheritDoc}
166 | */
167 | public void put(E e) {
168 | offer(e);
169 | }
170 |
171 | /**
172 | * Inserts the specified element into this delay queue. As the queue is
173 | * unbounded this method will never block.
174 | *
175 | * @param e the element to add
176 | * @param timeout This parameter is ignored as the method never blocks
177 | * @param unit This parameter is ignored as the method never blocks
178 | * @return {@code true}
179 | * @throws NullPointerException {@inheritDoc}
180 | */
181 | public boolean offer(E e, long timeout, TimeUnit unit) {
182 | return offer(e);
183 | }
184 |
185 | /**
186 | * Retrieves and removes the head of this queue, or returns {@code null}
187 | * if this queue has no elements with an expired delay.
188 | *
189 | * @return the head of this queue, or {@code null} if this
190 | * queue has no elements with an expired delay
191 | */
192 | public E poll() {
193 | final ReentrantLock lock = this.lock;
194 | lock.lock();
195 | try {
196 | E first = q.peek();
197 | if (first == null || first.getDelay(NANOSECONDS) > 0)
198 | return null;
199 | else
200 | return q.poll();
201 | } finally {
202 | lock.unlock();
203 | }
204 | }
205 |
206 | /**
207 | * Retrieves and removes the head of this queue, waiting if necessary
208 | * until an element with an expired delay is available on this queue.
209 | *
210 | * @return the head of this queue
211 | * @throws InterruptedException {@inheritDoc}
212 | */
213 | public E take() throws InterruptedException {
214 | final ReentrantLock lock = this.lock;
215 | lock.lockInterruptibly();
216 | try {
217 | for (;;) {
218 | E first = q.peek();
219 | if (first == null)
220 | available.await();
221 | else {
222 | long delay = first.getDelay(NANOSECONDS);
223 | if (delay <= 0)
224 | return q.poll();
225 | first = null; // don't retain ref while waiting
226 | if (leader != null)
227 | available.await();
228 | else {
229 | Thread thisThread = Thread.currentThread();
230 | leader = thisThread;
231 | try {
232 | available.awaitNanos(delay);
233 | } finally {
234 | if (leader == thisThread)
235 | leader = null;
236 | }
237 | }
238 | }
239 | }
240 | } finally {
241 | if (leader == null && q.peek() != null)
242 | available.signal();
243 | lock.unlock();
244 | }
245 | }
246 |
247 | /**
248 | * Retrieves and removes the head of this queue, waiting if necessary
249 | * until an element with an expired delay is available on this queue,
250 | * or the specified wait time expires.
251 | *
252 | * @return the head of this queue, or {@code null} if the
253 | * specified waiting time elapses before an element with
254 | * an expired delay becomes available
255 | * @throws InterruptedException {@inheritDoc}
256 | */
257 | public E poll(long timeout, TimeUnit unit) throws InterruptedException {
258 | long nanos = unit.toNanos(timeout);
259 | final ReentrantLock lock = this.lock;
260 | lock.lockInterruptibly();
261 | try {
262 | for (;;) {
263 | E first = q.peek();
264 | if (first == null) {
265 | if (nanos <= 0)
266 | return null;
267 | else
268 | nanos = available.awaitNanos(nanos);
269 | } else {
270 | long delay = first.getDelay(NANOSECONDS);
271 | if (delay <= 0)
272 | return q.poll();
273 | if (nanos <= 0)
274 | return null;
275 | first = null; // don't retain ref while waiting
276 | if (nanos < delay || leader != null)
277 | nanos = available.awaitNanos(nanos);
278 | else {
279 | Thread thisThread = Thread.currentThread();
280 | leader = thisThread;
281 | try {
282 | long timeLeft = available.awaitNanos(delay);
283 | nanos -= delay - timeLeft;
284 | } finally {
285 | if (leader == thisThread)
286 | leader = null;
287 | }
288 | }
289 | }
290 | }
291 | } finally {
292 | if (leader == null && q.peek() != null)
293 | available.signal();
294 | lock.unlock();
295 | }
296 | }
297 |
298 | /**
299 | * Retrieves, but does not remove, the head of this queue, or
300 | * returns {@code null} if this queue is empty. Unlike
301 | * {@code poll}, if no expired elements are available in the queue,
302 | * this method returns the element that will expire next,
303 | * if one exists.
304 | *
305 | * @return the head of this queue, or {@code null} if this
306 | * queue is empty
307 | */
308 | public E peek() {
309 | final ReentrantLock lock = this.lock;
310 | lock.lock();
311 | try {
312 | return q.peek();
313 | } finally {
314 | lock.unlock();
315 | }
316 | }
317 |
318 | public int size() {
319 | final ReentrantLock lock = this.lock;
320 | lock.lock();
321 | try {
322 | return q.size();
323 | } finally {
324 | lock.unlock();
325 | }
326 | }
327 |
328 | /**
329 | * Returns first element only if it is expired.
330 | * Used only by drainTo. Call only when holding lock.
331 | */
332 | private E peekExpired() {
333 | // assert lock.isHeldByCurrentThread();
334 | E first = q.peek();
335 | return (first == null || first.getDelay(NANOSECONDS) > 0) ?
336 | null : first;
337 | }
338 |
339 | /**
340 | * @throws UnsupportedOperationException {@inheritDoc}
341 | * @throws ClassCastException {@inheritDoc}
342 | * @throws NullPointerException {@inheritDoc}
343 | * @throws IllegalArgumentException {@inheritDoc}
344 | */
345 | public int drainTo(Collection super E> c) {
346 | if (c == null)
347 | throw new NullPointerException();
348 | if (c == this)
349 | throw new IllegalArgumentException();
350 | final ReentrantLock lock = this.lock;
351 | lock.lock();
352 | try {
353 | int n = 0;
354 | for (E e; (e = peekExpired()) != null;) {
355 | c.add(e); // In this order, in case add() throws.
356 | q.poll();
357 | ++n;
358 | }
359 | return n;
360 | } finally {
361 | lock.unlock();
362 | }
363 | }
364 |
365 | /**
366 | * @throws UnsupportedOperationException {@inheritDoc}
367 | * @throws ClassCastException {@inheritDoc}
368 | * @throws NullPointerException {@inheritDoc}
369 | * @throws IllegalArgumentException {@inheritDoc}
370 | */
371 | public int drainTo(Collection super E> c, int maxElements) {
372 | if (c == null)
373 | throw new NullPointerException();
374 | if (c == this)
375 | throw new IllegalArgumentException();
376 | if (maxElements <= 0)
377 | return 0;
378 | final ReentrantLock lock = this.lock;
379 | lock.lock();
380 | try {
381 | int n = 0;
382 | for (E e; n < maxElements && (e = peekExpired()) != null;) {
383 | c.add(e); // In this order, in case add() throws.
384 | q.poll();
385 | ++n;
386 | }
387 | return n;
388 | } finally {
389 | lock.unlock();
390 | }
391 | }
392 |
393 | /**
394 | * Atomically removes all of the elements from this delay queue.
395 | * The queue will be empty after this call returns.
396 | * Elements with an unexpired delay are not waited for; they are
397 | * simply discarded from the queue.
398 | */
399 | public void clear() {
400 | final ReentrantLock lock = this.lock;
401 | lock.lock();
402 | try {
403 | q.clear();
404 | } finally {
405 | lock.unlock();
406 | }
407 | }
408 |
409 | /**
410 | * Always returns {@code Integer.MAX_VALUE} because
411 | * a {@code DelayQueue} is not capacity constrained.
412 | *
413 | * @return {@code Integer.MAX_VALUE}
414 | */
415 | public int remainingCapacity() {
416 | return Integer.MAX_VALUE;
417 | }
418 |
419 | /**
420 | * Returns an array containing all of the elements in this queue.
421 | * The returned array elements are in no particular order.
422 | *
423 | * The returned array will be "safe" in that no references to it are
424 | * maintained by this queue. (In other words, this method must allocate
425 | * a new array). The caller is thus free to modify the returned array.
426 | *
427 | *
This method acts as bridge between array-based and collection-based
428 | * APIs.
429 | *
430 | * @return an array containing all of the elements in this queue
431 | */
432 | public Object[] toArray() {
433 | final ReentrantLock lock = this.lock;
434 | lock.lock();
435 | try {
436 | return q.toArray();
437 | } finally {
438 | lock.unlock();
439 | }
440 | }
441 |
442 | /**
443 | * Returns an array containing all of the elements in this queue; the
444 | * runtime type of the returned array is that of the specified array.
445 | * The returned array elements are in no particular order.
446 | * If the queue fits in the specified array, it is returned therein.
447 | * Otherwise, a new array is allocated with the runtime type of the
448 | * specified array and the size of this queue.
449 | *
450 | *
If this queue fits in the specified array with room to spare
451 | * (i.e., the array has more elements than this queue), the element in
452 | * the array immediately following the end of the queue is set to
453 | * {@code null}.
454 | *
455 | *
Like the {@link #toArray()} method, this method acts as bridge between
456 | * array-based and collection-based APIs. Further, this method allows
457 | * precise control over the runtime type of the output array, and may,
458 | * under certain circumstances, be used to save allocation costs.
459 | *
460 | *
The following code can be used to dump a delay queue into a newly
461 | * allocated array of {@code Delayed}:
462 | *
463 | *
{@code Delayed[] a = q.toArray(new Delayed[0]);}
464 | *
465 | * Note that {@code toArray(new Object[0])} is identical in function to
466 | * {@code toArray()}.
467 | *
468 | * @param a the array into which the elements of the queue are to
469 | * be stored, if it is big enough; otherwise, a new array of the
470 | * same runtime type is allocated for this purpose
471 | * @return an array containing all of the elements in this queue
472 | * @throws ArrayStoreException if the runtime type of the specified array
473 | * is not a supertype of the runtime type of every element in
474 | * this queue
475 | * @throws NullPointerException if the specified array is null
476 | */
477 | public T[] toArray(T[] a) {
478 | final ReentrantLock lock = this.lock;
479 | lock.lock();
480 | try {
481 | return q.toArray(a);
482 | } finally {
483 | lock.unlock();
484 | }
485 | }
486 |
487 | /**
488 | * Removes a single instance of the specified element from this
489 | * queue, if it is present, whether or not it has expired.
490 | */
491 | public boolean remove(Object o) {
492 | final ReentrantLock lock = this.lock;
493 | lock.lock();
494 | try {
495 | return q.remove(o);
496 | } finally {
497 | lock.unlock();
498 | }
499 | }
500 |
501 | @Override
502 | public boolean removeIf(Predicate super E> filter) {
503 | Objects.requireNonNull(filter);
504 | final ReentrantLock lock = this.lock;
505 | lock.lock();
506 | try {
507 | boolean removed = false;
508 | final Iterator each = q.iterator();
509 | while (each.hasNext()) {
510 | if (filter.test(each.next())) {
511 | each.remove();
512 | removed = true;
513 | }
514 | }
515 | return removed;
516 | } finally {
517 | lock.unlock();
518 | }
519 | }
520 |
521 | /**
522 | * Identity-based version for use in Itr.remove
523 | */
524 | void removeEQ(Object o) {
525 | final ReentrantLock lock = this.lock;
526 | lock.lock();
527 | try {
528 | for (Iterator it = q.iterator(); it.hasNext(); ) {
529 | if (o == it.next()) {
530 | it.remove();
531 | break;
532 | }
533 | }
534 | } finally {
535 | lock.unlock();
536 | }
537 | }
538 |
539 | /**
540 | * Returns an iterator over all the elements (both expired and
541 | * unexpired) in this queue. The iterator does not return the
542 | * elements in any particular order.
543 | *
544 | * The returned iterator is
545 | * weakly consistent.
546 | *
547 | * @return an iterator over the elements in this queue
548 | */
549 | public Iterator iterator() {
550 | return new Itr(toArray());
551 | }
552 |
553 | /**
554 | * Snapshot iterator that works off copy of underlying q array.
555 | */
556 | private class Itr implements Iterator {
557 | final Object[] array; // Array of all elements
558 | int cursor; // index of next element to return
559 | int lastRet; // index of last element, or -1 if no such
560 |
561 | Itr(Object[] array) {
562 | lastRet = -1;
563 | this.array = array;
564 | }
565 |
566 | public boolean hasNext() {
567 | return cursor < array.length;
568 | }
569 |
570 | @SuppressWarnings("unchecked")
571 | public E next() {
572 | if (cursor >= array.length)
573 | throw new NoSuchElementException();
574 | lastRet = cursor;
575 | return (E)array[cursor++];
576 | }
577 |
578 | public void remove() {
579 | if (lastRet < 0)
580 | throw new IllegalStateException();
581 | removeEQ(array[lastRet]);
582 | lastRet = -1;
583 | }
584 | }
585 |
586 | }
587 |
--------------------------------------------------------------------------------
/src/main/java/android/os/internal/PriorityQueue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 | *
5 | *
6 | *
7 | *
8 | *
9 | *
10 | *
11 | *
12 | *
13 | *
14 | *
15 | *
16 | *
17 | *
18 | *
19 | *
20 | *
21 | *
22 | *
23 | *
24 | */
25 |
26 | package android.os.internal;
27 |
28 | import java.util.AbstractQueue;
29 | import java.util.ArrayDeque;
30 | import java.util.Arrays;
31 | import java.util.Collection;
32 | import java.util.Comparator;
33 | import java.util.ConcurrentModificationException;
34 | import java.util.Iterator;
35 | import java.util.NoSuchElementException;
36 | import java.util.Queue;
37 | import java.util.SortedSet;
38 | import java.util.Spliterator;
39 | import java.util.function.Consumer;
40 |
41 | /**
42 | * An unbounded priority {@linkplain Queue queue} based on a priority heap.
43 | * The elements of the priority queue are ordered according to their
44 | * {@linkplain Comparable natural ordering}, or by a {@link Comparator}
45 | * provided at queue construction time, depending on which constructor is
46 | * used. A priority queue does not permit {@code null} elements.
47 | * A priority queue relying on natural ordering also does not permit
48 | * insertion of non-comparable objects (doing so may result in
49 | * {@code ClassCastException}).
50 | *
51 | * The head of this queue is the least element
52 | * with respect to the specified ordering. If multiple elements are
53 | * tied for least value, the head is one of those elements -- ties are
54 | * broken arbitrarily. The queue retrieval operations {@code poll},
55 | * {@code remove}, {@code peek}, and {@code element} access the
56 | * element at the head of the queue.
57 | *
58 | *
A priority queue is unbounded, but has an internal
59 | * capacity governing the size of an array used to store the
60 | * elements on the queue. It is always at least as large as the queue
61 | * size. As elements are added to a priority queue, its capacity
62 | * grows automatically. The details of the growth policy are not
63 | * specified.
64 | *
65 | *
This class and its iterator implement all of the
66 | * optional methods of the {@link Collection} and {@link
67 | * Iterator} interfaces. The Iterator provided in method {@link
68 | * #iterator()} is not guaranteed to traverse the elements of
69 | * the priority queue in any particular order. If you need ordered
70 | * traversal, consider using {@code Arrays.sort(pq.toArray())}.
71 | *
72 | *
Note that this implementation is not synchronized.
73 | * Multiple threads should not access a {@code PriorityQueue}
74 | * instance concurrently if any of the threads modifies the queue.
75 | * Instead, use the thread-safe {@link
76 | * java.util.concurrent.PriorityBlockingQueue} class.
77 | *
78 | *
Implementation note: this implementation provides
79 | * O(log(n)) time for the enqueuing and dequeuing methods
80 | * ({@code offer}, {@code poll}, {@code remove()} and {@code add});
81 | * linear time for the {@code remove(Object)} and {@code contains(Object)}
82 | * methods; and constant time for the retrieval methods
83 | * ({@code peek}, {@code element}, and {@code size}).
84 | *
85 | *
This class is a member of the
86 | *
87 | * Java Collections Framework.
88 | *
89 | * @since 1.5
90 | * @author Josh Bloch, Doug Lea
91 | * @param the type of elements held in this collection
92 | */
93 | public class PriorityQueue extends AbstractQueue
94 | implements java.io.Serializable {
95 |
96 | private static final long serialVersionUID = -7720805057305804111L;
97 |
98 | private static final int DEFAULT_INITIAL_CAPACITY = 11;
99 |
100 | /**
101 | * Priority queue represented as a balanced binary heap: the two
102 | * children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
103 | * priority queue is ordered by comparator, or by the elements'
104 | * natural ordering, if comparator is null: For each node n in the
105 | * heap and each descendant d of n, n <= d. The element with the
106 | * lowest value is in queue[0], assuming the queue is nonempty.
107 | */
108 | transient Object[] queue; // non-private to simplify nested class access
109 |
110 | /**
111 | * The number of elements in the priority queue.
112 | */
113 | private int size = 0;
114 |
115 | /**
116 | * The comparator, or null if priority queue uses elements'
117 | * natural ordering.
118 | */
119 | private final Comparator super E> comparator;
120 |
121 | /**
122 | * The number of times this priority queue has been
123 | * structurally modified. See AbstractList for gory details.
124 | */
125 | transient int modCount = 0; // non-private to simplify nested class access
126 |
127 | /**
128 | * Creates a {@code PriorityQueue} with the default initial
129 | * capacity (11) that orders its elements according to their
130 | * {@linkplain Comparable natural ordering}.
131 | */
132 | public PriorityQueue() {
133 | this(DEFAULT_INITIAL_CAPACITY, null);
134 | }
135 |
136 | /**
137 | * Creates a {@code PriorityQueue} with the specified initial
138 | * capacity that orders its elements according to their
139 | * {@linkplain Comparable natural ordering}.
140 | *
141 | * @param initialCapacity the initial capacity for this priority queue
142 | * @throws IllegalArgumentException if {@code initialCapacity} is less
143 | * than 1
144 | */
145 | public PriorityQueue(int initialCapacity) {
146 | this(initialCapacity, null);
147 | }
148 |
149 | /**
150 | * Creates a {@code PriorityQueue} with the default initial capacity and
151 | * whose elements are ordered according to the specified comparator.
152 | *
153 | * @param comparator the comparator that will be used to order this
154 | * priority queue. If {@code null}, the {@linkplain Comparable
155 | * natural ordering} of the elements will be used.
156 | * @since 1.8
157 | */
158 | public PriorityQueue(Comparator super E> comparator) {
159 | this(DEFAULT_INITIAL_CAPACITY, comparator);
160 | }
161 |
162 | /**
163 | * Creates a {@code PriorityQueue} with the specified initial capacity
164 | * that orders its elements according to the specified comparator.
165 | *
166 | * @param initialCapacity the initial capacity for this priority queue
167 | * @param comparator the comparator that will be used to order this
168 | * priority queue. If {@code null}, the {@linkplain Comparable
169 | * natural ordering} of the elements will be used.
170 | * @throws IllegalArgumentException if {@code initialCapacity} is
171 | * less than 1
172 | */
173 | public PriorityQueue(int initialCapacity,
174 | Comparator super E> comparator) {
175 | // Note: This restriction of at least one is not actually needed,
176 | // but continues for 1.5 compatibility
177 | if (initialCapacity < 1)
178 | throw new IllegalArgumentException();
179 | this.queue = new Object[initialCapacity];
180 | this.comparator = comparator;
181 | }
182 |
183 | /**
184 | * Creates a {@code PriorityQueue} containing the elements in the
185 | * specified collection. If the specified collection is an instance of
186 | * a {@link SortedSet} or is another {@code PriorityQueue}, this
187 | * priority queue will be ordered according to the same ordering.
188 | * Otherwise, this priority queue will be ordered according to the
189 | * {@linkplain Comparable natural ordering} of its elements.
190 | *
191 | * @param c the collection whose elements are to be placed
192 | * into this priority queue
193 | * @throws ClassCastException if elements of the specified collection
194 | * cannot be compared to one another according to the priority
195 | * queue's ordering
196 | * @throws NullPointerException if the specified collection or any
197 | * of its elements are null
198 | */
199 | @SuppressWarnings("unchecked")
200 | public PriorityQueue(Collection extends E> c) {
201 | if (c instanceof SortedSet>) {
202 | SortedSet extends E> ss = (SortedSet extends E>) c;
203 | this.comparator = (Comparator super E>) ss.comparator();
204 | initElementsFromCollection(ss);
205 | }
206 | else if (c instanceof PriorityQueue>) {
207 | PriorityQueue extends E> pq = (PriorityQueue extends E>) c;
208 | this.comparator = (Comparator super E>) pq.comparator();
209 | initFromPriorityQueue(pq);
210 | }
211 | else {
212 | this.comparator = null;
213 | initFromCollection(c);
214 | }
215 | }
216 |
217 | /**
218 | * Creates a {@code PriorityQueue} containing the elements in the
219 | * specified priority queue. This priority queue will be
220 | * ordered according to the same ordering as the given priority
221 | * queue.
222 | *
223 | * @param c the priority queue whose elements are to be placed
224 | * into this priority queue
225 | * @throws ClassCastException if elements of {@code c} cannot be
226 | * compared to one another according to {@code c}'s
227 | * ordering
228 | * @throws NullPointerException if the specified priority queue or any
229 | * of its elements are null
230 | */
231 | @SuppressWarnings("unchecked")
232 | public PriorityQueue(PriorityQueue extends E> c) {
233 | this.comparator = (Comparator super E>) c.comparator();
234 | initFromPriorityQueue(c);
235 | }
236 |
237 | /**
238 | * Creates a {@code PriorityQueue} containing the elements in the
239 | * specified sorted set. This priority queue will be ordered
240 | * according to the same ordering as the given sorted set.
241 | *
242 | * @param c the sorted set whose elements are to be placed
243 | * into this priority queue
244 | * @throws ClassCastException if elements of the specified sorted
245 | * set cannot be compared to one another according to the
246 | * sorted set's ordering
247 | * @throws NullPointerException if the specified sorted set or any
248 | * of its elements are null
249 | */
250 | @SuppressWarnings("unchecked")
251 | public PriorityQueue(SortedSet extends E> c) {
252 | this.comparator = (Comparator super E>) c.comparator();
253 | initElementsFromCollection(c);
254 | }
255 |
256 | private void initFromPriorityQueue(PriorityQueue extends E> c) {
257 | if (c.getClass() == PriorityQueue.class) {
258 | this.queue = c.toArray();
259 | this.size = c.size();
260 | } else {
261 | initFromCollection(c);
262 | }
263 | }
264 |
265 | private void initElementsFromCollection(Collection extends E> c) {
266 | Object[] a = c.toArray();
267 | // If c.toArray incorrectly doesn't return Object[], copy it.
268 | if (a.getClass() != Object[].class)
269 | a = Arrays.copyOf(a, a.length, Object[].class);
270 | int len = a.length;
271 | if (len == 1 || this.comparator != null)
272 | for (int i = 0; i < len; i++)
273 | if (a[i] == null)
274 | throw new NullPointerException();
275 | this.queue = a;
276 | this.size = a.length;
277 | }
278 |
279 | /**
280 | * Initializes queue array with elements from the given Collection.
281 | *
282 | * @param c the collection
283 | */
284 | private void initFromCollection(Collection extends E> c) {
285 | initElementsFromCollection(c);
286 | heapify();
287 | }
288 |
289 | /**
290 | * The maximum size of array to allocate.
291 | * Some VMs reserve some header words in an array.
292 | * Attempts to allocate larger arrays may result in
293 | * OutOfMemoryError: Requested array size exceeds VM limit
294 | */
295 | private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
296 |
297 | /**
298 | * Increases the capacity of the array.
299 | *
300 | * @param minCapacity the desired minimum capacity
301 | */
302 | private void grow(int minCapacity) {
303 | int oldCapacity = queue.length;
304 | // Double size if small; else grow by 50%
305 | int newCapacity = oldCapacity + ((oldCapacity < 64) ?
306 | (oldCapacity + 2) :
307 | (oldCapacity >> 1));
308 | // overflow-conscious code
309 | if (newCapacity - MAX_ARRAY_SIZE > 0)
310 | newCapacity = hugeCapacity(minCapacity);
311 | queue = Arrays.copyOf(queue, newCapacity);
312 | }
313 |
314 | private static int hugeCapacity(int minCapacity) {
315 | if (minCapacity < 0) // overflow
316 | throw new OutOfMemoryError();
317 | return (minCapacity > MAX_ARRAY_SIZE) ?
318 | Integer.MAX_VALUE :
319 | MAX_ARRAY_SIZE;
320 | }
321 |
322 | /**
323 | * Inserts the specified element into this priority queue.
324 | *
325 | * @return {@code true} (as specified by {@link Collection#add})
326 | * @throws ClassCastException if the specified element cannot be
327 | * compared with elements currently in this priority queue
328 | * according to the priority queue's ordering
329 | * @throws NullPointerException if the specified element is null
330 | */
331 | public boolean add(E e) {
332 | return offer(e);
333 | }
334 |
335 | /**
336 | * Inserts the specified element into this priority queue.
337 | *
338 | * @return {@code true} (as specified by {@link Queue#offer})
339 | * @throws ClassCastException if the specified element cannot be
340 | * compared with elements currently in this priority queue
341 | * according to the priority queue's ordering
342 | * @throws NullPointerException if the specified element is null
343 | */
344 | public boolean offer(E e) {
345 | if (e == null)
346 | throw new NullPointerException();
347 | modCount++;
348 | int i = size;
349 | if (i >= queue.length)
350 | grow(i + 1);
351 | size = i + 1;
352 | if (i == 0)
353 | queue[0] = e;
354 | else
355 | siftUp(i, e);
356 | return true;
357 | }
358 |
359 | @SuppressWarnings("unchecked")
360 | public E peek() {
361 | return (size == 0) ? null : (E) queue[0];
362 | }
363 |
364 | private int indexOf(Object o) {
365 | if (o != null) {
366 | for (int i = 0; i < size; i++)
367 | if (o.equals(queue[i]))
368 | return i;
369 | }
370 | return -1;
371 | }
372 |
373 | /**
374 | * Removes a single instance of the specified element from this queue,
375 | * if it is present. More formally, removes an element {@code e} such
376 | * that {@code o.equals(e)}, if this queue contains one or more such
377 | * elements. Returns {@code true} if and only if this queue contained
378 | * the specified element (or equivalently, if this queue changed as a
379 | * result of the call).
380 | *
381 | * @param o element to be removed from this queue, if present
382 | * @return {@code true} if this queue changed as a result of the call
383 | */
384 | public boolean remove(Object o) {
385 | int i = indexOf(o);
386 | if (i == -1)
387 | return false;
388 | else {
389 | removeAt(i);
390 | return true;
391 | }
392 | }
393 |
394 | /**
395 | * Version of remove using reference equality, not equals.
396 | * Needed by iterator.remove.
397 | *
398 | * @param o element to be removed from this queue, if present
399 | * @return {@code true} if removed
400 | */
401 | boolean removeEq(Object o) {
402 | for (int i = 0; i < size; i++) {
403 | if (o == queue[i]) {
404 | removeAt(i);
405 | return true;
406 | }
407 | }
408 | return false;
409 | }
410 |
411 | /**
412 | * Returns {@code true} if this queue contains the specified element.
413 | * More formally, returns {@code true} if and only if this queue contains
414 | * at least one element {@code e} such that {@code o.equals(e)}.
415 | *
416 | * @param o object to be checked for containment in this queue
417 | * @return {@code true} if this queue contains the specified element
418 | */
419 | public boolean contains(Object o) {
420 | return indexOf(o) != -1;
421 | }
422 |
423 | /**
424 | * Returns an array containing all of the elements in this queue.
425 | * The elements are in no particular order.
426 | *
427 | * The returned array will be "safe" in that no references to it are
428 | * maintained by this queue. (In other words, this method must allocate
429 | * a new array). The caller is thus free to modify the returned array.
430 | *
431 | *
This method acts as bridge between array-based and collection-based
432 | * APIs.
433 | *
434 | * @return an array containing all of the elements in this queue
435 | */
436 | public Object[] toArray() {
437 | return Arrays.copyOf(queue, size);
438 | }
439 |
440 | /**
441 | * Returns an array containing all of the elements in this queue; the
442 | * runtime type of the returned array is that of the specified array.
443 | * The returned array elements are in no particular order.
444 | * If the queue fits in the specified array, it is returned therein.
445 | * Otherwise, a new array is allocated with the runtime type of the
446 | * specified array and the size of this queue.
447 | *
448 | *
If the queue fits in the specified array with room to spare
449 | * (i.e., the array has more elements than the queue), the element in
450 | * the array immediately following the end of the collection is set to
451 | * {@code null}.
452 | *
453 | *
Like the {@link #toArray()} method, this method acts as bridge between
454 | * array-based and collection-based APIs. Further, this method allows
455 | * precise control over the runtime type of the output array, and may,
456 | * under certain circumstances, be used to save allocation costs.
457 | *
458 | *
Suppose {@code x} is a queue known to contain only strings.
459 | * The following code can be used to dump the queue into a newly
460 | * allocated array of {@code String}:
461 | *
462 | *
{@code String[] y = x.toArray(new String[0]);}
463 | *
464 | * Note that {@code toArray(new Object[0])} is identical in function to
465 | * {@code toArray()}.
466 | *
467 | * @param a the array into which the elements of the queue are to
468 | * be stored, if it is big enough; otherwise, a new array of the
469 | * same runtime type is allocated for this purpose.
470 | * @return an array containing all of the elements in this queue
471 | * @throws ArrayStoreException if the runtime type of the specified array
472 | * is not a supertype of the runtime type of every element in
473 | * this queue
474 | * @throws NullPointerException if the specified array is null
475 | */
476 | @SuppressWarnings("unchecked")
477 | public T[] toArray(T[] a) {
478 | final int size = this.size;
479 | if (a.length < size)
480 | // Make a new array of a's runtime type, but my contents:
481 | return (T[]) Arrays.copyOf(queue, size, a.getClass());
482 | System.arraycopy(queue, 0, a, 0, size);
483 | if (a.length > size)
484 | a[size] = null;
485 | return a;
486 | }
487 |
488 | /**
489 | * Returns an iterator over the elements in this queue. The iterator
490 | * does not return the elements in any particular order.
491 | *
492 | * @return an iterator over the elements in this queue
493 | */
494 | public Iterator iterator() {
495 | return new Itr();
496 | }
497 |
498 | private final class Itr implements Iterator {
499 | /**
500 | * Index (into queue array) of element to be returned by
501 | * subsequent call to next.
502 | */
503 | private int cursor = 0;
504 |
505 | /**
506 | * Index of element returned by most recent call to next,
507 | * unless that element came from the forgetMeNot list.
508 | * Set to -1 if element is deleted by a call to remove.
509 | */
510 | private int lastRet = -1;
511 |
512 | /**
513 | * A queue of elements that were moved from the unvisited portion of
514 | * the heap into the visited portion as a result of "unlucky" element
515 | * removals during the iteration. (Unlucky element removals are those
516 | * that require a siftup instead of a siftdown.) We must visit all of
517 | * the elements in this list to complete the iteration. We do this
518 | * after we've completed the "normal" iteration.
519 | *
520 | * We expect that most iterations, even those involving removals,
521 | * will not need to store elements in this field.
522 | */
523 | private ArrayDeque forgetMeNot = null;
524 |
525 | /**
526 | * Element returned by the most recent call to next iff that
527 | * element was drawn from the forgetMeNot list.
528 | */
529 | private E lastRetElt = null;
530 |
531 | /**
532 | * The modCount value that the iterator believes that the backing
533 | * Queue should have. If this expectation is violated, the iterator
534 | * has detected concurrent modification.
535 | */
536 | private int expectedModCount = modCount;
537 |
538 | public boolean hasNext() {
539 | return cursor < size ||
540 | (forgetMeNot != null && !forgetMeNot.isEmpty());
541 | }
542 |
543 | @SuppressWarnings("unchecked")
544 | public E next() {
545 | if (expectedModCount != modCount)
546 | throw new ConcurrentModificationException();
547 | if (cursor < size)
548 | return (E) queue[lastRet = cursor++];
549 | if (forgetMeNot != null) {
550 | lastRet = -1;
551 | lastRetElt = forgetMeNot.poll();
552 | if (lastRetElt != null)
553 | return lastRetElt;
554 | }
555 | throw new NoSuchElementException();
556 | }
557 |
558 | public void remove() {
559 | if (expectedModCount != modCount)
560 | throw new ConcurrentModificationException();
561 | if (lastRet != -1) {
562 | E moved = PriorityQueue.this.removeAt(lastRet);
563 | lastRet = -1;
564 | if (moved == null)
565 | cursor--;
566 | else {
567 | if (forgetMeNot == null)
568 | forgetMeNot = new ArrayDeque<>();
569 | forgetMeNot.add(moved);
570 | }
571 | } else if (lastRetElt != null) {
572 | PriorityQueue.this.removeEq(lastRetElt);
573 | lastRetElt = null;
574 | } else {
575 | throw new IllegalStateException();
576 | }
577 | expectedModCount = modCount;
578 | }
579 | }
580 |
581 | public int size() {
582 | return size;
583 | }
584 |
585 | /**
586 | * Removes all of the elements from this priority queue.
587 | * The queue will be empty after this call returns.
588 | */
589 | public void clear() {
590 | modCount++;
591 | for (int i = 0; i < size; i++)
592 | queue[i] = null;
593 | size = 0;
594 | }
595 |
596 | @SuppressWarnings("unchecked")
597 | public E poll() {
598 | if (size == 0)
599 | return null;
600 | int s = --size;
601 | modCount++;
602 | E result = (E) queue[0];
603 | E x = (E) queue[s];
604 | queue[s] = null;
605 | if (s != 0)
606 | siftDown(0, x);
607 | return result;
608 | }
609 |
610 | /**
611 | * Removes the ith element from queue.
612 | *
613 | * Normally this method leaves the elements at up to i-1,
614 | * inclusive, untouched. Under these circumstances, it returns
615 | * null. Occasionally, in order to maintain the heap invariant,
616 | * it must swap a later element of the list with one earlier than
617 | * i. Under these circumstances, this method returns the element
618 | * that was previously at the end of the list and is now at some
619 | * position before i. This fact is used by iterator.remove so as to
620 | * avoid missing traversing elements.
621 | */
622 | @SuppressWarnings("unchecked")
623 | private E removeAt(int i) {
624 | // assert i >= 0 && i < size;
625 | modCount++;
626 | int s = --size;
627 | if (s == i) // removed last element
628 | queue[i] = null;
629 | else {
630 | E moved = (E) queue[s];
631 | queue[s] = null;
632 | siftDown(i, moved);
633 | if (queue[i] == moved) {
634 | siftUp(i, moved);
635 | if (queue[i] != moved)
636 | return moved;
637 | }
638 | }
639 | return null;
640 | }
641 |
642 | /**
643 | * Inserts item x at position k, maintaining heap invariant by
644 | * promoting x up the tree until it is greater than or equal to
645 | * its parent, or is the root.
646 | *
647 | * To simplify and speed up coercions and comparisons. the
648 | * Comparable and Comparator versions are separated into different
649 | * methods that are otherwise identical. (Similarly for siftDown.)
650 | *
651 | * @param k the position to fill
652 | * @param x the item to insert
653 | */
654 | private void siftUp(int k, E x) {
655 | if (comparator != null)
656 | siftUpUsingComparator(k, x);
657 | else
658 | siftUpComparable(k, x);
659 | }
660 |
661 | @SuppressWarnings("unchecked")
662 | private void siftUpComparable(int k, E x) {
663 | Comparable super E> key = (Comparable super E>) x;
664 | while (k > 0) {
665 | int parent = (k - 1) >>> 1;
666 | Object e = queue[parent];
667 | if (key.compareTo((E) e) >= 0)
668 | break;
669 | queue[k] = e;
670 | k = parent;
671 | }
672 | queue[k] = key;
673 | }
674 |
675 | @SuppressWarnings("unchecked")
676 | private void siftUpUsingComparator(int k, E x) {
677 | while (k > 0) {
678 | int parent = (k - 1) >>> 1;
679 | Object e = queue[parent];
680 | if (comparator.compare(x, (E) e) >= 0)
681 | break;
682 | queue[k] = e;
683 | k = parent;
684 | }
685 | queue[k] = x;
686 | }
687 |
688 | /**
689 | * Inserts item x at position k, maintaining heap invariant by
690 | * demoting x down the tree repeatedly until it is less than or
691 | * equal to its children or is a leaf.
692 | *
693 | * @param k the position to fill
694 | * @param x the item to insert
695 | */
696 | private void siftDown(int k, E x) {
697 | if (comparator != null)
698 | siftDownUsingComparator(k, x);
699 | else
700 | siftDownComparable(k, x);
701 | }
702 |
703 | @SuppressWarnings("unchecked")
704 | private void siftDownComparable(int k, E x) {
705 | Comparable super E> key = (Comparable super E>)x;
706 | int half = size >>> 1; // loop while a non-leaf
707 | while (k < half) {
708 | int child = (k << 1) + 1; // assume left child is least
709 | Object c = queue[child];
710 | int right = child + 1;
711 | if (right < size &&
712 | ((Comparable super E>) c).compareTo((E) queue[right]) > 0)
713 | c = queue[child = right];
714 | if (key.compareTo((E) c) <= 0)
715 | break;
716 | queue[k] = c;
717 | k = child;
718 | }
719 | queue[k] = key;
720 | }
721 |
722 | @SuppressWarnings("unchecked")
723 | private void siftDownUsingComparator(int k, E x) {
724 | int half = size >>> 1;
725 | while (k < half) {
726 | int child = (k << 1) + 1;
727 | Object c = queue[child];
728 | int right = child + 1;
729 | if (right < size &&
730 | comparator.compare((E) c, (E) queue[right]) > 0)
731 | c = queue[child = right];
732 | if (comparator.compare(x, (E) c) <= 0)
733 | break;
734 | queue[k] = c;
735 | k = child;
736 | }
737 | queue[k] = x;
738 | }
739 |
740 | /**
741 | * Establishes the heap invariant (described above) in the entire tree,
742 | * assuming nothing about the order of the elements prior to the call.
743 | */
744 | @SuppressWarnings("unchecked")
745 | private void heapify() {
746 | for (int i = (size >>> 1) - 1; i >= 0; i--)
747 | siftDown(i, (E) queue[i]);
748 | }
749 |
750 | /**
751 | * Returns the comparator used to order the elements in this
752 | * queue, or {@code null} if this queue is sorted according to
753 | * the {@linkplain Comparable natural ordering} of its elements.
754 | *
755 | * @return the comparator used to order this queue, or
756 | * {@code null} if this queue is sorted according to the
757 | * natural ordering of its elements
758 | */
759 | public Comparator super E> comparator() {
760 | return comparator;
761 | }
762 |
763 | /**
764 | * Saves this queue to a stream (that is, serializes it).
765 | *
766 | * @serialData The length of the array backing the instance is
767 | * emitted (int), followed by all of its elements
768 | * (each an {@code Object}) in the proper order.
769 | * @param s the stream
770 | */
771 | private void writeObject(java.io.ObjectOutputStream s)
772 | throws java.io.IOException {
773 | // Write out element count, and any hidden stuff
774 | s.defaultWriteObject();
775 |
776 | // Write out array length, for compatibility with 1.5 version
777 | s.writeInt(Math.max(2, size + 1));
778 |
779 | // Write out all elements in the "proper order".
780 | for (int i = 0; i < size; i++)
781 | s.writeObject(queue[i]);
782 | }
783 |
784 | /**
785 | * Reconstitutes the {@code PriorityQueue} instance from a stream
786 | * (that is, deserializes it).
787 | *
788 | * @param s the stream
789 | */
790 | private void readObject(java.io.ObjectInputStream s)
791 | throws java.io.IOException, ClassNotFoundException {
792 | // Read in size, and any hidden stuff
793 | s.defaultReadObject();
794 |
795 | // Read in (and discard) array length
796 | s.readInt();
797 |
798 | queue = new Object[size];
799 |
800 | // Read in all elements.
801 | for (int i = 0; i < size; i++)
802 | queue[i] = s.readObject();
803 |
804 | // Elements are guaranteed to be in "proper order", but the
805 | // spec has never explained what that might be.
806 | heapify();
807 | }
808 |
809 | /**
810 | * Creates a late-binding
811 | * and fail-fast {@link Spliterator} over the elements in this
812 | * queue.
813 | *
814 | * The {@code Spliterator} reports {@link Spliterator#SIZED},
815 | * {@link Spliterator#SUBSIZED}, and {@link Spliterator#NONNULL}.
816 | * Overriding implementations should document the reporting of additional
817 | * characteristic values.
818 | *
819 | * @return a {@code Spliterator} over the elements in this queue
820 | * @since 1.8
821 | */
822 | public final Spliterator spliterator() {
823 | return new PriorityQueueSpliterator(this, 0, -1, 0);
824 | }
825 |
826 | static final class PriorityQueueSpliterator implements Spliterator {
827 | /*
828 | * This is very similar to ArrayList Spliterator, except for
829 | * extra null checks.
830 | */
831 | private final PriorityQueue pq;
832 | private int index; // current index, modified on advance/split
833 | private int fence; // -1 until first use
834 | private int expectedModCount; // initialized when fence set
835 |
836 | /** Creates new spliterator covering the given range */
837 | PriorityQueueSpliterator(PriorityQueue pq, int origin, int fence,
838 | int expectedModCount) {
839 | this.pq = pq;
840 | this.index = origin;
841 | this.fence = fence;
842 | this.expectedModCount = expectedModCount;
843 | }
844 |
845 | private int getFence() { // initialize fence to size on first use
846 | int hi;
847 | if ((hi = fence) < 0) {
848 | expectedModCount = pq.modCount;
849 | hi = fence = pq.size;
850 | }
851 | return hi;
852 | }
853 |
854 | public PriorityQueueSpliterator trySplit() {
855 | int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
856 | return (lo >= mid) ? null :
857 | new PriorityQueueSpliterator(pq, lo, index = mid,
858 | expectedModCount);
859 | }
860 |
861 | @SuppressWarnings("unchecked")
862 | public void forEachRemaining(Consumer super E> action) {
863 | int i, hi, mc; // hoist accesses and checks from loop
864 | PriorityQueue q; Object[] a;
865 | if (action == null)
866 | throw new NullPointerException();
867 | if ((q = pq) != null && (a = q.queue) != null) {
868 | if ((hi = fence) < 0) {
869 | mc = q.modCount;
870 | hi = q.size;
871 | }
872 | else
873 | mc = expectedModCount;
874 | if ((i = index) >= 0 && (index = hi) <= a.length) {
875 | for (E e;; ++i) {
876 | if (i < hi) {
877 | if ((e = (E) a[i]) == null) // must be CME
878 | break;
879 | action.accept(e);
880 | }
881 | else if (q.modCount != mc)
882 | break;
883 | else
884 | return;
885 | }
886 | }
887 | }
888 | throw new ConcurrentModificationException();
889 | }
890 |
891 | public boolean tryAdvance(Consumer super E> action) {
892 | if (action == null)
893 | throw new NullPointerException();
894 | int hi = getFence(), lo = index;
895 | if (lo >= 0 && lo < hi) {
896 | index = lo + 1;
897 | @SuppressWarnings("unchecked") E e = (E)pq.queue[lo];
898 | if (e == null)
899 | throw new ConcurrentModificationException();
900 | action.accept(e);
901 | if (pq.modCount != expectedModCount)
902 | throw new ConcurrentModificationException();
903 | return true;
904 | }
905 | return false;
906 | }
907 |
908 | public long estimateSize() {
909 | return (long) (getFence() - index);
910 | }
911 |
912 | public int characteristics() {
913 | return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL;
914 | }
915 | }
916 | }
917 |
--------------------------------------------------------------------------------