Java tutorial
/******************************************************************************* * This file is part of BOINC. * http://boinc.berkeley.edu * Copyright (C) 2012 University of California * * BOINC is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * BOINC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with BOINC. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package edu.berkeley.boinc; import edu.berkeley.boinc.utils.*; import java.util.ArrayList; import android.app.Activity; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.RemoteException; import android.support.v4.app.Fragment; import android.text.SpannableString; import android.text.style.UnderlineSpan; import android.util.Log; import android.view.Display; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.widget.Button; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import edu.berkeley.boinc.rpc.ImageWrapper; import edu.berkeley.boinc.rpc.Project; import edu.berkeley.boinc.rpc.ProjectInfo; import edu.berkeley.boinc.rpc.RpcClient; public class ProjectDetailsFragment extends Fragment { private String url; private ProjectInfo projectInfo; // might be null for projects added via manual URL attach private Project project; private ArrayList<ImageWrapper> slideshowImages = new ArrayList<ImageWrapper>(); private LayoutInflater li; private View root; private HorizontalScrollView slideshowWrapper; private LinearLayout slideshowHook; private ProgressBar slideshowLoading; // display dimensions private int width; private int height; private boolean retryLayout = true; // BroadcastReceiver event is used to update the UI with updated information from // the client. This is generally called once a second. // private IntentFilter ifcsc = new IntentFilter("edu.berkeley.boinc.clientstatuschange"); private BroadcastReceiver mClientStatusChangeRec = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //if(Logging.DEBUG) Log.d(Logging.TAG, "ClientStatusChange - onReceive()"); getCurrentProjectData(); if (retryLayout) populateLayout(); else updateChangingItems(root); } }; @Override public void onCreate(Bundle savedInstanceState) { // get data url = getArguments().getString("url"); getCurrentProjectData(); setHasOptionsMenu(true); // enables fragment specific menu super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (Logging.VERBOSE) Log.v(Logging.TAG, "ProjectDetailsFragment onCreateView"); // Inflate the layout for this fragment this.li = inflater; View layout = inflater.inflate(R.layout.project_details_layout, container, false); root = layout; return layout; } @SuppressWarnings("deprecation") @Override public void onAttach(Activity activity) { // first time fragment can get a valid context (before this, getActivity() will return null!) Display display = activity.getWindowManager().getDefaultDisplay(); width = display.getWidth(); height = display.getHeight(); super.onAttach(activity); } @Override public void onPause() { getActivity().unregisterReceiver(mClientStatusChangeRec); super.onPause(); } @Override public void onResume() { super.onResume(); getActivity().registerReceiver(mClientStatusChangeRec, ifcsc); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // appends the project specific menu to the main menu. inflater.inflate(R.menu.project_details_menu, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); if (project == null) return; // no new tasks, adapt based on status MenuItem nnt = menu.findItem(R.id.projects_control_nonewtasks); if (project.dont_request_more_work) nnt.setTitle(R.string.projects_control_allownewtasks); else nnt.setTitle(R.string.projects_control_nonewtasks); // project suspension, adapt based on status MenuItem suspend = menu.findItem(R.id.projects_control_suspend); if (project.suspended_via_gui) suspend.setTitle(R.string.projects_control_resume); else suspend.setTitle(R.string.projects_control_suspend); // detach, only show when project not managed MenuItem remove = menu.findItem(R.id.projects_control_remove); if (project.attached_via_acct_mgr) remove.setVisible(false); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.projects_control_update: new ProjectOperationAsync().execute(RpcClient.PROJECT_UPDATE); break; case R.id.projects_control_suspend: if (project.suspended_via_gui) new ProjectOperationAsync().execute(RpcClient.PROJECT_RESUME); else new ProjectOperationAsync().execute(RpcClient.PROJECT_SUSPEND); break; case R.id.projects_control_nonewtasks: if (project.dont_request_more_work) new ProjectOperationAsync().execute(RpcClient.PROJECT_ANW); else new ProjectOperationAsync().execute(RpcClient.PROJECT_NNW); break; case R.id.projects_control_reset: showConfirmationDialog(RpcClient.PROJECT_RESET); break; case R.id.projects_control_remove: showConfirmationDialog(RpcClient.PROJECT_DETACH); break; default: if (Logging.WARNING) Log.w(Logging.TAG, "ProjectDetailsFragment onOptionsItemSelected: could not match ID"); } return super.onOptionsItemSelected(item); } private void showConfirmationDialog(final int operation) { final Dialog dialog = new Dialog(getActivity()); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setContentView(R.layout.dialog_confirm); Button confirm = (Button) dialog.findViewById(R.id.confirm); TextView tvTitle = (TextView) dialog.findViewById(R.id.title); TextView tvMessage = (TextView) dialog.findViewById(R.id.message); // operation dependend texts if (operation == RpcClient.PROJECT_DETACH) { tvTitle.setText(R.string.projects_confirm_detach_title); tvMessage.setText(getString(R.string.projects_confirm_detach_message) + " " + project.project_name + " " + getString(R.string.projects_confirm_detach_message2)); confirm.setText(R.string.projects_confirm_detach_confirm); } else if (operation == RpcClient.PROJECT_RESET) { tvTitle.setText(R.string.projects_confirm_reset_title); tvMessage.setText(getString(R.string.projects_confirm_reset_message) + " " + project.project_name + getString(R.string.projects_confirm_reset_message2)); confirm.setText(R.string.projects_confirm_reset_confirm); } confirm.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { new ProjectOperationAsync().execute(operation); dialog.dismiss(); } }); Button cancel = (Button) dialog.findViewById(R.id.cancel); cancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); dialog.show(); } private void populateLayout() { if (project == null) { retryLayout = true; return; // if data not available yet, return. frequently retrys with onReceive } retryLayout = false; View v = root; updateChangingItems(v); slideshowWrapper = (HorizontalScrollView) v.findViewById(R.id.slideshow_wrapper); slideshowHook = (LinearLayout) v.findViewById(R.id.slideshow_hook); slideshowLoading = (ProgressBar) v.findViewById(R.id.slideshow_loading); // set website TextView website = (TextView) v.findViewById(R.id.project_url); SpannableString content = new SpannableString(project.master_url); content.setSpan(new UnderlineSpan(), 0, content.length(), 0); website.setText(content); website.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(project.master_url)); startActivity(i); } }); // set general area if (projectInfo != null && projectInfo.generalArea != null) { TextView generalArea = (TextView) v.findViewById(R.id.general_area); generalArea.setText(projectInfo.generalArea); } else { LinearLayout wrapper = (LinearLayout) v.findViewById(R.id.general_area_wrapper); wrapper.setVisibility(View.GONE); } // set specific area if (projectInfo != null && projectInfo.specificArea != null) { TextView specificArea = (TextView) v.findViewById(R.id.specific_area); specificArea.setText(projectInfo.specificArea); } else { LinearLayout wrapper = (LinearLayout) v.findViewById(R.id.specific_area_wrapper); wrapper.setVisibility(View.GONE); } // set description if (projectInfo != null && projectInfo.description != null) { TextView description = (TextView) v.findViewById(R.id.description); description.setText(projectInfo.description); } else { LinearLayout wrapper = (LinearLayout) v.findViewById(R.id.description_wrapper); wrapper.setVisibility(View.GONE); } // set home if (projectInfo != null && projectInfo.home != null) { TextView home = (TextView) v.findViewById(R.id.based_at); home.setText(projectInfo.home); } else { LinearLayout wrapper = (LinearLayout) v.findViewById(R.id.based_at_wrapper); wrapper.setVisibility(View.GONE); } // load slideshow new UpdateSlideshowImagesAsync().execute(); } private void getCurrentProjectData() { try { ArrayList<Project> allProjects = (ArrayList<Project>) BOINCActivity.monitor.getProjects(); for (Project tmpP : allProjects) { if (tmpP.master_url.equals(url)) this.project = tmpP; } this.projectInfo = BOINCActivity.monitor.getProjectInfo(url); } catch (Exception e) { if (Logging.ERROR) Log.e(Logging.TAG, "ProjectDetailsFragment getCurrentProjectData could not retrieve project list"); } if (this.project == null) if (Logging.WARNING) Log.w(Logging.TAG, "ProjectDetailsFragment getCurrentProjectData could not find project for URL: " + url); if (this.projectInfo == null) if (Logging.DEBUG) Log.d(Logging.TAG, "ProjectDetailsFragment getCurrentProjectData could not find project attach list for URL: " + url); } private void updateChangingItems(View v) { try { // status String newStatus = BOINCActivity.monitor.getProjectStatus(project.master_url); LinearLayout wrapper = (LinearLayout) v.findViewById(R.id.status_wrapper); if (!newStatus.isEmpty()) { wrapper.setVisibility(View.VISIBLE); TextView statusT = (TextView) v.findViewById(R.id.status_text); statusT.setText(newStatus); } else { wrapper.setVisibility(View.GONE); } } catch (Exception e) { } } // executes project operations in new thread private final class ProjectOperationAsync extends AsyncTask<Object, Void, Boolean> { @Override protected Boolean doInBackground(Object... params) { if (Logging.DEBUG) Log.d(Logging.TAG, "ProjectOperationAsync doInBackground"); try { Integer operation = (Integer) params[0]; return BOINCActivity.monitor.projectOp(operation, project.master_url); } catch (Exception e) { if (Logging.WARNING) Log.w(Logging.TAG, "ProjectOperationAsync error in do in background", e); } return false; } @Override protected void onPostExecute(Boolean success) { if (success) try { BOINCActivity.monitor.forceRefresh(); } catch (RemoteException e) { } else if (Logging.WARNING) Log.w(Logging.TAG, "ProjectOperationAsync failed."); } } private final class UpdateSlideshowImagesAsync extends AsyncTask<Void, Void, Boolean> { @Override protected Boolean doInBackground(Void... params) { if (Logging.DEBUG) Log.d(Logging.TAG, "UpdateSlideshowImagesAsync updating images in new thread. project: " + project.master_url); try { //status = Monitor.getClientStatus(); slideshowImages = (ArrayList<ImageWrapper>) BOINCActivity.monitor .getSlideshowForProject(project.master_url); } catch (Exception e) { if (Logging.WARNING) Log.w(Logging.TAG, "UpdateSlideshowImagesAsync: Could not load data, clientStatus not initialized."); return false; } // load slideshow images // slideshowImages = status.getSlideshowForProject(project.master_url); if (slideshowImages == null || slideshowImages.size() == 0) return false; return true; } @Override protected void onPostExecute(Boolean success) { if (Logging.DEBUG) Log.d(Logging.TAG, "UpdateSlideshowImagesAsync success: " + success + " images: " + slideshowImages.size()); if (success && slideshowImages.size() > 0) { slideshowLoading.setVisibility(View.GONE); for (ImageWrapper image : slideshowImages) { ImageView iv = (ImageView) li.inflate(R.layout.project_details_slideshow_image_layout, null); Bitmap bitmap = image.image; if (scaleImages(bitmap.getHeight(), bitmap.getWidth())) bitmap = Bitmap.createScaledBitmap(image.image, image.image.getWidth() * 2, image.image.getHeight() * 2, false); iv.setImageBitmap(bitmap); slideshowHook.addView(iv); } } else { slideshowWrapper.setVisibility(View.GONE); } } private boolean scaleImages(int imageHeight, int imageWidth) { return (height >= imageHeight * 2 && width >= imageWidth * 2); } } }