001/*
002 * JPPF.
003 * Copyright (C) 2005-2018 JPPF Team.
004 * http://www.jppf.org
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.jppf.android.node;
019
020import android.util.Log;
021import android.view.LayoutInflater;
022import android.view.View;
023import android.widget.ImageView;
024import android.widget.TextView;
025
026import org.jppf.android.events.R;
027import org.jppf.android.node.views.GlowingTextView;
028import org.jppf.android.node.views.ProgressTextView;
029import org.jppf.node.event.NodeLifeCycleEvent;
030import org.jppf.node.event.TaskExecutionEvent;
031
032import java.util.concurrent.atomic.AtomicInteger;
033import java.util.concurrent.atomic.AtomicLong;
034
035/**
036 * This is the default node events handler, used if none is provided by the jobs.
037 * @author Laurent Cohen
038 * @since 5.1
039 */
040public class DefaultAndroidNodeIntegration extends AndroidNodeIntegrationAdapter {
041  /**
042   * Log tag for this class.
043   */
044  private final static String LOG_TAG = DefaultAndroidNodeIntegration.class.getSimpleName();
045  /**
046   * Format for the executed / job total field.
047   */
048  private static final String TASKS_FORMAT = "%,d / %,d";
049  /**
050   * Atomic counter for the number of tasks executed by the node.
051   */
052  private AtomicLong totalTasks = new AtomicLong(0);
053  /**
054   * The view handled by this node integration.
055   */
056  private View view = null;
057  /**
058   * The number of completed tasks from the current job, if any.
059   */
060  private AtomicInteger currentJobTasks = new AtomicInteger(0);
061  /**
062   * The number of tasks in the current job.
063   */
064  private int totalJobTasks = 0;
065
066  public DefaultAndroidNodeIntegration() {
067    Log.v(LOG_TAG, "in DefaultAndroidNodeIntegration()");
068  }
069
070  @Override
071  public View getContentView() {
072    Log.v(LOG_TAG, "in getContentView() : view = " + view + ", activity = " + activity + ", this = " + this);
073    if ((view == null) && (activity != null)) {
074      LayoutInflater inflater = activity.getLayoutInflater();
075      view = inflater.inflate(R.layout.default_view, null, false);
076    }
077    return view;
078  }
079
080  @Override
081  public void taskExecuted(final TaskExecutionEvent event) {
082    final int jobCurrent = currentJobTasks.incrementAndGet();
083    final int jobTotal = totalJobTasks;
084    final long total = totalTasks.incrementAndGet();
085    Log.v(LOG_TAG, String.format("taskExecuted() current=%d, total=%d, this=%s", jobCurrent, jobTotal, this));
086    if (activity != null) activity.runOnUiThread(new Runnable() {
087      @Override
088      public void run() {
089        setCurrentTasksText(jobCurrent, jobTotal);
090        setViewText(R.id.total_tasks, String.format("%,d", total));
091      }
092    });
093  }
094
095  @Override
096  public void nodeStarting(final NodeLifeCycleEvent event) {
097    Log.v(LOG_TAG, "nodeStarting()");
098    if (activity != null) activity.runOnUiThread(new Runnable() {
099      @Override
100      public void run() {
101        setViewText(R.id.current_job, "N/A");
102        setImageViewIcon(R.id.node_state, R.mipmap.on);
103        setImageViewIcon(R.id.execution_state, R.mipmap.idle);
104        setViewText(R.id.total_tasks, String.format("%,d", totalTasks.get()));
105        setCurrentTasksText(0, 0);
106      }
107    });
108  }
109
110  @Override
111  public void nodeEnding(final NodeLifeCycleEvent event) {
112    Log.v(LOG_TAG, "nodeEnding()");
113    if (activity != null) activity.runOnUiThread(new Runnable() {
114      @Override
115      public void run() {
116        setImageViewIcon(R.id.node_state, R.mipmap.off);
117      }
118    });
119  }
120
121  @Override
122  public void jobStarting(final NodeLifeCycleEvent event) {
123    final int total = totalJobTasks = event.getTasks().size();
124    Log.v(LOG_TAG, String.format("starting job '%s' with %d tasks", event.getJob().getName(), totalJobTasks));
125    currentJobTasks.set(0);
126    if (activity != null) activity.runOnUiThread(new Runnable() {
127      @Override
128      public void run() {
129        setViewText(R.id.current_job, event.getJob().getName());
130        setImageViewIcon(R.id.node_state, R.mipmap.off);
131        setImageViewIcon(R.id.execution_state, R.mipmap.active);
132        setCurrentTasksText(0, total);
133        GlowingTextView currentJobView = (GlowingTextView) activity.findViewById(R.id.current_job);
134        currentJobView.startAnimation(400L, currentJobView.getCurrentTextColor(), 0x808080);
135      }
136    });
137  }
138
139  @Override
140  public void jobEnding(final NodeLifeCycleEvent event) {
141    Log.v(LOG_TAG, String.format("ending job '%s', currentTasks=%d, totalTasks=%d", event.getJob().getName(), currentJobTasks.get(), totalJobTasks));
142    if (activity != null) activity.runOnUiThread(new Runnable() {
143      @Override
144      public void run() {
145        setImageViewIcon(R.id.node_state, R.mipmap.on);
146        setImageViewIcon(R.id.execution_state, R.mipmap.idle);
147        setViewText(R.id.total_tasks, String.format("%,d", totalTasks.get()));
148        GlowingTextView currentJobView = (GlowingTextView) activity.findViewById(R.id.current_job);
149        currentJobView.endAnimation();
150      }
151    });
152  }
153
154  /**
155   * Set the specified text in the specified text view.
156   * @param viewId the id of the text view to update.
157   * @param text the text to set in the view.
158   */
159  private void setViewText(int viewId, String text) {
160    ((TextView) activity.findViewById(viewId)).setText(text);
161  }
162
163  /**
164   * Set the specified image in the specified image view.
165   * @param viewId the id of the text view to update.
166   * @param iconId the id of the image resource to set.
167   */
168  private void setImageViewIcon(int viewId, int iconId) {
169    ((ImageView) activity.findViewById(viewId)).setImageResource(iconId);
170  }
171
172  /**
173   * Set the text of the "current tasks" text view.
174   * @param current the number of executed tasks from the current jobs.
175   * @param total the total number of tasks in the current jobs.
176   */
177  private void setCurrentTasksText(int current, int total) {
178    int pct = total <= 0 ? 0 : (int) (100d * (double) current / (double) total);
179    ((ProgressTextView) activity.findViewById(R.id.current_tasks)).setPct(pct);
180    setViewText(R.id.current_tasks, String.format(TASKS_FORMAT, current, total));
181  }
182}