summaryrefslogtreecommitdiffstats
path: root/base/message_pump_android.cc
blob: 2daf98db3157fa8ac9aed43ce34052745119836b (plain)
1
2
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_pump_android.h"

#include <jni.h>

#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "jni/system_message_handler_jni.h"

using base::android::ScopedJavaLocalRef;

namespace {

base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
    g_system_message_handler_obj = LAZY_INSTANCE_INITIALIZER;

}  // namespace

// ----------------------------------------------------------------------------
// Native JNI methods called by Java.
// ----------------------------------------------------------------------------
// This method can not move to anonymous namespace as it has been declared as
// 'static' in system_message_handler_jni.h.
static jboolean DoRunLoopOnce(JNIEnv* env, jobject obj, jint native_delegate) {
  base::MessagePump::Delegate* delegate =
      reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
  DCHECK(delegate);
  // This is based on MessagePumpForUI::DoRunLoop() from desktop.
  // Note however that our system queue is handled in the java side.
  // In desktop we inspect and process a single system message and then
  // we call DoWork() / DoDelayedWork().
  // On Android, the java message queue may contain messages for other handlers
  // that will be processed before calling here again.
  bool more_work_is_plausible = delegate->DoWork();

  // This is the time when we need to do delayed work.
  base::TimeTicks delayed_work_time;
  more_work_is_plausible |= delegate->DoDelayedWork(&delayed_work_time);

  // This is a major difference between android and other platforms: since we
  // can't inspect it and process just one single message, instead we'll yeld
  // the callstack, and post a message to call us back soon.
  if (more_work_is_plausible)
    return true;

  more_work_is_plausible = delegate->DoIdleWork();
  if (!more_work_is_plausible && !delayed_work_time.is_null()) {
    // We only set the timer here as returning true would post a message.
    jlong millis =
        (delayed_work_time - base::TimeTicks::Now()).InMillisecondsRoundedUp();
    Java_SystemMessageHandler_setDelayedTimer(env, obj, millis);
  }
  return more_work_is_plausible;
}

namespace base {

MessagePumpForUI::MessagePumpForUI()
    : state_(NULL) {
}

MessagePumpForUI::~MessagePumpForUI() {
}

void MessagePumpForUI::Run(Delegate* delegate) {
  NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
      " test_stub_android.h";
}

void MessagePumpForUI::Start(Delegate* delegate) {
  state_ = new MessageLoop::AutoRunState(MessageLoop::current());

  DCHECK(g_system_message_handler_obj.Get().is_null());

  JNIEnv* env = base::android::AttachCurrentThread();
  DCHECK(env);

  g_system_message_handler_obj.Get().Reset(
      Java_SystemMessageHandler_create(env, reinterpret_cast<jint>(delegate)));
}

void MessagePumpForUI::Quit() {
  if (!g_system_message_handler_obj.Get().is_null()) {
    JNIEnv* env = base::android::AttachCurrentThread();
    DCHECK(env);

    Java_SystemMessageHandler_removeTimer(env,
        g_system_message_handler_obj.Get().obj());
    g_system_message_handler_obj.Get().Reset();
  }

  if (state_) {
    delete state_;
    state_ = NULL;
  }
}

void MessagePumpForUI::ScheduleWork() {
  if (g_system_message_handler_obj.Get().is_null())
    return;

  JNIEnv* env = base::android::AttachCurrentThread();
  DCHECK(env);

  Java_SystemMessageHandler_setTimer(env,
      g_system_message_handler_obj.Get().obj());
}

void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
  if (g_system_message_handler_obj.Get().is_null())
    return;

  JNIEnv* env = base::android::AttachCurrentThread();
  DCHECK(env);

  jlong millis =
      (delayed_work_time - base::TimeTicks::Now()).InMillisecondsRoundedUp();
  // Note that we're truncating to milliseconds as required by the java side,
  // even though delayed_work_time is microseconds resolution.
  Java_SystemMessageHandler_setDelayedTimer(env,
      g_system_message_handler_obj.Get().obj(), millis);
}

// Register native methods
bool RegisterSystemMessageHandler(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

}  // namespace base