Sfoglia il codice sorgente

1.修改Android Apex Mobile重命名KPI、Result、ShipMap。

Pen Li 7 anni fa
parent
commit
5bc2762277
27 ha cambiato i file con 4681 aggiunte e 40 eliminazioni
  1. 8 2
      ApexDrivers/apexmobile/src/main/AndroidManifest.xml
  2. 1 1
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/DetailActivity.java
  3. 1 1
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/DetailFragment.java
  4. 1 1
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/TestActivity.java
  5. 539 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPICell.java
  6. 67 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPIDot.java
  7. 47 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPIItemButton.java
  8. 47 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPIListView.java
  9. 53 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPISwipeRefresh.java
  10. 88 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPIViewPager.java
  11. 710 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/PieChartView.java
  12. 1 2
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/HistoryFragment.java
  13. 4 5
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/KPIFragment.java
  14. 1 1
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/NewDetailActivity.java
  15. 1 2
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/RecentFragment.java
  16. 2 2
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/TrackingListFragment.java
  17. 646 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/result/AMResultActivity.java
  18. 348 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/result/PullRefreshListView.java
  19. 1360 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/result/SearchResultActivity.java
  20. 0 2
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/saved/AMListFragment.java
  21. 735 0
      ApexDrivers/apexmobile/src/main/java/com/usai/apex/shipmap/ShipMap.java
  22. 3 3
      ApexDrivers/apexmobile/src/main/res/layout/activity_search_result.xml
  23. 1 1
      ApexDrivers/apexmobile/src/main/res/layout/activity_test.xml
  24. 2 2
      ApexDrivers/apexmobile/src/main/res/layout/detail_fragment_withmap.xml
  25. 4 4
      ApexDrivers/apexmobile/src/main/res/layout/fragment_kpi.xml
  26. 8 8
      ApexDrivers/apexmobile/src/main/res/layout/kpi_cell.xml
  27. 3 3
      ApexDrivers/apexmobile/src/main/res/layout/kpi_item_button.xml

+ 8 - 2
ApexDrivers/apexmobile/src/main/AndroidManifest.xml

@@ -330,19 +330,25 @@
             <!-- <category android:name="android.intent.category.LAUNCHER" /> -->
             <!-- </intent-filter> -->
         </activity>
+
         <activity
-            android:name=".Result.AMResultActivity"
+            android:name=".result.AMResultActivity"
             android:screenOrientation="portrait"
             android:theme="@style/ResultActionbarTheme"/>
+
         <activity
-            android:name=".Result.SearchResultActivity"
+            android:name=".result.SearchResultActivity"
             android:screenOrientation="portrait"/>
+
         <activity android:name=".ContainerSearchActivity"/>
+
         <activity
             android:name=".pdf.PDFPreviewActivity"
             android:screenOrientation="portrait"
             android:theme="@style/ResultActionbarTheme"/>
+
         <activity android:name=".LicenseActivity"/>
+
         <activity android:name=".TestActivity"/>
 
         <activity

+ 1 - 1
ApexDrivers/apexmobile/src/main/java/com/usai/apex/DetailActivity.java

@@ -23,7 +23,7 @@ import android.widget.TabHost;
 import android.widget.TabWidget;
 import android.widget.TextView;
 
-import com.usai.apex.Result.AMResultActivity;
+import com.usai.apex.result.AMResultActivity;
 import com.usai.apex.mainframe.RootActivity;
 import com.usai.util.commonUtil;
 import com.usai.util.dbUtil;

+ 1 - 1
ApexDrivers/apexmobile/src/main/java/com/usai/apex/DetailFragment.java

@@ -44,7 +44,7 @@ import android.widget.ScrollView;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.usai.apex.ShipMap.ShipMap;
+import com.usai.apex.shipmap.ShipMap;
 import com.usai.apex.mainframe.NewDetailActivity;
 import com.usai.apex.pdf.PDFPreviewActivity;
 import com.usai.util.Network;

+ 1 - 1
ApexDrivers/apexmobile/src/main/java/com/usai/apex/TestActivity.java

@@ -3,7 +3,7 @@ package com.usai.apex;
 import android.support.v7.app.AppCompatActivity;
 import android.os.Bundle;
 
-import com.usai.apex.ShipMap.ShipMap;
+import com.usai.apex.shipmap.ShipMap;
 
 import org.json.JSONException;
 import org.json.JSONObject;

+ 539 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPICell.java

@@ -0,0 +1,539 @@
+package com.usai.apex.kpi;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.GestureDetector;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.usai.apex.R;
+import com.usai.apex.mainframe.KPIFragment;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+public class KPICell extends RelativeLayout implements KPIListView.KPIListViewTouchListener,View.OnTouchListener {
+
+    public KPICell(Context context) {
+        super(context);
+//        init();
+    }
+
+    public KPICell(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+//        init();
+    }
+
+    public KPICell(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+//        init();
+    }
+
+
+    private KPICell mCell;
+    private ArrayList<PieChartView.ChartItem> mChartItems;
+    private PieChartView mChartView;
+    private ImageButton mPreBtn,mNextBtn;
+    private TextView mMonthTV,mShipTV,mContainerTV,mTeuTV,mSelectionTV;
+    private KPIListView mItemListView;
+    private ValueAnimator mAnimation;
+
+    public void init() {
+
+        mCell = this;
+
+        mDetector = new GestureDetector(getContext(), new GestureListener());
+        mMonthTV = findViewById(R.id.monthTV);
+        mShipTV = findViewById(R.id.shipmentTV);
+        mContainerTV = findViewById(R.id.containerTV);
+        mTeuTV = findViewById(R.id.teuTV);
+        mSelectionTV = findViewById(R.id.selectionTV);
+
+        mShipTV.setText(null);
+        mContainerTV.setText(null);
+        mTeuTV.setText(null);
+        mSelectionTV.setText(null);
+
+        mItemListView = findViewById(R.id.item_list);
+        mAdapter = new KPIItemAdapter(getContext(),R.layout.kpi_item_cell);
+        mItemListView.setAdapter(mAdapter);
+        mItemListView.setListener(this);
+
+        mChartView = findViewById(R.id.chart_view);
+
+        if (mAnimation == null) {
+            mAnimation = ValueAnimator.ofFloat(0f, 100f);
+
+            mAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator updatedAnimation) {
+                    // You can use the animated value in a property that uses the
+                    // same type as the animation. In this case, you can use the
+                    // float value in the translationX property.
+                    float animatedValue = (float)updatedAnimation.getAnimatedValue();
+
+                    mChartView.progress = animatedValue / 100.0f;
+                    mChartView.postInvalidate();
+                }
+            });
+
+            mAnimation.addListener(new Animator.AnimatorListener() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+
+                }
+            });
+
+            mAnimation.setDuration(100);
+        }
+
+
+        mChartView.minTitleAngle = 20;
+        mChartView.setPieChartItemClickListener(new PieChartView.PieChartItemClickListener() {
+            @Override
+            public void pieChartItemClicked(PieChartView pieChartView, PieChartView.ChartItem item) {
+
+                if (mListener != null) {
+                    mListener.KPIPieChartClickedItem(mCell,item);
+                }
+                mAnimation.end();
+
+                mAnimation.start();
+
+            }
+
+            @Override
+            public void pieChartCenterClicked(PieChartView pieChartView) {
+
+                if (mListener != null) {
+                    mListener.KPIPieChartClickedTitle(mCell);
+                }
+            }
+
+            @Override
+            public void pieChartDidBeginTouch() {
+                if (mListener != null) {
+                    mListener.KPIPieChartDidBeginClicked();
+                }
+            }
+
+            @Override
+            public void pieChartDidEndTouch() {
+                if (mListener != null) {
+                    mListener.KPIPieChartDidEndClicked();
+                }
+            }
+        });
+
+//        mPreBtn = findViewById(R.id.preBtn);
+//        mPreBtn.setOnClickListener(new OnClickListener() {
+//            @Override
+//            public void onClick(View v) {
+//                if (mListener != null) {
+//                    mListener.KPIPreviousButtonClicked(mCell);
+//                }
+//            }
+//        });
+//
+//        mNextBtn = findViewById(R.id.nextBtn);
+//        mNextBtn.setOnClickListener(new OnClickListener() {
+//            @Override
+//            public void onClick(View v) {
+//                if (mListener != null) {
+//                    mListener.KPINextButtonClicked(mCell);
+//                }
+//            }
+//        });
+    }
+
+    private void resizePieChartView(int w) {
+
+        int leftInterval = dp2px(getContext(),60);
+        int rightInterval = dp2px(getContext(),60);
+
+        final int pieW = (w - leftInterval - rightInterval);
+
+
+        mChartView.post(new Runnable() {
+
+            @Override
+            public void run() {
+
+                LayoutParams layout = (LayoutParams)mChartView.getLayoutParams();
+                layout.width = (int)pieW;
+                layout.height = (int)pieW;
+                mChartView.setLayoutParams(layout);
+                mChartView.requestLayout();
+            }
+        });
+    }
+
+    public void setMonthShipment(String shipment, int color) {
+        mShipTV.setText("Shipment:" + shipment);
+        mShipTV.setTextColor(color);
+    }
+
+    public void setMonthContainer(String container, int color) {
+        mContainerTV.setText("Container:" + container);
+        mContainerTV.setTextColor(color);
+    }
+
+    public void setMonthTeu(String teu, int color) {
+        mTeuTV.setText("TEU:" + teu);
+        mTeuTV.setTextColor(color);
+    }
+
+    public void setNameAndCount(String name, int count) {
+        if (mChartView != null) {
+            mChartView.setNameAndCount(name,count);
+        }
+    }
+
+    private KPIFragment.KPIModel mModel;
+    public void setKPIModel(KPIFragment.KPIModel model) {
+        mModel = model;
+        if (model != null) {
+            setChartItems(model.items);
+            setNameAndCount(model.name,model.total);
+        }
+    }
+
+    public void setSelection(String selection) {
+        mSelectionTV.setText(selection);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+
+        super.onSizeChanged(w, h, oldw, oldh);
+
+    }
+
+    private int mWidth = 0;
+    private int mHeight = 0;
+
+    public int getKPIWidth() {
+        return mWidth;
+    }
+
+    public int getKPIHeight() {
+        return mHeight;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        int w = getMeasuredWidth();
+        int h = getMeasuredHeight();
+
+        if (w != mWidth) {
+//            resizePieChartView(w);
+        }
+
+        mWidth = w;
+        mHeight = h;
+
+        float textSize = 7;
+        mMonthTV.setTextSize(TypedValue.COMPLEX_UNIT_PT,textSize);
+        mShipTV.setTextSize(TypedValue.COMPLEX_UNIT_PT,textSize);
+        mContainerTV.setTextSize(TypedValue.COMPLEX_UNIT_PT,textSize);
+        mTeuTV.setTextSize(TypedValue.COMPLEX_UNIT_PT,textSize);
+        mSelectionTV.setTextSize(TypedValue.COMPLEX_UNIT_PT,textSize);
+    }
+
+
+    float mTotal = 0;
+    private ArrayList<PieChartView.ChartItem> preparePieChartItems() {
+
+        float total = 0;
+        ArrayList<PieChartView.ChartItem> displayItems = new ArrayList<>();
+
+        if (mChartItems != null) {
+            total = 0;
+            for (int i = 0; i < mChartItems.size(); i++) {
+                PieChartView.ChartItem item = mChartItems.get(i);
+                if (item.display) {
+                    total += item.value;
+                }
+            }
+        } else {
+            total = 0;
+        }
+
+
+        for (int i = 0; i < mChartItems.size(); i++) {
+            PieChartView.ChartItem item = mChartItems.get(i);
+            if (item.display) {
+                if (total > 0) {
+                    item.setPercentage(item.value / total);
+                } else {
+                    item.setPercentage(0.f);
+                }
+
+                displayItems.add(item);
+            }
+        }
+
+        mTotal = total;
+        return displayItems;
+    }
+
+    private void refreshUI() {
+        ArrayList<PieChartView.ChartItem> displayItems = preparePieChartItems();
+        mChartView.setChartItems(displayItems);
+        mAdapter.notifyDataSetChanged();
+    }
+
+    public void setChartItems(ArrayList<PieChartView.ChartItem> chartItems) {
+        mChartItems = chartItems;
+        Log.d("KPI Cell", "setChartItems: ");
+        refreshUI();
+    }
+
+    public void randomColor() {
+        String r,g,b;
+        Random random = new Random();
+        r = Integer.toHexString(random.nextInt(256)).toUpperCase();
+        g = Integer.toHexString(random.nextInt(256)).toUpperCase();
+        b = Integer.toHexString(random.nextInt(256)).toUpperCase();
+
+        r = r.length()==1 ? "0" + r : r ;
+        g = g.length()==1 ? "0" + g : g ;
+        b = b.length()==1 ? "0" + b : b ;
+        int color = Color.parseColor("#" + r + g + b);
+        setBackgroundColor(color);
+    }
+
+    public static int dp2px(Context context, float dpValue) {
+        float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+
+    public static int px2dp(Context context, float pxValue) {
+        float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (pxValue / scale + 0.5f);
+    }
+
+    private KPIItemAdapter mAdapter;
+
+//    @Override
+//    public void onClick(View v) {
+//        if (v instanceof KPIItemButton) {
+//            KPIItemButton button = (KPIItemButton) v;
+//            Integer tag = (Integer) button.getTag();
+//            PieChartView.ChartItem item = mChartItems.get(tag);
+//            item.display = !item.display;
+//            refreshUI();
+//        }
+//    }
+
+    @Override
+    public void KPIListViewTouched(boolean t) {
+        if (mListener != null) {
+            mListener.KPIListTouched(t);
+        }
+    }
+
+    private class KPIItemAdapter extends BaseAdapter {
+
+        class ViewHolder {
+            KPIItemButton button_0, button_1;
+            ViewHolder(View root) {
+                if (root != null) {
+                    button_0 = root.findViewById(R.id.item_btn_0);
+                    button_1 = root.findViewById(R.id.item_btn_1);
+                    root.setTag(this);
+                }
+            }
+        }
+
+        int mLayoutId;
+        public KPIItemAdapter(Context context,int layoutId) {
+            mLayoutId = layoutId;
+        }
+
+        @NonNull
+        @Override
+        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+
+            ViewHolder holder;
+            if (convertView == null) {
+                convertView = LayoutInflater.from(getContext()).inflate(mLayoutId,null);
+                holder = new ViewHolder(convertView);
+            } else {
+                holder = (ViewHolder) convertView.getTag();
+            }
+            holder.button_0.setOnClickListener(null);
+            holder.button_1.setOnClickListener(null);
+            holder.button_0.setOnTouchListener(null);
+            holder.button_1.setOnTouchListener(null);
+
+            holder.button_0.setTitle(null);
+            holder.button_1.setTitle(null);
+            holder.button_0.setDotColor(Color.parseColor("#00000000"));
+            holder.button_1.setDotColor(Color.parseColor("#00000000"));
+
+            int index = 2 * position;
+            PieChartView.ChartItem item_0 = mChartItems.get(index);
+
+            if (item_0.display) {
+                holder.button_0.setTitle(String.format("%s(%.2f%%)",item_0.shortTitle,item_0.getPercentage() * 100));
+                holder.button_0.setTitleColor(Color.BLACK);
+                holder.button_0.setDotColor(item_0.color);
+            } else {
+                holder.button_0.setTitle(item_0.shortTitle);
+                holder.button_0.setDotColor(Color.LTGRAY);
+                holder.button_0.setTitleColor(Color.LTGRAY);
+            }
+
+            holder.button_0.setTag(index);
+            holder.button_0.setOnTouchListener(mCell);
+
+            if (index < mChartItems.size() - 1) {
+                PieChartView.ChartItem item_1 = mChartItems.get(index + 1);
+                if (item_1.display) {
+                    holder.button_1.setTitle(String.format("%s(%.2f%%)",item_1.shortTitle,item_1.getPercentage() * 100));
+                    holder.button_1.setDotColor(item_1.color);
+                    holder.button_1.setTitleColor(Color.BLACK);
+                } else {
+                    holder.button_1.setTitle(item_1.shortTitle);
+                    holder.button_1.setDotColor(Color.LTGRAY);
+                    holder.button_1.setTitleColor(Color.LTGRAY);
+                }
+
+                holder.button_1.setTag(index + 1);
+                holder.button_1.setOnTouchListener(mCell);
+            }
+
+            return convertView;
+        }
+
+        @Override
+        public int getCount() {
+
+            if (mChartItems == null) {
+                return 0;
+            }
+
+            int row = mChartItems.size() / 2;
+            int col = mChartItems.size() % 2;
+            if (col != 0) {
+                row++;
+            }
+
+            return row;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            int index = 2 * position;
+            PieChartView.ChartItem item_0 = mChartItems.get(index);
+            return item_0;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+    }
+
+    private KPIListener mListener;
+    public void setListener(KPIListener listener) {
+        mListener = listener;
+    }
+
+    public KPIListener getListener() {
+        return mListener;
+    }
+
+    public interface KPIListener {
+
+        void KPIPieChartClickedItem(KPICell cell, PieChartView.ChartItem item);
+        void KPIPieChartClickedTitle(KPICell cell);
+//        void KPIPreviousButtonClicked(KPICell cell);
+//        void KPINextButtonClicked(KPICell cell);
+
+        void KPIPieChartDidBeginClicked();
+        void KPIPieChartDidEndClicked();
+
+        void KPIListTouched(boolean touch);
+
+        void KPICellDidDoubleClickItem(KPICell cell, int index, KPIFragment.KPIModel model);
+
+    }
+
+    private KPIItemButton mClickBtn;
+    private GestureDetector mDetector;
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+
+        if (v instanceof KPIItemButton) {
+            mClickBtn = (KPIItemButton) v;
+            mDetector.onTouchEvent(event);
+        }
+
+        return true;
+    }
+
+    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
+
+        @Override
+        public boolean onDoubleTapEvent(MotionEvent e) {
+
+
+            if (e.getAction() == MotionEvent.ACTION_UP) {
+                Log.d("KPI Cell", "onDoubleTapEvent: ");
+                if (mListener != null) {
+                    mListener.KPICellDidDoubleClickItem(mCell,(Integer) mClickBtn.getTag(),mModel);
+                }
+            }
+
+            return false;
+        }
+
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent e) {
+
+            Log.d("KPI Cell", "onSingleTapConfirmed: ");
+            if (mClickBtn != null) {
+                KPIItemButton button = mClickBtn;
+                Integer tag = (Integer) button.getTag();
+                PieChartView.ChartItem item = mChartItems.get(tag);
+                item.display = !item.display;
+                refreshUI();
+            }
+
+            return false;
+        }
+    }
+}

+ 67 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPIDot.java

@@ -0,0 +1,67 @@
+package com.usai.apex.kpi;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class KPIDot extends View {
+    public KPIDot(Context context) {
+        super(context);
+    }
+
+    public KPIDot(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public KPIDot(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private int mWidth,mHeight;
+
+    int dotColor = -1;
+    public void setDotColor(int color) {
+        dotColor = color;
+        invalidate();
+    }
+
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+//        super.onDraw(canvas);
+
+        if (dotColor == -1) {
+            super.onDraw(canvas);
+            return;
+        }
+
+        setBackgroundColor(Color.WHITE);
+
+        Paint brush = new Paint(Paint.ANTI_ALIAS_FLAG);
+        brush.setAntiAlias(true); // 抗锯齿
+        brush.setDither(true); // 防抖动
+        brush.setStyle(Paint.Style.FILL);
+        brush.setColor(dotColor);
+
+        float r = Math.min(mWidth,mHeight) * 0.5f;
+        float x = (mWidth - 2 * r) * 0.5f;
+        float y = (mHeight - 2 * r) * 0.5f;
+        RectF rect = new RectF(x,y,x + 2 * r, y + 2 * r);
+        canvas.drawArc(rect,0,360,true,brush);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        mWidth = w;
+        mHeight = h;
+
+        invalidate();
+    }
+}

+ 47 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPIItemButton.java

@@ -0,0 +1,47 @@
+package com.usai.apex.kpi;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.usai.apex.R;
+
+public class KPIItemButton extends RelativeLayout {
+
+    public KPIItemButton(Context context) {
+        super(context);
+    }
+
+    public KPIItemButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public KPIItemButton(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    private KPIDot mDot;
+    private TextView mTextView;
+
+    public void setDotColor(int color) {
+        if (mDot == null) {
+            mDot = findViewById(R.id.icon_view);
+        }
+        mDot.setDotColor(color);
+    }
+
+    public void setTitle(String title) {
+        if (mTextView == null) {
+            mTextView = findViewById(R.id.name_tv);
+        }
+        mTextView.setText(title);
+    }
+
+    public void setTitleColor(int color) {
+        if (mTextView == null) {
+            mTextView = findViewById(R.id.name_tv);
+        }
+        mTextView.setTextColor(color);
+    }
+}

+ 47 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPIListView.java

@@ -0,0 +1,47 @@
+package com.usai.apex.kpi;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.ListView;
+
+public class KPIListView extends ListView {
+
+    public KPIListView(Context context) {
+        super(context);
+    }
+
+    public KPIListView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public KPIListView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+
+         if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
+             if (mListener != null) {
+                 mListener.KPIListViewTouched(true);
+             }
+        } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
+             if (mListener != null) {
+                 mListener.KPIListViewTouched(false);
+             }
+        }
+
+        return super.onTouchEvent(event);
+    }
+
+    private KPIListViewTouchListener mListener;
+
+    public void setListener(KPIListViewTouchListener listener) {
+        this.mListener = mListener;
+    }
+
+    public interface KPIListViewTouchListener {
+        void KPIListViewTouched(boolean t);
+    }
+}

+ 53 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPISwipeRefresh.java

@@ -0,0 +1,53 @@
+package com.usai.apex.kpi;
+
+import android.content.Context;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+
+public class KPISwipeRefresh extends SwipeRefreshLayout {
+
+    public KPISwipeRefresh(Context context) {
+        super(context);
+    }
+
+    public KPISwipeRefresh(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    private float mFirstPointY = 0;
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+
+        Log.d("Refresh", "onInterceptTouchEvent: " + ev.getY() + "and Action: " + ev.getAction());
+
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mFirstPointY = ev.getY();
+        }
+
+        // 防止下拉和ListView向上滑动冲突
+        if (mFirstPointY > 100) {
+            return false;
+        }
+
+        return super.onInterceptTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+
+        Log.d("Refresh OnTouch", "onInterceptTouchEvent: " + ev.getY() + "and Action: " + ev.getAction());
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mFirstPointY = ev.getY();
+        }
+
+        // 防止下拉和ListView向上滑动冲突
+        if (mFirstPointY > 100) {
+            return false;
+        }
+
+        return super.onTouchEvent(ev);
+    }
+}

+ 88 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/KPIViewPager.java

@@ -0,0 +1,88 @@
+package com.usai.apex.kpi;
+
+import android.content.Context;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+public class KPIViewPager extends ViewPager {
+
+    private boolean scrollEnable = true;
+
+    public KPIViewPager(Context context) {
+        super(context);
+    }
+
+    public KPIViewPager(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setScrollEnable(boolean enable) {
+        scrollEnable = enable;
+    }
+
+    public boolean getScrollEnable() {
+        return scrollEnable;
+    }
+
+//    @Override
+//    public boolean onTouchEvent(MotionEvent ev) {
+//        if (scrollEnable) {
+//            return super.onTouchEvent(ev);
+//        }
+//        return false;
+//    }
+//
+//    @Override
+//    public boolean onInterceptTouchEvent(MotionEvent arg0) {
+//        if (scrollEnable) {
+//            return super.onInterceptTouchEvent(arg0);
+//        }
+//        return false;
+//    }
+
+
+    //mViewTouchMode表示ViewPager是否全权控制滑动事件,默认为true,即控制
+    private boolean mViewTouchMode = true;
+
+    public void setViewTouchMode(boolean b) {
+        if (b && !isFakeDragging()) {
+            //全权控制滑动事件
+            beginFakeDrag();
+        } else if (!b && isFakeDragging()) {
+            //终止控制滑动事件
+            endFakeDrag();
+        }
+        mViewTouchMode = b;
+    }
+
+    /**
+     * 在mViewTouchMode为true的时候,ViewPager不拦截点击事件,点击事件将由子View处理
+     */
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        if (mViewTouchMode || !scrollEnable) {
+            return false;
+        }
+        return super.onInterceptTouchEvent(event);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (scrollEnable) {
+            return super.onTouchEvent(ev);
+        }
+        return false;
+    }
+
+    /**
+     * 在mViewTouchMode为true或者滑动方向不是左右的时候,ViewPager将放弃控制点击事件,
+     * 这样做有利于在ViewPager中加入ListView等可以滑动的控件,否则两者之间的滑动将会有冲突
+     */
+    @Override
+    public boolean arrowScroll(int direction) {
+        if (mViewTouchMode) return false;
+        if (direction != FOCUS_LEFT && direction != FOCUS_RIGHT) return false;
+        return super.arrowScroll(direction);
+    }
+}

+ 710 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/kpi/PieChartView.java

@@ -0,0 +1,710 @@
+package com.usai.apex.kpi;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
+import android.support.annotation.Nullable;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Random;
+
+
+/**
+ * Created by macmini1 on 2018/3/28.
+ */
+
+public class PieChartView extends View {
+
+//    private static final long serialVersionUID = 4564384597971491851L;
+
+    private static float titleFontSize = 40.0f;
+    private static float nameFontSize = 50.0f;
+    private static float detal = 10;
+    private static double M_PI = 3.14159265358979323846264338327950288;
+    private static double M_PI_2 = 1.57079632679489661923132169163975144;
+
+    public interface PieChartItemClickListener {
+
+        void pieChartItemClicked(PieChartView pieChartView, ChartItem item);
+        void pieChartCenterClicked(PieChartView pieChartView);
+        void pieChartDidBeginTouch();
+        void pieChartDidEndTouch();
+    }
+
+    public static class ChartItem implements Serializable {
+
+        private static final long serialVersionUID = 1437379045091025768L;
+
+        public String shortTitle;
+        public boolean display = true;
+
+        public int color = -1;
+        public float value;
+        public String title;
+        public int titleColor = -1;
+
+        private float startAngle;
+        private float angle;
+        private float endAngle;
+        private boolean select;
+        private PointF titlePosition;
+        private float percentage;
+        private Size titleSize;
+
+
+
+        private int getColor() {
+            if (color == -1) {
+                String r,g,b;
+                Random random = new Random();
+                r = Integer.toHexString(random.nextInt(256)).toUpperCase();
+                g = Integer.toHexString(random.nextInt(256)).toUpperCase();
+                b = Integer.toHexString(random.nextInt(256)).toUpperCase();
+
+                r = r.length()==1 ? "0" + r : r ;
+                g = g.length()==1 ? "0" + g : g ;
+                b = b.length()==1 ? "0" + b : b ;
+                color = Color.parseColor("#" + r + g + b);
+            }
+            return color;
+        }
+
+        private int getTitleColor() {
+            if (titleColor == -1) {
+//                String r,g,b;
+//                Random random = new Random();
+//                r = Integer.toHexString(random.nextInt(256)).toUpperCase();
+//                g = Integer.toHexString(random.nextInt(256)).toUpperCase();
+//                b = Integer.toHexString(random.nextInt(256)).toUpperCase();
+//
+//                r = r.length()==1 ? "0" + r : r ;
+//                g = g.length()==1 ? "0" + g : g ;
+//                b = b.length()==1 ? "0" + b : b ;
+//                titleColor = Color.parseColor("#" + r + g + b);
+                titleColor = Color.WHITE;
+            }
+            return titleColor;
+        }
+
+        private PieChartView.Size measure() {
+
+            Paint textPaint = new Paint();
+            textPaint.setColor(getTitleColor());
+            textPaint.setTextSize(titleFontSize);
+            textPaint.setStyle(Paint.Style.FILL);
+            //该方法即为设置基线上那个点到底是left,center,还是right  这里我设置为center
+            textPaint.setTextAlign(Paint.Align.CENTER);
+
+
+            Rect rect = new Rect();
+            String msg = getMessage();
+            textPaint.getTextBounds(msg, 0, msg.length(), rect);
+            int width = rect.width();// 文字宽
+            int height = rect.height();// 文字高
+
+            Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
+            float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
+            float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
+            float baseY = 0 - top / 2.0f - bottom / 2.0f;//基线中间点的y轴计算公式
+
+
+            titleSize = new Size(width,height);
+            return titleSize;
+        }
+
+        public float getPercentage() {
+            return percentage;
+        }
+
+        public void setPercentage(float percent) {
+            percentage = percent;
+        }
+
+        private String getMessage() {
+            return String.format("%.2f%%",percentage * 100);
+        }
+    }
+
+    private static class Size implements Serializable {
+        private static final long serialVersionUID = 3369542887994794927L;
+        int mWidth, mHeight;
+        public Size(int width, int height) {
+            mWidth = width;
+            mHeight = height;
+        }
+    }
+
+    public static int px2dp(Context context, float pxValue) {
+        float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (pxValue / scale + 0.5f);
+    }
+
+    public static int dp2px(Context context, float dpValue) {
+        float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+
+    public static int px2sp(Context context, float pxValue) {
+        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
+        return (int) (pxValue / fontScale + 0.5f);
+    }
+
+    public static int sp2px(Context context, float spValue) {
+        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
+        return (int) (spValue * fontScale + 0.5f);
+    }
+
+
+    private Paint mBrush = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private int mWidth,mHeight;
+    private Context mCtx;
+    private ArrayList<ChartItem> chartItems = new ArrayList<>();
+    private ChartItem mSelectedItem;
+    private float mRadius;
+    private PieChartItemClickListener mPieChartItemClickListener;
+    public float minTitleAngle = 0;
+
+    public float progress = 0;
+
+    public PieChartView(Context context) {
+        this(context,null);
+    }
+
+    public PieChartView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs,0);
+    }
+
+    public PieChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mCtx = context;
+        init();
+    }
+
+    public void setPieChartItemClickListener(PieChartItemClickListener listener) {
+        mPieChartItemClickListener = listener;
+    }
+
+
+    private float total = 0;
+    public void setChartItems(ArrayList<ChartItem> items) {
+        chartItems = items;
+
+        if (items != null) {
+            total = 0;
+            for (int i = 0; i < items.size(); i++) {
+                ChartItem item = items.get(i);
+                total += item.value;
+            }
+
+        } else {
+            chartItems = new ArrayList<>();
+            total = 0;
+        }
+
+        invalidate();
+    }
+
+    private String mName;
+    private int mCount;
+    public void setNameAndCount(String name, int count) {
+        mName = name;
+        mCount = count;
+    }
+
+    public void setRadius(float radius) {
+        mRadius = dp2px(getContext(),radius);
+    }
+
+    private void init() {
+
+        setBackgroundColor(Color.WHITE);
+        mBrush.setAntiAlias(true); // 抗锯齿
+        mBrush.setDither(true); // 防抖动
+        mBrush.setStyle(Paint.Style.FILL);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mWidth = w;
+        mHeight = h;
+
+        mRadius = radius();
+        titleFontSize = 4.0f * px2dp(getContext(),mRadius) / 18.0f;
+        nameFontSize = 5.0f * px2dp(getContext(),mRadius) / 18.0f;
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+
+        if (total == 0) {
+            super.onDraw(canvas);
+        } else {
+
+            prepareItems();
+
+            showPie(canvas);
+
+            float hollowR = radius() * 0.5f;
+            float x = (mWidth - hollowR * 2) * 0.5f;
+            float y = (mHeight - hollowR * 2) * 0.5f;
+
+            RectF rect = new RectF(x, y,x + 2 * hollowR, y + 2 * hollowR);
+
+            Paint hollowPaint = new Paint();
+            hollowPaint.setAntiAlias(true); // 抗锯齿
+            hollowPaint.setDither(true); // 防抖动
+            hollowPaint.setStyle(Paint.Style.FILL);
+            ColorDrawable colordDrawable = (ColorDrawable) getBackground();
+            int color = colordDrawable.getColor();
+            hollowPaint.setColor(color);
+            canvas.drawArc(rect,0,360,true,hollowPaint);
+
+            drawPieTitle(canvas,mName,String.format("%d",mCount));
+        }
+
+    }
+
+    private void showPie(Canvas canvas) {
+
+        for (int i = 0; i < chartItems.size(); i++) {
+            ChartItem item = chartItems.get(i);
+            drawPieItem(canvas,item);
+        }
+    }
+
+    private void prepareItems() {
+
+
+        float perIntervalAngle = 1.0f;
+
+        ArrayList<ChartItem> zeroItems = new ArrayList<>();
+        // 剔除value == 0
+        for (int i = 0; i < chartItems.size(); i++) {
+            ChartItem item = chartItems.get(i);
+            if (item.value == 0) {
+                zeroItems.add(item);
+            }
+        }
+
+        if (zeroItems.size() > 0) {
+            for (int j = 0; j < zeroItems.size(); j++) {
+                ChartItem item = zeroItems.get(j);
+                chartItems.remove(item);
+            }
+        }
+
+        if (chartItems.size() == 1) {
+            perIntervalAngle = 0;
+        }
+        float totalIntervalAngle = perIntervalAngle * chartItems.size();
+        float totalAngle = 360.f - totalIntervalAngle;
+        float currentAngle = perIntervalAngle;
+
+        for (int i = 0; i < chartItems.size(); i++) {
+            ChartItem item = chartItems.get(i);
+            if (total > 0) {
+                item.percentage = item.value / total;
+            } else {
+                item.percentage = 0.f;
+            }
+            item.startAngle = currentAngle;
+            item.angle = totalAngle * item.percentage;
+            item.endAngle = item.startAngle + item.angle;
+
+            currentAngle += item.angle + perIntervalAngle;
+
+
+            float midAngle = (item.startAngle + item.endAngle) * 0.5f;
+
+            PointF point = findTitlePosition(midAngle);
+            item.titlePosition = point;
+            Size titleSize = item.measure();
+//            float x = point.x + titleSize.mWidth * 0.5f;
+//            float y = point.y - titleSize.mHeight * 0.5f;
+//
+//            item.titlePosition = new PointF(x,y);
+
+        }
+
+        // Title
+//        int lcount = lbArr.size() + ltArr.size();
+//        int rcount = rbArr.size() + rtArr.size();
+//
+//        float lh = mHeight / (lcount * 1.0f);
+//        float rh = mHeight / (rcount * 1.0f);
+//
+//        // 0
+//        for (int i = rbArr.size() - 1; i >= 0; i--) {
+//            // 最后一个Title在最下
+//            ChartItem item = rbArr.get(i);
+//            int index = (rbArr.size() - 1) - i;
+//
+//            float maxY = mHeight - rh * index;
+//            float minY = mHeight - rh * (index + 1);
+//            Size titleSize = item.measure();
+//
+////            float y = mHeight - rh * (index + 0.5f);
+//            float y = perfectY(maxY,minY,item.lineEndPoint.y,titleSize.mHeight);
+//            float x = mWidth * 1.0f - titleSize.mWidth;
+//            item.baseX = x + 0.5f * titleSize.mWidth;
+//
+//            item.titlePoint = new PointF(x,y);
+////            Log.d("prepareItems", "RB: " + item.title);
+//        }
+//        // 1
+//        for (int i = 0; i < lbArr.size(); i++) {
+//            // 第一个Title在最下
+//            ChartItem item = lbArr.get(i);
+//            int index = i;
+//            float maxY = mHeight - lh * index;
+//            float minY = mHeight - lh * (index + 1);
+//            Size titleSize = item.measure();
+//
+////            float y = mHeight - lh * (index + 0.5f);
+//            float y = perfectY(maxY,minY,item.lineEndPoint.y,titleSize.mHeight);
+//            float x = titleSize.mWidth;
+//            item.baseX = x - 0.5f * titleSize.mWidth;
+//
+//            item.titlePoint = new PointF(x,y);
+////            Log.d("prepareItems", "LB: " + item.title);
+//        }
+//
+//        // 2
+//        for (int i = ltArr.size() - 1; i >= 0; i--) {
+//            //最后一个Title在最上
+//            ChartItem item = ltArr.get(i);
+//            int index = (ltArr.size() - 1) - i;
+//
+//            float minY = lh * index;
+//            float maxY = lh * (index + 1);
+//            Size titleSize = item.measure();
+//
+////            float y = lh * (index + 0.5f);
+//            float x = titleSize.mWidth;
+//            float y = perfectY(maxY,minY,item.lineEndPoint.y,titleSize.mHeight);
+//            item.baseX = x - 0.5f * titleSize.mWidth;
+//
+//            item.titlePoint = new PointF(x,y);
+////            Log.d("prepareItems", "LT: " + item.title);
+//        }
+//
+//        // 3
+//        for (int i = 0; i < rtArr.size(); i++) {
+//            // 第一个Title在最上
+//            ChartItem item = rtArr.get(i);
+//            int index = i;
+//
+//            float minY = rh * index;
+//            float maxY = rh * (index + 1);
+//            Size titleSize = item.measure();
+//
+////            float y = rh * (index + 0.5f);
+//            float x = mWidth * 1.0f - titleSize.mWidth;
+//            float y = perfectY(maxY,minY,item.lineEndPoint.y,titleSize.mHeight);
+//            item.baseX = x + 0.5f * titleSize.mWidth;
+//
+//            item.titlePoint = new PointF(x,y);
+//            Log.d("prepareItems", "RT: " + item.title);
+//        }
+
+    }
+
+    public float perfectY(float maxY, float minY,float py, float h) {
+        float min_y = py - h * 0.5f, max_y = py + h * 0.5f;
+        if (min_y >= minY && max_y <= maxY) {
+            return py;
+        }
+
+        if ((min_y - minY) < 0) {
+            py += minY - min_y;
+        } else {
+            py -= max_y - maxY;
+        }
+
+        return py;
+    }
+
+    private void drawPieTitle(Canvas canvas, String title, String count) {
+
+        if (canvas == null || title == null || count == null) {
+            return;
+        }
+
+        if (title.length() == 0 || count.length() == 0) {
+            return;
+        }
+
+        float centerX = mWidth * 0.5f;
+        float centerY = mHeight * 0.5f;
+
+        float r = mRadius * 0.5f;
+        float w = (float) (Math.sqrt(Math.pow(r,2) / 2)) * 2.0f;
+        float h = w;
+
+        float x = centerX - w * 0.5f;
+        float y = centerY - h * 0.5f;
+
+//        String msg = "Per ETA\r\nContainer\r\n485845";
+
+//        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+//        paint.setStyle(Paint.Style.STROKE);
+//        canvas.drawLine(x,y,x + w,y,paint);
+
+        String msg = title + "\r\n" + count;
+
+        canvas.save();
+
+        TextPaint textPaint = new TextPaint();
+        textPaint.setColor(Color.BLACK);
+        textPaint.setTextSize(nameFontSize);
+        textPaint.setAntiAlias(true);
+
+        StaticLayout layout = new StaticLayout(msg, textPaint, (int)w, Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);
+
+        y = y + (h - layout.getHeight()) * 0.5f;
+        canvas.translate(x,y);
+        layout.draw(canvas);
+
+        canvas.restore();
+
+
+
+//        canvas.drawText(msg,x,y,textPaint);
+    }
+
+    private void drawPieItem(Canvas canvas,ChartItem item) {
+        if (item == null || canvas == null) {
+            return;
+        }
+
+        // draw Pie
+        if (item.angle > 0) {
+            float r = radius();
+            if (item.select) {
+                r += detal * progress;
+            }
+            float x = (mWidth - r * 2) * 0.5f;
+            float y = (mHeight - r * 2) * 0.5f;
+
+            RectF rect = new RectF(x, y,x + 2 * r, y + 2 * r);
+
+            mBrush.setColor(item.getColor());
+            canvas.drawArc(rect,item.startAngle,item.angle,true,mBrush);
+        }
+
+        if (minTitleAngle > item.angle) {
+            return;
+        }
+
+        // draw Title
+        Paint textPaint = new Paint();
+        textPaint.setColor(item.getTitleColor());
+        textPaint.setTextSize(titleFontSize);
+        textPaint.setStyle(Paint.Style.FILL);
+        //该方法即为设置基线上那个点到底是left,center,还是right  这里我设置为center
+        textPaint.setTextAlign(Paint.Align.CENTER);
+
+        String msg = item.getMessage();
+        canvas.drawText(msg,item.titlePosition.x,item.titlePosition.y + item.titleSize.mHeight * 0.5f,textPaint);
+
+
+//        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+//        paint.setStyle(Paint.Style.STROKE);
+//        canvas.drawLine(item.titlePosition.x - 40.0f,item.titlePosition.y,item.titlePosition.x + 40.0f, item.titlePosition.y,paint);
+//        canvas.drawLine(item.titlePosition.x,item.titlePosition.y - 400.f,item.titlePosition.x, item.titlePosition.y + 40.0f,paint);
+
+    }
+
+    private PointF center() {
+        return new PointF(mWidth * 0.5f,mHeight * 0.5f);
+    }
+
+    private float radius() {
+//        if (mRadius <= 0) {
+            return Math.min(mWidth,mHeight) * 0.5f * 0.9f;
+//        } else {
+//            return mRadius;
+//        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+
+        if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
+
+            float touchX = event.getX();
+            float touchY = event.getY();
+
+            float distance = (float) Math.sqrt(Math.pow(center().x - touchX,2) + Math.pow(center().y - touchY,2));
+
+            if (distance < radius() * 0.5f) {
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                    if (mPieChartItemClickListener != null) {
+                        mPieChartItemClickListener.pieChartDidBeginTouch();
+                    }
+                }
+
+                if (mPieChartItemClickListener != null) {
+                    mPieChartItemClickListener.pieChartCenterClicked(this);
+                }
+                return true;
+            }
+
+            if (distance > radius()) {
+                return super.onTouchEvent(event);
+            }
+
+            if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                if (mPieChartItemClickListener != null) {
+                    mPieChartItemClickListener.pieChartDidBeginTouch();
+                }
+            }
+
+            double rad_angle = findAngleBytouchPoint(touchX,touchY);
+            float angle = (float) (180.0f / M_PI * rad_angle);
+
+            Log.d("Touch", String.format("onTouch Angle: %f",angle));
+
+            Iterator iterator = chartItems.iterator();
+            while (iterator.hasNext()) {
+                ChartItem item = (ChartItem) iterator.next();
+                if (item.startAngle <= angle && item.endAngle >= angle) {
+                    if (mSelectedItem != null) {
+                        if (mSelectedItem == item) {
+                            break;
+                        } else {
+                            mSelectedItem.select = false;
+                        }
+                    }
+                    mSelectedItem = item;
+                    mSelectedItem.select = true;
+                    invalidate();
+                    if (mPieChartItemClickListener != null) {
+                        mPieChartItemClickListener.pieChartItemClicked(this,item);
+                    }
+                    break;
+                }
+            }
+            return true;
+        } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) {
+
+            if (mPieChartItemClickListener != null) {
+                mPieChartItemClickListener.pieChartDidEndTouch();
+            }
+
+            if (mSelectedItem != null) {
+                mSelectedItem.select = false;
+                invalidate();
+                mSelectedItem = null;
+            }
+            if (mPieChartItemClickListener != null) {
+                mPieChartItemClickListener.pieChartItemClicked(this,null);
+            }
+
+        }
+
+
+
+        return super.onTouchEvent(event);
+    }
+
+    private double findAngleBytouchPoint(float touchX, float touchY) {
+
+        float r = mRadius;
+        float x = (mWidth - r * 2) * 0.5f;
+        float y = (mHeight - r * 2) * 0.5f;
+        RectF rect = new RectF(x, y,x + 2 * r, y + 2 * r);
+
+        if (rect.contains(touchX,touchY)) {
+
+            float centerX = mWidth * 0.5f;
+            float centerY = mHeight * 0.5f;
+
+            float distance = (float) Math.sqrt(Math.pow(centerX - touchX,2) + Math.pow(centerY - touchY,2));
+            float angle = (float) Math.asin(Math.abs(touchY - centerY) / distance);
+
+            float offsetX = touchX - centerX;
+            float offsetY = touchY - centerY;
+
+
+            if (offsetX > 0 && offsetY > 0) {
+                return angle;
+            }
+            if (offsetX < 0 && offsetY > 0) {
+                return M_PI - angle;
+            }
+            if (offsetX < 0 && offsetY < 0) {
+                return M_PI + angle;
+            }
+            if (offsetX > 0 && offsetY < 0) {
+                return M_PI * 2 - angle;
+            }
+            if (offsetX == 0) {
+                if (offsetY > 0) {
+                    return M_PI;
+                }
+                if (offsetY < 0) {
+                    return M_PI_2 * 3;
+                }
+            }
+            if (offsetY == 0) {
+                if (offsetX > 0) {
+                    return 0;
+                }
+                if (offsetX < 0) {
+                    return M_PI;
+                }
+            }
+
+            return 0;
+
+        }
+        return 0;
+    }
+
+    private PointF findTitlePosition(float angle) {
+
+        float centerX = mWidth * 0.5f;
+        float centerY = mHeight * 0.5f;
+        float r = mRadius * 0.75f;
+        float rad = (float) (angle * M_PI / 180.0f);
+
+        return new PointF(centerX + (float) Math.cos(rad) * r, centerY + (float) Math.sin(rad) * r);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+
+//        KPICell p = (KPICell) getParent();
+//        int w = p.getKPIWidth();
+//
+//        int leftInterval = dp2px(getContext(),60);
+//        int rightInterval = dp2px(getContext(),60);
+//
+//        int pieW = (w - leftInterval - rightInterval);
+
+//        widthMeasureSpec = MeasureSpec.makeMeasureSpec(pieW, MeasureSpec.EXACTLY);
+//        heightMeasureSpec = MeasureSpec.makeMeasureSpec(pieW, MeasureSpec.EXACTLY);
+
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        heightMeasureSpec = MeasureSpec.makeMeasureSpec(width,MeasureSpec.EXACTLY);
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+}

+ 1 - 2
ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/HistoryFragment.java

@@ -1,7 +1,6 @@
 package com.usai.apex.mainframe;
 
 
-import android.app.Activity;
 import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -13,7 +12,7 @@ import android.widget.ListView;
 
 import com.usai.apex.ApexTrackingApplication;
 import com.usai.apex.R;
-import com.usai.apex.Result.PullRefreshListView;
+import com.usai.apex.result.PullRefreshListView;
 import com.usai.util.Network;
 import com.usai.util.dbUtil;
 

+ 4 - 5
ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/KPIFragment.java

@@ -25,12 +25,11 @@ import android.view.ViewGroup;
 import android.widget.ProgressBar;
 
 import com.usai.apex.ApexTrackingApplication;
-import com.usai.apex.KPI.KPICell;
-import com.usai.apex.KPI.KPIViewPager;
-import com.usai.apex.KPI.PieChartView;
+import com.usai.apex.kpi.KPICell;
+import com.usai.apex.kpi.KPIViewPager;
+import com.usai.apex.kpi.PieChartView;
 import com.usai.apex.R;
-import com.usai.apex.Result.AMResultActivity;
-import com.usai.apex.ResultActivity;
+import com.usai.apex.result.AMResultActivity;
 import com.usai.util.Network;
 
 import org.json.JSONArray;

+ 1 - 1
ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/NewDetailActivity.java

@@ -25,7 +25,7 @@ import android.widget.TextView;
 import com.usai.apex.ApexTrackingApplication;
 import com.usai.apex.DetailFragment;
 import com.usai.apex.R;
-import com.usai.apex.Result.AMResultActivity;
+import com.usai.apex.result.AMResultActivity;
 import com.usai.apex.ViewPagerAdapter;
 import com.usai.util.commonUtil;
 import com.usai.util.dbUtil;

+ 1 - 2
ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/RecentFragment.java

@@ -1,7 +1,6 @@
 package com.usai.apex.mainframe;
 
 
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -16,7 +15,7 @@ import android.widget.ListView;
 
 import com.usai.apex.ApexTrackingApplication;
 import com.usai.apex.R;
-import com.usai.apex.ShipMap.ShipMap;
+import com.usai.apex.shipmap.ShipMap;
 import com.usai.util.Network;
 import com.usai.util.RAUtil;
 import com.usai.util.dbUtil;

+ 2 - 2
ApexDrivers/apexmobile/src/main/java/com/usai/apex/mainframe/TrackingListFragment.java

@@ -28,8 +28,8 @@ import android.widget.TextView;
 
 import com.usai.apex.ApexTrackingApplication;
 import com.usai.apex.R;
-import com.usai.apex.Result.PullRefreshListView;
-import com.usai.apex.ShipMap.ShipMap;
+import com.usai.apex.result.PullRefreshListView;
+import com.usai.apex.shipmap.ShipMap;
 import com.usai.util.commonUtil;
 
 import org.apache.http.util.EncodingUtils;

+ 646 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/result/AMResultActivity.java

@@ -0,0 +1,646 @@
+package com.usai.apex.result;
+
+import android.app.Dialog;
+import android.app.DownloadManager;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.usai.apex.ApexTrackingApplication;
+import com.usai.apex.CustomizeFieldsActivity;
+import com.usai.apex.R;
+import com.usai.apex.mainframe.NewDetailActivity;
+import com.usai.apex.pdf.PDFPreviewActivity;
+import com.usai.util.Network;
+import com.usai.util.RAUtil;
+import com.usai.util.dbUtil;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Created by macmini1 on 2018/2/23.
+ */
+
+public class AMResultActivity extends SearchResultActivity {
+    TextView mtitleview;
+    private static int REQUEST_FIELD_SETTING = 1000;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+
+        setCustomActionBar();
+
+    }
+    private void setCustomActionBar() {
+        ActionBar.LayoutParams lp =new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT, Gravity.CENTER);
+        View mActionBarView = LayoutInflater.from(this).inflate(R.layout.actionbar_customtitle, null);
+
+        mtitleview= mActionBarView.findViewById(R.id.title);
+        String title = mParams.getString("title");
+        mtitleview.setText(title);
+        setTitle(title);
+//
+//        mActionBarView.setBackgroundColor(Color.YELLOW);
+//        titleview.setBackgroundColor(Color.BLUE);
+        ActionBar actionBar = getSupportActionBar();
+        actionBar.setCustomView(mActionBarView, lp);
+//        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
+//        actionBar.setDisplayShowCustomEnabled(true);
+        actionBar.setDisplayHomeAsUpEnabled(true);
+
+
+//        actionBar.setIcon(getNumberDrawable());
+//        actionBar.setDisplayShowHomeEnabled(true);
+        actionBar.setDisplayShowTitleEnabled(true);
+    }
+//    @Override
+//    public void setTitle(CharSequence title) {
+////        View mActionBarView = LayoutInflater.from(this).inflate(R.layout.actionbar_customtitle, null);
+////
+////        TextView mtitleviewtitleview = mActionBarView.findViewById(R.id.title);
+//
+//        if(title==null)
+//            title="";
+//        if(mtitleview!=null)
+//            mtitleview.setText(title);
+//    }
+    @Override
+    protected void loadData() {
+        if (mParams.getString("columns") == null) {
+            ArrayList<String> header_name = new ArrayList<String>();
+            ArrayList<String> header_aname = new ArrayList<String>();
+            getHeader(header_name, header_aname);
+            String fields = "";
+            Iterator<String> iterator = header_name.iterator();
+            while (iterator.hasNext()) {
+                String name = iterator.next();
+                fields = fields + name + ",";
+            }
+            if (fields.length() > 0) {
+                fields = fields.substring(0, fields.length() - 1);
+            }
+            mParams.putString("columns", fields);
+        }
+        super.loadData();
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+//        resultListView.setAdapter(adapter);
+//
+//        Iterator<String> keyIterator = resultData.keys();
+//        ArrayList<String> keys = new ArrayList<>();
+//        while (keyIterator.hasNext()) {
+//            String key = keyIterator.next();
+//            keys.add(key);
+//        }
+//        for (int i = 0; i < keys.size(); i++) {
+//            String key = keys.get(i);
+//            resultData.remove(key);
+//        }
+//
+//        adapter.notifyDataSetChanged();
+
+        if (requestCode == REQUEST_FIELD_SETTING) {
+
+            ArrayList<String> header_name = new ArrayList<String>();
+            ArrayList<String> header_aname = new ArrayList<String>();
+            getHeader(header_name,header_aname);
+            String fields = "";
+            Iterator<String> iterator = header_name.iterator();
+            while (iterator.hasNext()) {
+                String name = iterator.next();
+                fields = fields + name + ",";
+            }
+            fields = fields.substring(0,fields.length() - 1);
+            mParams.putString("columns",fields);
+
+
+            loadData();
+
+        }
+
+    }
+
+    // 动态修改Menu
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+        menu.clear();
+
+
+        if (resultData != null && resultData.length() > 0) {
+            try {
+                JSONArray menu_json = resultData.getJSONArray("menu");
+
+                if (menu_json != null && menu_json.length() > 0) {
+
+                    for (int i = 0; i < menu_json.length(); i++) {
+                        JSONObject json = menu_json.getJSONObject(i);
+                        String title = json.getString("title");
+                        menu.add(0, i, 0, title);
+                    }
+                }
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return true;
+    }
+
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+
+
+        int which = item.getItemId();
+
+        switch (item.getItemId())
+        {
+
+            case android.R.id.home:
+                finish();
+                break;
+            default:
+            {
+                try {
+                    JSONArray menu = resultData.getJSONArray("menu");
+                    JSONObject json = menu.getJSONObject(which);
+
+                    String actionType = json.getString("action");
+                    String url = json.optString("url");
+
+
+
+                    if (actionType.equals("field_setting")) {
+
+                        fieldSetting();
+                    } else if (actionType.equals("save")) {
+
+                        save();
+                    } else if (actionType.equals("download")) {
+
+                        export(url);
+                    }
+
+                } catch (JSONException exception) {
+                    Log.d("Result", "onClick: ",exception);
+                }
+            }
+        }
+
+
+
+        return true;
+    }
+
+
+    @Override
+    public void cellDoubleTapAction(final int position) {
+
+        final JSONArray content_action = contentAction();
+        if (content_action != null) {
+
+            try {
+                if (content_action.length() == 1) {
+
+                    JSONObject action = content_action.getJSONObject(0);
+                    String module = action.getString("module");
+
+                    if (module.equals("quick_look")) {
+
+                        showQuickLookForPosition(position,action);
+
+                    } else if (module.equals("detail")) {
+
+                        showDetailForPosition(position);
+                    }
+
+
+                } else if (content_action.length() > 1) {
+
+                    ArrayList<String> titleList = new ArrayList<>();
+
+                    for (int i = 0; i < content_action.length(); i++) {
+                        JSONObject json = content_action.getJSONObject(i);
+                        String title = json.getString("title");
+                        titleList.add(title);
+                    }
+
+                    new AlertDialog.Builder(mContext)
+                            .setSingleChoiceItems((String[])titleList.toArray(new String[titleList.size()]), -1, new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int which) {
+
+                                    try {
+
+                                        JSONObject json = content_action.getJSONObject(which);
+                                        String module = json.getString("module");
+
+                                        if (module.equals("quick_look")) {
+
+                                            showQuickLookForPosition(position,json);
+                                        } else if (module.equals("detail")) {
+
+                                            showDetailForPosition(position);
+                                        }
+
+
+                                    } catch (JSONException exception) {
+                                        Log.d("Result", "onClick: ",exception);
+                                    }
+                                    dialog.dismiss();
+
+                                }
+                            })
+                            .show();
+                }
+
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+
+        }
+
+    }
+
+    public void showDetailForPosition(final int position) {
+
+        ArrayList<String> actions = getActions();
+        if (actions.size() < 1) {
+            return;
+        }
+
+        try {
+            JSONArray arr_col = contentLayout().getJSONObject("header").getJSONArray("col");
+            JSONArray item = contentData().getJSONArray("item_" + (position - 1));
+
+            String module_name = mParams.getString("module_name");
+            String detail_id = item.getString(arr_col.length());
+
+            Intent intent = new Intent(mContext, NewDetailActivity.class);
+            intent.putExtra("function_name", module_name);
+            intent.putExtra("actions_count", actions.size());
+            intent.putExtra("_id",detail_id);
+
+            Iterator<String> iterator = actions.iterator();
+            int i = 0;
+            while (iterator.hasNext()) {
+                String name = iterator.next();
+                intent.putExtra("action" + i++, name);
+            }
+            startActivity(intent);
+
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+    }
+    @Override
+    public void showQuickLook(final JSONObject param, final String url) {
+
+        showProgressDialog("Please wait","Downloading...");
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                String cacheDir = ApexTrackingApplication.getInstance().getExternalCacheDir().getAbsolutePath();//ApexTrackingApplication.getInstance().getDocumentDir();
+
+                // 下载文件
+                final File downloadFile = Network.downloadFile(RAUtil.Json2Bundle(param),url,cacheDir);
+
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        progressDialog.dismiss();
+                        if (downloadFile != null && downloadFile.exists()) {
+                            String email = null,email_subject = null,email_content = null;
+                            try {
+                                //此处需要新增保存文档的本地表
+
+                                email=param.getString("email");
+                                email_subject=param.getString("email_subject");
+                                email_content=param.getString("email_content");
+
+                            } catch (JSONException e) {
+                                e.printStackTrace();
+                            }
+                            previewPDF(downloadFile.getAbsolutePath(),email,email_subject,email_content);
+                        } else {
+                            showAlert("Sorry,there is a wrong.");
+                        }
+                    }
+                });
+
+            }
+        }).start();
+
+
+    }
+    public void showQuickLookForPosition(final int position,JSONObject action) {
+
+        try {
+
+            JSONObject params = new JSONObject();
+            Iterator<String> iterator = action.getJSONObject("params").keys();
+            while (iterator.hasNext()) {
+                String key = iterator.next();
+                JSONArray item = contentData().getJSONArray("item_" + (position - 1));
+                int idx = action.getJSONObject("params").getInt(key);
+                params.put(key,item.get(idx));
+            }
+
+            String url = action.getString("url");
+//            String module_name = mParams.getString("module_name");
+
+            showQuickLook(params,url);
+//            downloaddoc(url);
+
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+
+    protected void previewPDF(String file,String email,String subject,String content) {
+        Intent myIntent = new Intent();
+        myIntent = new Intent(AMResultActivity.this, PDFPreviewActivity.class);
+
+        myIntent.putExtra("file",file);
+        myIntent.putExtra("iscache",true);
+
+        try {
+            JSONObject json = new JSONObject();
+//            email = "66666@qq.com";
+//            subject = "test subject";
+//            content = "test body";
+            if (email != null) {
+                json.put("email",email);
+            }
+            if (subject != null) {
+                json.put("subject",subject);
+            }
+            if (content != null) {
+                json.put("content",content);
+            }
+            myIntent.putExtra("email",json.toString());
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+
+        startActivity(myIntent);
+    }
+
+    private void downloaddoc(String url)
+    {
+
+            // if (true)
+            // return;
+//            URLSpan span[] = ((TextView) v).getUrls();
+//            if (span.length < 1)
+//                return;
+//            span[0].getURL();
+//            Log.d("Text", span[0].getURL());
+//
+//            TextView tv = (TextView)v;
+
+            final DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
+
+            Uri uri = Uri.parse(url);
+            final DownloadManager.Request request = new DownloadManager.Request(uri);
+
+            // 设置允许使用的网络类型,这里是移动网络和wifi都可以
+            request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
+                    | DownloadManager.Request.NETWORK_WIFI);
+
+            request.setDestinationInExternalPublicDir("Apex Mobile",url);
+
+            // 禁止发出通知,既后台下载,如果要使用这一句必须声明一个权限:android.permission.DOWNLOAD_WITHOUT_NOTIFICATION
+            // request.setShowRunningNotification(false);
+
+            // 不显示下载界面
+            request.setVisibleInDownloadsUi(false);
+            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
+
+							/*
+							 * 设置下载后文件存放的位置,如果sdcard不可用,那么设置这个将报错,
+							 * 因此最好不设置如果sdcard可用,下载后的文件 在/mnt/sdcard/Android/
+							 * data/packageName/files目录下面
+							 * ,如果sdcard不可用,设置了下面这个将报错,不设置,下载后的文件在/cache这个 目录下面
+							 */
+            // request.setDestinationInExternalFilesDir(this,
+            // null, "tar.apk");
+
+            android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(
+                    AMResultActivity.this);
+            builder.setMessage(getString(R.string.str_downloadmessage));
+
+            builder.setTitle(getString(R.string.str_confirmdownload));
+
+            builder.setPositiveButton(
+                    getString(R.string.str_download),
+                    new Dialog.OnClickListener()
+                    {
+
+                        @Override
+                        public void onClick(
+                                DialogInterface dialog,
+                                int which)
+                        {
+                            downloadManager.enqueue(request);
+                            dialog.dismiss();
+
+                        }
+                    });
+
+            builder.setNegativeButton(
+                    getString(R.string.str_cancel),
+                    new Dialog.OnClickListener()
+                    {
+
+                        @Override
+                        public void onClick(
+                                DialogInterface dialog,
+                                int which)
+                        {
+                            dialog.dismiss();
+                        }
+                    });
+
+            builder.create().show();
+
+
+    }
+
+    public void getHeader(ArrayList<String> header_name, ArrayList<String> header_aname) {
+
+        String module_name = mParams.getString("module_name");
+        String user = ApexTrackingApplication.get_user();
+
+        SQLiteDatabase db = dbUtil.OpenDB(this, null, false);
+        Cursor cursor = db.query("fields_info", new String[] { "aname", "name",
+                "_id" }, "function_name='" + module_name + "' and user='"
+                + user + "' and behavior=" + Network.BEHAVIOR_RESULT
+                + " and show = 1", null, null, null, "priority , aname", null);
+        while (cursor.moveToNext())
+        {
+            String aname = cursor.getString(0);
+            String name = cursor.getString(1);
+
+            header_name.add(name);
+            header_aname.add(aname);
+        }
+        dbUtil.CloseCursor(cursor);
+        dbUtil.CloseDB(db);
+    }
+
+    public ArrayList<String> getActions() {
+
+        String module_name = mParams.getString("module_name");
+
+        SQLiteDatabase db = dbUtil.OpenDB(this, null, false);
+        Cursor cursor = db.query("actions_info",
+                new String[] { "name" }, "function_name='"
+                        + module_name + "' and user='" + ApexTrackingApplication.get_user() + "'", null,
+                null, null, "priority", null);
+
+        ArrayList<String> actions = new ArrayList<>();
+
+        while (cursor.moveToNext())
+        {
+            String name = cursor.getString(0);
+            actions.add(name);
+        }
+        dbUtil.CloseCursor(cursor);
+        dbUtil.CloseDB(db);
+
+        return actions;
+
+    }
+
+    public void save() {
+
+        final View edit = new EditText(this);
+        new android.app.AlertDialog.Builder(this)
+                .setIconAttribute(android.R.attr.alertDialogIcon)
+                .setTitle(R.string.str_createname)
+                .setView(edit)
+                .setPositiveButton(android.R.string.ok,
+                        new DialogInterface.OnClickListener()
+                        {
+                            public void onClick(DialogInterface dialog,
+                                                int whichButton)
+                            {
+                                String name = ((EditText) edit)
+                                        .getText().toString();
+
+                                if(TextUtils.isEmpty(name))
+                                {
+                                    new android.app.AlertDialog.Builder(AMResultActivity.this)
+                                            .setTitle("Warning")
+                                            .setMessage("Name can not be empty.")
+
+                                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                                @Override
+                                                public void onClick(DialogInterface dialog, int which) {
+
+                                                }
+                                            })
+                                            .show();
+                                    return;
+                                }
+
+                                String param = getIntent().toUri(0);
+
+                                JSONObject obj = new JSONObject();
+                                Set<String> keys = mParams.keySet();
+                                for (String key : keys)
+                                {
+
+
+                                    try
+                                    {
+                                        obj.put(key, mParams.get(key).toString());
+
+                                    }
+                                    catch (JSONException e)
+                                    {
+                                        // TODO Auto-generated catch block
+                                        e.printStackTrace();
+                                    }
+
+                                }
+                                obj.toString();
+
+                                SQLiteDatabase db = dbUtil.OpenDB(
+                                        ApexTrackingApplication.get_instance(), null, true);
+                                db.execSQL("insert into history(params,name,criterion,module_name,user,create_time) values('"
+
+                                        + param
+                                        + "','"
+                                        + name
+                                        + "','"
+                                        + obj.toString()
+                                        + "','"
+                                        + mParams.getString("module_name")
+                                        + "','"
+                                        + ApexTrackingApplication.get_user()
+                                        + "',"
+                                        + System.currentTimeMillis() + ")");
+                                dbUtil.CloseDB(db);
+
+										/* User clicked OK so do some stuff */
+                            }
+                        })
+                .setNegativeButton(android.R.string.cancel,
+                        new DialogInterface.OnClickListener()
+                        {
+                            public void onClick(DialogInterface dialog,
+                                                int whichButton)
+                            {
+
+										/* User clicked cancel so do some stuff */
+                            }
+                        }).create().show();
+    }
+
+    public void fieldSetting() {
+
+        Intent intent = new Intent();
+        intent.setClass(this, CustomizeFieldsActivity.class);
+        intent.putExtra("user", ApexTrackingApplication.get_user());
+        intent.putExtra("function_name", mParams.getString("module_name"));
+        intent.putExtra("behavior", Network.BEHAVIOR_RESULT);
+        startActivityForResult(intent,REQUEST_FIELD_SETTING);
+
+    }
+
+}

+ 348 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/result/PullRefreshListView.java

@@ -0,0 +1,348 @@
+package com.usai.apex.result;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.RotateAnimation;
+import android.widget.AbsListView;
+import android.widget.ListView;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class PullRefreshListView extends ListView implements AbsListView.OnScrollListener {
+
+    /**
+     * 头布局
+     */
+    private View headerView;
+
+    /**
+     * 头部布局的高度
+     */
+    private int headerViewHeight;
+
+    /**
+     * 底部布局
+     */
+    private View footerView;
+
+
+    /**
+     * 底部布局的高度
+     */
+    private int footerViewHeight;
+
+
+    /**
+     * 按下时的Y坐标
+     */
+    private int downY;
+
+    public static final int PULL_REFRESH = 0;//下拉刷新的状态
+    public static final int RELEASE_REFRESH = 1;//松开刷新的状态
+    public static final int REFRESHING = 2;//正在刷新的状态
+
+    /**
+     * 当前下拉刷新处于的状态
+     */
+    private int currentState = PULL_REFRESH;
+
+    /**
+     * 头部布局在下拉刷新改变时,图标的动画
+     */
+    private RotateAnimation upAnimation,downAnimation;
+
+    private boolean isLoadingMore = false;
+    private boolean isRefreshing = false;
+
+    public PullRefreshListView(Context context) {
+        this(context,null);
+    }
+
+    public PullRefreshListView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    private void init(){
+        //设置滑动监听
+        setOnScrollListener(this);
+        //初始化头布局
+        initHeaderView();
+        //初始化头布局中图标的旋转动画
+        initRotateAnimation();
+        //初始化为尾布局
+        initFooterView();
+    }
+
+    @Override
+    public void setLayoutParams(ViewGroup.LayoutParams params) {
+        super.setLayoutParams(params);
+    }
+
+    /**
+     * 初始化headerView
+     */
+    private void initHeaderView() {
+
+//        headerView =  View.inflate(getContext(), R.layout.refresh_header, null);
+        if (headerView != null) {
+            //测量headView的高度
+            headerView.measure(0, 0);
+            //获取高度,并保存
+            headerViewHeight = headerView.getMeasuredHeight();
+            //设置paddingTop = -headerViewHeight;这样,该控件被隐藏
+//            headerView.setPadding(0, -headerViewHeight, 0, 0);
+            headerStateChange(currentState,-headerViewHeight);
+            //添加头布局
+            addHeaderView(headerView);
+        }
+    }
+
+    /**
+     * 初始化旋转动画
+     */
+    private void initRotateAnimation() {
+
+        upAnimation = new RotateAnimation(0, -180,
+                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
+                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
+        upAnimation.setDuration(300);
+        upAnimation.setFillAfter(true);
+
+        downAnimation = new RotateAnimation(-180, -360,
+                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
+                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
+        downAnimation.setDuration(300);
+        downAnimation.setFillAfter(true);
+    }
+
+    //初始化底布局,与头布局同理
+    private void initFooterView() {
+
+//        footerView =  View.inflate(getContext(), R.layout.refresh_footer, null);
+        if (footerView != null) {
+            footerView.measure(0, 0);
+            footerViewHeight = footerView.getMeasuredHeight();
+//            footerView.setPadding(0, -footerViewHeight, 0, 0);
+            footerStateChange(PULL_REFRESH, -footerViewHeight);
+            addFooterView(footerView);
+        }
+    }
+
+    public void setRefreshHeader(View header) {
+        headerView = header;
+        initHeaderView();
+    }
+
+    public void setRefreshFooter(View footer) {
+        footerView = footer;
+        initFooterView();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+
+        if (headerView == null) {
+            return super.onTouchEvent(ev);
+        }
+
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                //获取按下时y坐标
+                downY = (int) ev.getY();
+                break;
+            case MotionEvent.ACTION_MOVE:
+
+                if(currentState==REFRESHING){
+                    //如果当前处在滑动状态,则不做处理
+                    break;
+                }
+                //手指滑动偏移量
+                int deltaY = (int) (ev.getY() - downY);
+
+                //获取新的padding值
+                int paddingTop = -headerViewHeight + deltaY;
+
+                if(paddingTop>-headerViewHeight && getFirstVisiblePosition()==0){
+                    //向下滑,且处于顶部,设置padding值,该方法实现了顶布局慢慢滑动显现
+//                    headerView.setPadding(0, paddingTop, 0, 0);
+
+
+                    if(paddingTop>=0 && currentState==PULL_REFRESH){
+
+                        //从下拉刷新进入松开刷新状态
+                        currentState = RELEASE_REFRESH;
+                    }else if (paddingTop<0 && currentState==RELEASE_REFRESH) {
+
+                        //进入下拉刷新状态
+                        currentState = PULL_REFRESH;
+                    }
+
+                    headerStateChange(currentState,paddingTop);
+
+                    return true;//拦截TouchMove,不让listview处理该次move事件,会造成listview无法滑动
+                }
+
+
+                break;
+            case MotionEvent.ACTION_UP:
+
+                if(currentState==PULL_REFRESH){
+                    //仍处于下拉刷新状态,未滑动一定距离,不加载数据,隐藏headView
+//                    headerView.setPadding(0, -headerViewHeight, 0, 0);
+                    headerStateChange(currentState,-headerViewHeight);
+
+                }else if (currentState==RELEASE_REFRESH) {
+
+                    //滑倒一定距离,显示无padding值得headcView
+//                    headerView.setPadding(0, 0, 0, 0);
+
+                    //设置状态为刷新
+                    currentState = REFRESHING;
+
+                    //刷新头部布局
+                    headerStateChange(currentState,0);
+
+                }
+                break;
+        }
+        return super.onTouchEvent(ev);
+    }
+
+
+    private void headerStateChange(int state,int offset) {
+
+        if (state == REFRESHING) {
+            isRefreshing = true;
+        }
+
+        if (headerView == null) {
+            return;
+        }
+
+        headerView.setPadding(0, offset, 0, 0);
+        if (listener != null) {
+            listener.onHeaderStateChange(state,offset);
+        }
+    }
+
+    private void footerStateChange(int state,int offset) {
+
+        if (state == REFRESHING) {
+            isRefreshing = true;
+        }
+
+        if (footerView == null) {
+            return;
+        }
+
+        footerView.setPadding(0, offset, 0, 0);
+
+        if (listener != null) {
+            listener.onFooterStateChange(state,offset + footerViewHeight);
+        }
+    }
+
+    /**
+     * 完成刷新操作,重置状态,在你获取完数据并更新完adater之后,去在UI线程中调用该方法
+     */
+    public void completeRefresh(){
+
+        isRefreshing = false;
+        if(isLoadingMore){
+
+            //重置footerView状态
+//            footerView.setPadding(0, -footerViewHeight, 0, 0);
+            isLoadingMore = false;
+            footerStateChange(PULL_REFRESH,-footerViewHeight);
+        } else {
+
+            //重置headerView状态
+//            headerView.setPadding(0, -headerViewHeight, 0, 0);
+            currentState = PULL_REFRESH;
+            headerStateChange(currentState,-headerViewHeight);
+        }
+    }
+
+    /**
+     * 获取当前系统时间,并格式化
+     * @return
+     */
+    private String getCurrentTime(){
+        SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
+        return format.format(new Date());
+    }
+
+    private OnRefreshListener listener;
+    public void setOnRefreshListener(OnRefreshListener listener){
+        this.listener = listener;
+    }
+    public interface OnRefreshListener{
+        void onHeaderStateChange(int state, int offset);
+        void onFooterStateChange(int state, int offset);
+        void shouldPullDownToRefresh(boolean should);
+    }
+
+    /**
+     * SCROLL_STATE_IDLE:闲置状态,就是手指松开
+     * SCROLL_STATE_TOUCH_SCROLL:手指触摸滑动,就是按着来滑动
+     * SCROLL_STATE_FLING:快速滑动后松开
+     */
+    @Override
+    public void onScrollStateChanged(AbsListView view, int scrollState) {
+
+        if (footerView == null) {
+            return;
+        }
+
+        if(scrollState==OnScrollListener.SCROLL_STATE_IDLE
+                && getLastVisiblePosition()==(getCount()-1) &&!isLoadingMore){
+            if (!isRefreshing) {
+
+                isRefreshing = true;
+                isLoadingMore = true;
+
+//                footerView.setPadding(0, 0, 0, 0);//显示出footerView
+                footerStateChange(REFRESHING,0);
+
+                setSelection(getCount());//让listview最后一条显示出来,在页面完全显示出底布局
+
+            }
+        }
+    }
+
+
+
+    public int getOffsetY() {
+        View c = getChildAt(0);
+        if (c == null) {
+            return 0;
+        }
+        int firstVisiblePosition = getFirstVisiblePosition();
+        int top = c.getTop();
+        return -top + firstVisiblePosition * c.getHeight() ;
+    }
+
+    @Override
+    public void onScroll(AbsListView view, int firstVisibleItem,
+                         int visibleItemCount, int totalItemCount) {
+
+
+        if (listener != null) {
+            if (getOffsetY() == 0) {
+                listener.shouldPullDownToRefresh(true);
+            } else {
+                listener.shouldPullDownToRefresh(false);
+            }
+        }
+
+        Log.d("Didida", "onScroll: " + firstVisibleItem + "  " + getOffsetY());
+
+    }
+
+}

+ 1360 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/result/SearchResultActivity.java

@@ -0,0 +1,1360 @@
+package com.usai.apex.result;
+
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.DataSetObserver;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v4.content.FileProvider;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.text.Html;
+import android.text.Layout;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.GestureDetector;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseAdapter;
+import android.widget.HorizontalScrollView;
+import android.widget.RelativeLayout;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+import com.usai.apex.ApexTrackingApplication;
+import com.usai.apex.R;
+import com.usai.util.Network;
+import com.usai.util.RAUtil;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+
+//import com.usai.redant.Detail.KVDetailActivity;
+//import com.usai.redant.Detail.OrderDetailActivity;
+//import com.usai.apex.redantmobile.BuildConfig;
+
+//import static com.usai.redant.CommonEditor.CommonEditorActivity.URL_REMOTE;
+
+
+public class SearchResultActivity extends AppCompatActivity {
+
+    public static SearchResultActivity instance = null;
+    protected Bundle mParams;
+    protected JSONObject resultData = new JSONObject();
+
+    protected Context mContext;
+    protected PullRefreshListView resultListView;
+    protected ResultAdapter adapter;
+    protected SwipeRefreshLayout resultSwipe;
+    protected View list_footer;
+    protected View refresh_footer;
+
+    private View clickedView;
+    private View.OnTouchListener resultRowClickListener;
+    private GestureDetector detector;
+
+    protected int footer_height;
+    protected int header_height;
+
+    ProgressDialog progressDialog;
+    public boolean isLoading = false;//表示是否正处于加载状态
+
+
+    public void cellDoubleTapAction(int position) {
+
+//        try {
+//
+//            JSONArray row_action = resultData.optJSONArray("row_action");
+//            if (row_action != null) {
+//
+//                if (row_action.length() == 1) {
+//
+//                    JSONObject action = row_action.getJSONObject(0);
+//                    String module = action.getString("module");
+//
+//                    if (module.equals("quick_look")) {
+//                        JSONObject param = action.getJSONObject("params");
+//                        String url = action.getString("url");
+//                        showQuickLook(param,url);
+//                    } else if (module.equals("kv_detail")) {
+//                        JSONObject params = new JSONObject();
+//                        params.put("query_id",mParams.get("query_id"));
+//
+//                        JSONObject criteria = new JSONObject();
+//                        JSONObject action_params = action.getJSONObject("params");
+//                        Iterator<String> iterator = action_params.keys();
+//                        while (iterator.hasNext()) {
+//                            String key = iterator.next();
+//                            JSONArray item = contentData().getJSONArray("item_" + position);
+//                            int idx = action_params.getInt(key);
+//                            criteria.put(key,item.get(idx));
+//                        }
+//
+//                        params.put("criteria",criteria.toString());
+//                        showKVDetail(params);
+//
+//                    } else if (module.equals("order_detail")) {
+//
+//                        showOrderDetail();
+//
+//                    }
+//
+//
+//                } else if (row_action.length() > 1) {
+//
+//                    ArrayList<String> titleList = new ArrayList<>();
+//
+//                    for (int i = 0; i < row_action.length(); i++) {
+//                        JSONObject json = row_action.getJSONObject(i);
+//                        String title = json.getString("title");
+//                        titleList.add(title);
+//                    }
+//
+//                    new AlertDialog.Builder(mContext)
+//                            .setSingleChoiceItems((String[])titleList.toArray(new String[titleList.size()]), -1, new DialogInterface.OnClickListener() {
+//                                @Override
+//                                public void onClick(DialogInterface dialog, int which) {
+//
+//                                    try {
+//                                        JSONArray content_action = resultData.getJSONArray("row_action");
+//                                        JSONObject json = content_action.getJSONObject(which);
+//                                        String module = json.getString("module");
+//                                        JSONObject add_params = json.getJSONObject("params");
+//
+//                                        if (module.equals("quick_look")) {
+//                                            JSONObject param = json.getJSONObject("params");
+//                                            String url = json.getString("url");
+//                                            showQuickLook(param,url);
+//                                        } else if (module.equals("kv_detail")) {
+//
+//                                            JSONObject params = json.getJSONObject("params");
+//                                            showKVDetail(params);
+//
+//                                        } else if (module.equals("order_detail")) {
+//
+//                                            showOrderDetail();
+//
+//                                        }
+//
+//
+//                                    } catch (JSONException exception) {
+//                                        Log.d("Result", "onClick: ",exception);
+//                                    }
+//                                    dialog.dismiss();
+//
+//                                }
+//                            })
+//                            .show();
+//
+//                }
+//
+//            }
+//
+//        } catch (JSONException exception) {
+//            Log.e("Result", "onDoubleTapEvent: ",exception);
+//        }
+    }
+
+    void setMargin(View view,int l,int t,int r,int b) {
+        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(view.getLayoutParams());
+        lp.setMargins(l, t, r, b);
+        view.setLayoutParams(lp);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (progressDialog != null) {
+            progressDialog.dismiss();
+            progressDialog = null;
+        }
+    }
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_search_result);
+
+        instance = this;
+        mContext = this;
+        footer_height = dp2px(this,30);
+        header_height = dp2px(this,60);
+
+        resultListView = (PullRefreshListView) findViewById(R.id.result_table_list);
+        resultSwipe = findViewById(R.id.result_swipe);
+
+        progressDialog = new ProgressDialog(mContext);
+        progressDialog.setCancelable(false);
+
+        initClickListener();
+
+
+        adapter = new ResultAdapter(mContext);
+        resultListView.setAdapter(adapter);
+        resultListView.setDividerHeight(0);
+
+        // refresh header & footer
+        list_footer = View.inflate(this, R.layout.refresh_footer, null);
+        resultListView.setRefreshFooter(list_footer);
+
+        refresh_footer = findViewById(R.id.result_refresh_footer);
+        refresh_footer.bringToFront();
+
+        resultListView.setOnRefreshListener(new PullRefreshListView.OnRefreshListener() {
+            @Override
+            public void onHeaderStateChange(int state, int offset) {
+                Log.d("Pull Down", "onHeaderStateChange: " + offset);
+//                setMargin(refresh_header,0,offset,0,0);
+//                if (state == PullRefreshListView.REFRESHING) {
+//                   loadData();
+//                }
+            }
+
+            @Override
+            public void onFooterStateChange(int state, int offset) {
+
+                setMargin(refresh_footer,0,resultListView.getHeight() - offset,0,0);
+                if (state == PullRefreshListView.REFRESHING) {
+                    if (!isLoading) {
+                        loadMore();
+                    }
+                }
+            }
+
+            @Override
+            public void shouldPullDownToRefresh(boolean should) {
+                resultSwipe.setEnabled(should);
+            }
+        });
+
+        resultSwipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+            @Override
+            public void onRefresh() {
+                if (isLoading) {
+                    resultSwipe.setRefreshing(false);
+                } else {
+                    loadData();
+                }
+            }
+        });
+
+
+
+        if (savedInstanceState != null) {
+            mParams = savedInstanceState.getBundle("query_params");
+        } else {
+            mParams = getIntent().getBundleExtra("query_params");
+        }
+
+        if (mParams == null) {
+            mParams = new Bundle();
+        }
+
+        String title = mParams.getString("title");
+        setTitle(title);
+
+        loadData();
+
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+
+        outState.putBundle("query_params",mParams);
+    }
+
+    // 动态修改Menu
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+        menu.clear();
+
+
+//        if (resultData != null) {
+//            try {
+//                JSONArray menu_json = resultData.getJSONArray("menu");
+//
+//                if (menu_json != null && menu_json.length() > 0) {
+//
+//                    for (int i = 0; i < menu_json.length(); i++) {
+//                        JSONObject json = menu_json.getJSONObject(i);
+//                        String title = json.getString("title");
+//                        menu.add(0, i, 0, title);
+//                    }
+//                }
+//            } catch (JSONException e) {
+//                e.printStackTrace();
+//            }
+//        }
+
+        return true;
+    }
+
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+
+
+//        int which = item.getItemId();
+//        try {
+//            JSONArray menu = resultData.getJSONArray("menu");
+//            JSONObject json = menu.getJSONObject(which);
+//
+//            String actionType = json.getString("action");
+//            String url = json.optString("url");
+//
+//            if (actionType.equals("download")) {
+//                export(url);
+//            } else if (actionType.equals("save")) {
+//                if(BuildConfig.DEBUG && true){
+//                    //do something for assert aim
+//                    Log.e("Result", "onOptionsItemSelected DialogClick: not implement");
+//                }
+//            }
+//
+//        } catch (JSONException exception) {
+//            Log.d("Result", "onClick: ",exception);
+//        }
+
+        return true;
+    }
+
+
+//    public int last_index;
+//    public int total_index;
+//
+//    @Override
+//    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+//        last_index = firstVisibleItem+visibleItemCount;
+//        total_index = totalItemCount;
+//    }
+//
+//    @Override
+//    public void onScrollStateChanged(AbsListView view, int scrollState) {
+//        if(last_index == total_index && (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE))
+//        {
+//            // 表示此时需要显示刷新视图界面进行新数据的加载(要等滑动停止)
+//            if(!isLoading)
+//            {
+//                // 设置刷新界面可见
+//                footer.setVisibility(View.VISIBLE);
+//                loadMore();
+//            }
+//        }
+//    }
+
+    // 设置header 和 footer宽度,否则listView会显示默认宽度
+    protected void setupUI() {
+        try {
+            if (resultData == null) {
+                return;
+            } else {
+                int result = resultData.getInt("result");
+                if (result != 2) {
+                    return;
+                }
+            }
+            JSONObject layout = resultData.getJSONObject("layout");
+
+            JSONObject header = layout.getJSONObject("header");
+            int width = header.getInt("width");
+            width = convertDp2Px(width);
+
+            AbsListView.LayoutParams footerLayoutParams = (AbsListView.LayoutParams)list_footer.getLayoutParams();
+            if (footerLayoutParams == null) {
+                footerLayoutParams = new AbsListView.LayoutParams(width,footer_height);
+            }
+            footerLayoutParams.height = footer_height;
+            footerLayoutParams.width = width;
+            list_footer.setLayoutParams(footerLayoutParams);
+
+
+        } catch (JSONException e) {
+            Log.e("Result", "setupUI: ", e);
+        }
+
+    }
+
+    public void loadComplete() {
+
+        setupUI();
+        resultListView.completeRefresh();
+        if (resultSwipe.isRefreshing()) {
+            resultSwipe.setRefreshing(false);
+        }
+        resultListView.forceLayout();
+
+        isLoading = false;//设置正在刷新标志位false
+        invalidateOptionsMenu();
+
+        String title = resultData.optString("table_title");
+        setTitleColor(Color.BLACK);
+        setTitle(title);
+
+        progressDialog.dismiss();
+    }
+
+
+    protected void showProgressDialog(String title, String msg) {
+        progressDialog.setTitle(title);
+        progressDialog.setMessage(msg);
+        progressDialog.show();
+    }
+
+    JSONObject readRawFile(int id)
+    {
+        String content;
+        Resources resources=this.getResources();
+        InputStream is=null;
+        try{
+            is=resources.openRawResource(id);
+            byte buffer[]=new byte[is.available()];
+            is.read(buffer);
+            content=new String(buffer);
+            JSONObject json = new JSONObject(content);
+            return json;
+        }
+        catch(IOException e)
+        {
+            e.printStackTrace();
+        }
+        catch (JSONException e) {
+            e.printStackTrace();
+        }
+        finally
+        {
+            if(is!=null)
+            {
+                try{
+                    is.close();
+                }catch(IOException e)
+                {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return null;
+    }
+
+    protected void loadData() {
+
+//        resultData = readRawFile(R.raw.predef_query);
+//        if (1 == 1) {
+//            return;
+//        }
+
+        if (isLoading) {
+            return;
+        }
+
+        isLoading = true;
+
+        showProgressDialog(null,"Loading");
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                try {
+
+                    mParams.putInt("offset",0);
+                    mParams.putInt("limit",25);
+                    JSONObject new_resultData = Network.query(mParams);
+
+                    if (new_resultData != null) {
+                        Iterator<String> iterator = new_resultData.keys();
+                        while (iterator.hasNext()) {
+                            String key = iterator.next();
+                            Object value = new_resultData.get(key);
+                            resultData.put(key,value);
+                        }
+                    }
+
+                    runOnUiThread(new Runnable() {
+                        @Override
+                        public void run() {
+
+                            loadComplete();
+                            int result = resultData.optInt("result",0);
+                            if (result == 2) {
+
+                            } else {
+
+                                String msg = resultData.optString("msg");
+                                if (msg == null || msg.isEmpty()) {
+                                    msg = "Sorry,some error occurred";
+                                }
+
+                                new AlertDialog.Builder(mContext)
+                                        .setTitle("Warning")
+                                        .setMessage(msg)
+                                        .show();
+                            }
+
+                            adapter.notifyDataSetChanged();
+                        }
+                    });
+
+                } catch (Exception e) {
+                    Log.e("Result", "onCreate: ",e);
+                }
+
+
+
+
+            }
+        }).start();
+
+    }
+
+    protected void loadMore() {
+
+        if (isLoading) {
+            return;
+        }
+
+        isLoading = true;
+        showProgressDialog(null,"Loading");
+
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                try {
+
+//                    Thread.sleep(2000);
+//
+//                    InputStream in = getResources().openRawResource( R.raw.result);
+//                    int length = in.available();
+//                    byte[] buffer = new byte[length];
+//                    in.read(buffer);
+//                    String res = new String(buffer,"utf8");
+//                    in.close();
+//
+//                    JSONObject newJson = new JSONObject(res);
+
+                    mParams.putInt("offset",adapter.getCount());
+                    mParams.putInt("limit",25);
+                    JSONObject newJson = Network.query(mParams);
+
+                    if (newJson != null) {
+
+                        int result = newJson.getInt("result");
+                        if (result == 2) {
+                            JSONObject newData = newJson.getJSONObject("data");
+                            int add_count = newData.getInt("count");
+
+                            JSONObject data = resultData.getJSONObject("data");
+                            int count = data.getInt("count");
+
+                            for (int i = 0; i < add_count; i++) {
+                                JSONArray new_data_item = newData.getJSONArray("item_" + i);
+                                if (new_data_item != null) {
+                                    data.put("item_" + count++,new_data_item);
+                                }
+                            }
+                            data.put("count",count);
+                            resultData.put("data",data);
+
+                            runOnUiThread(new Runnable() {
+                                @Override
+                                public void run() {
+
+                                    loadComplete();
+                                    adapter.notifyDataSetChanged();
+                                }
+                            });
+                        } else {
+                            String msg = newJson.optString("msg");
+                            if (msg == null || msg.isEmpty()) {
+                                msg = "Some error occurred";
+                            }
+                            showAlert(msg);
+                        }
+
+
+                    }
+
+
+                } catch (Exception e) {
+                    Log.e("Result", "onCreate: ",e);
+                    showAlert("Some error occurred");
+                }
+
+
+
+
+            }
+        }).start();
+    }
+
+    protected JSONObject contentData() {
+        try {
+            return resultData.getJSONObject("data");
+        } catch (JSONException e) {
+            Log.e("Result", "contentData: ", e);
+        }
+        return null;
+    }
+
+    protected JSONArray contentMenu() {
+        if (resultData != null) {
+            try {
+                JSONArray menu_json = resultData.getJSONArray("menu");
+                return menu_json;
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    protected JSONArray contentAction() {
+        if (resultData != null) {
+            try {
+                JSONArray action_json = resultData.getJSONArray("row_action");
+                return action_json;
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    protected JSONObject contentLayout() {
+        if (resultData != null) {
+            try {
+                JSONObject layout = resultData.getJSONObject("layout");
+                return layout;
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+
+    }
+
+
+    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
+
+        @Override
+        public boolean onDoubleTapEvent(MotionEvent e) {
+
+
+            if (e.getAction() == MotionEvent.ACTION_UP) {
+
+                TableRow cellRow = (TableRow)clickedView.getParent();
+                RelativeLayout cell = (RelativeLayout)cellRow.getParent();
+
+                int position = resultListView.getPositionForView(cell);
+//                Log.d("Result", "onDoubleTapEvent: " + position);
+
+                if (position == 0) {
+                    return false;
+                }
+
+                cellDoubleTapAction(position);
+
+            }
+
+            return false;
+        }
+
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent e) {
+            if (clickedView instanceof TextView) {
+                TextView tv = (TextView)clickedView;
+                if (ellipsisTextView(tv)) {
+                    showAlert(tv.getText().toString());
+                }
+            }
+            return false;
+        }
+    }
+
+    private int normalColor;
+    private int touchColor = Color.GRAY;
+    private void initClickListener() {
+
+        // 需要作为成员变量
+        detector = new GestureDetector(mContext, new GestureListener());
+
+        resultRowClickListener = new View.OnTouchListener() {
+
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+
+                TableRow cellRow = (TableRow)v.getParent();
+                RelativeLayout cell = (RelativeLayout)cellRow.getParent();
+
+                int position = resultListView.getPositionForView(cell);
+
+                if (position == 0) {
+                    return false;
+                }
+
+
+//                View cellRow = (View) v.getParent();
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {
+
+                    if (clickedView != null) {
+                        ((View)clickedView.getParent()).setBackgroundColor(normalColor);
+                    }
+
+                    normalColor = ((ColorDrawable)cellRow.getBackground()).getColor();
+                    cellRow.setBackgroundColor(touchColor);
+
+                } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) {
+//                    cell.setBackgroundColor(normalColor);
+                }
+
+                clickedView = v;
+
+                detector.onTouchEvent(event);
+
+                return true;
+            }
+        };
+
+    }
+
+
+
+    protected class ResultAdapter extends BaseAdapter {
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return true;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return true;
+        }
+
+        private class ResultHoder {
+            public ResultHoder(View view) {
+                row = (TableRow)view.findViewById(R.id.result_row);
+                view.setTag(this);
+            }
+            TableRow row;
+        }
+
+        public ResultAdapter(Context ctx) {
+
+        }
+
+        @Override
+        public void registerDataSetObserver(DataSetObserver observer) {
+            super.registerDataSetObserver(observer);
+        }
+
+        @Override
+        public void unregisterDataSetObserver(DataSetObserver observer) {
+            super.unregisterDataSetObserver(observer);
+        }
+
+        @Override
+        public int getCount() {
+            if (resultData == null) {
+                return 0;
+            } else {
+                int result = resultData.optInt("result");
+                if (result != 2) {
+                    return 0;
+                }
+            }
+            try {
+                JSONObject data = resultData.getJSONObject("data");
+                int result_count = data.getInt("count");
+                return result_count + 1; // header + data
+
+            } catch (JSONException e) {
+                Log.e("Result", "getCount: ", e);
+                return 0;
+            }
+        }
+
+        @Override
+        public Object getItem(int position) {
+            try {
+                if (position == 0) {
+                    // header
+
+                    JSONObject layout = resultData.getJSONObject("layout");
+                    JSONObject header = layout.getJSONObject("header");
+                    JSONArray col = header.getJSONArray("col");
+
+                    return col;
+
+                } else {
+                    // result row
+
+                    JSONObject data = resultData.getJSONObject("data");
+                    JSONArray item = data.getJSONArray("item_" + (position - 1));
+
+                    return item;
+                }
+
+
+            } catch (JSONException e) {
+                Log.e("Result", "getItem: ", e);
+            }
+            return null;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return false;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+
+            View cell;
+            ResultHoder holder;
+            if (convertView == null) {
+
+                cell = LayoutInflater.from(mContext).inflate(R.layout.result_cell,null);
+                holder = new ResultHoder(cell);
+
+
+            } else {
+
+                cell = convertView;
+                holder = (ResultHoder)cell.getTag();
+
+            }
+//            holder.row.removeAllViews();
+
+//            cell.setOnTouchListener(resultRowClickListener);
+
+            holder.row.setBackgroundColor(Color.WHITE);
+            // setup
+           try {
+
+               JSONObject layout = resultData.getJSONObject("layout");
+
+               JSONObject header = layout.getJSONObject("header");
+               int width = header.getInt("width");
+               int height = header.getInt("height");
+               int margin_t = header.getInt("margin_t");
+               int margin_l = header.getInt("margin_l");
+               int margin_b = header.getInt("margin_b");
+               int margin_r = header.getInt("margin_r");
+
+               width = convertDp2Px(width);
+               height = convertDp2Px(height);
+               margin_t = convertDp2Px(margin_t);
+               margin_l = convertDp2Px(margin_l);
+               margin_b = convertDp2Px(margin_b);
+               margin_r = convertDp2Px(margin_r);
+
+
+               HorizontalScrollView.LayoutParams listViewLayoutParams = (HorizontalScrollView.LayoutParams)resultListView.getLayoutParams();
+               listViewLayoutParams.width = width;
+               resultListView.setLayoutParams(listViewLayoutParams);
+
+
+
+               JSONArray obj = (JSONArray)getItem(position);
+               JSONArray arr_col = header.getJSONArray("col");
+
+               if (position == 0) {
+
+                   // header
+                   String bg_color = header.getString("bg_color");
+                   String f_color = header.getString("f_color");
+
+                   if (!bg_color.contains("0x")) {
+                       bg_color = "0x" + bg_color;
+                   }
+                   if (!f_color.contains("0x")) {
+                       f_color = "0x" + f_color;
+                   }
+                   bg_color = bg_color.replace("0x","#");
+                   f_color = f_color.replace("0x","#");
+
+                   RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)holder.row.getLayoutParams();
+                   layoutParams.height = height;
+                   holder.row.setLayoutParams(layoutParams);
+
+                   // 调整显示列后,需要删除多余的列
+                   if (holder.row.getChildCount() > arr_col.length()) {
+                       for (int i = arr_col.length(); i < holder.row.getChildCount(); i++) {
+                           TextView tv = (TextView)holder.row.findViewById(i);
+                           holder.row.removeView(tv);
+                       }
+                   }
+
+                   // col
+                   for (int i = 0; i < arr_col.length(); i++) {
+
+                       JSONObject value = obj.getJSONObject(i);
+                       int col_w = value.getInt("width");
+                       col_w = convertDp2Px(col_w);
+
+                       String h_align = value.getString("h_align");
+                       String v_center = value.getString("v_center");
+                       String col_bg_color = value.getString("bg_color");
+                       String col_f_color = value.getString("f_color");
+                       String name = value.getString("name");
+
+
+                       bg_color = bg_color.replace("0x","#");
+                       f_color = f_color.replace("0x","#");
+
+                       TextView tv = (TextView)holder.row.findViewById(i);
+                       if (tv == null) {
+                           tv = new TextView(mContext);
+
+                           tv.setGravity(convertGravity("h_align",h_align) | convertGravity("v_center",v_center));
+                           tv.setSingleLine();
+                           tv.setEllipsize(TextUtils.TruncateAt.END);
+                           tv.setId(i);
+                           tv.setBackgroundDrawable(getResources().getDrawable(R.drawable.result_black_border));
+                           tv.setOnTouchListener(resultRowClickListener);
+                       } else {
+                           holder.row.removeView(tv);
+                       }
+
+                       // layout
+                       tv.setWidth(col_w);
+                       tv.setHeight(height);
+                       tv.setPadding(margin_l,margin_t,margin_r,margin_b);
+
+                       TableRow.LayoutParams tvLayoutParams = new  TableRow.LayoutParams(col_w, height);
+
+                       holder.row.addView(tv,i,tvLayoutParams);
+
+                       // content
+                       tv.setTextColor(Color.parseColor(f_color));
+                       tv.setTextSize(TypedValue.COMPLEX_UNIT_SP,14);
+                       tv.getPaint().setFakeBoldText(true);
+
+                       if (name.contains("</")) {
+                           tv.setText(Html.fromHtml(name));
+                       } else {
+                           tv.setText(name);
+                       }
+
+                   }
+                   holder.row.setBackgroundColor(Color.parseColor(bg_color));
+
+               } else {
+
+                   // row
+                   JSONObject row = layout.getJSONObject("row");
+                   String f_color = row.getString("f_color");
+                   String color_0 = row.getString("color_0");
+                   String color_1 = row.getString("color_1");
+
+                   if (!f_color.contains("0x")) {
+                       f_color = "0x" + f_color;
+                   }
+                   if (!color_0.contains("0x")) {
+                       color_0 = "0x" + color_0;
+                   }
+                   if (!color_1.contains("0x")) {
+                       color_1 = "0x" + color_1;
+                   }
+
+
+                   f_color = f_color.replace("0x","#");
+                   color_0 = color_0.replace("0x","#");
+                   color_1 = color_1.replace("0x","#");
+
+                   int row_h = row.getInt("height");
+                   row_h = convertDp2Px(row_h);
+
+                   RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)holder.row.getLayoutParams();
+                   layoutParams.height = row_h;
+                   holder.row.setLayoutParams(layoutParams);
+
+                   // 调整显示列后,需要删除多余的列
+                   if (holder.row.getChildCount() > arr_col.length()) {
+                       for (int i = arr_col.length(); i < holder.row.getChildCount(); i++) {
+                           TextView tv = (TextView)holder.row.findViewById(i);
+                           holder.row.removeView(tv);
+                       }
+                   }
+
+                   // col
+                   for (int i = 0; i < arr_col.length(); i++) {
+
+                       JSONArray col_layout = row.getJSONArray("val");
+                       JSONObject layout_val = col_layout.getJSONObject(i);
+
+                       String type = layout_val.getString("type");
+                       String h_align = layout_val.getString("h_align");
+                       String v_center = layout_val.getString("v_center");
+                       String col_bg_color = layout_val.getString("bg_color");
+                       String col_f_color = layout_val.getString("f_color");
+
+                       col_bg_color = col_bg_color.replace("0x","#");
+                       col_f_color = col_f_color.replace("0x","#");
+
+                       String value = obj.getString(i);
+
+
+                       JSONObject size = ((JSONArray)getItem(0)).getJSONObject(i);
+                       int col_w = size.getInt("width");
+                       int col_h = row.getInt("height");
+
+                       col_w = convertDp2Px(col_w);
+                       col_h = convertDp2Px(col_h);
+
+                       TextView tv = (TextView) holder.row.findViewById(i);
+                       if (tv == null) {
+                           tv = new TextView(mContext);
+
+                           tv.setGravity(convertGravity("h_align",h_align) | convertGravity("v_center",v_center));
+                           tv.setSingleLine();
+                           tv.setEllipsize(TextUtils.TruncateAt.END);
+                           tv.setId(i);
+                           tv.setOnTouchListener(resultRowClickListener);
+                           tv.setBackgroundDrawable(getResources().getDrawable(R.drawable.result_black_border));
+                       } else {
+                           holder.row.removeView(tv);
+                       }
+
+                       // layout
+                       tv.setWidth(col_w);
+                       tv.setHeight(col_h);
+                       tv.setPadding(margin_l,margin_t,margin_r,margin_b);
+
+                       TableRow.LayoutParams tvLayoutParams = new  TableRow.LayoutParams(col_w, col_h);
+                       holder.row.addView(tv,i,tvLayoutParams);
+
+                       // content
+
+                       tv.setTextColor(Color.parseColor(f_color));
+                       tv.setTextSize(TypedValue.COMPLEX_UNIT_SP,12);
+                       tv.getPaint().setFakeBoldText(false);
+                       tv.setText(Html.fromHtml(value));
+//                       if (value.contains("</")) {
+//                           tv.setText(Html.fromHtml(value));
+//                       } else {
+//                           tv.setText(value);
+//                       }
+
+
+                   }
+
+                   if ((position - 1) % 2 == 0) {
+                       holder.row.setBackgroundColor(Color.parseColor(color_0));
+                   } else {
+                       holder.row.setBackgroundColor(Color.parseColor(color_1));
+
+                   }
+               }
+
+           } catch (JSONException e) {
+               Log.e("Result", "getView: ", e);
+           }
+
+            return cell;
+        }
+
+        private int convertGravity(String key, String align) {
+
+            if (key.equals("h_align")) {
+                if (align.equals("center")) {
+                    return Gravity.CENTER_HORIZONTAL;
+                } else if (align.equals("left")) {
+                    return Gravity.LEFT;
+                } else if (align.equals("right")) {
+                    return Gravity.RIGHT;
+                }
+
+            }
+
+            if (key.equals("v_center")) {
+
+                if (align.equals("center")) {
+                    return Gravity.CENTER_VERTICAL;
+                } else if (align.equals("top")) {
+                    return Gravity.TOP;
+                } else if (align.equals("bottom")) {
+                    return Gravity.BOTTOM;
+                }
+            }
+            return Gravity.CENTER;
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            return 0;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 1;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return false;
+        }
+    }
+
+
+    public boolean ellipsisTextView(TextView tv) {
+        Layout l = tv.getLayout();
+        if ( l != null){
+            int lines = l.getLineCount();
+            if ( lines > 0) {
+                if (l.getEllipsisCount(lines - 1) > 0) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public int convertDp2Px(int dp) {
+        return dp2px(mContext,dp);
+    }
+
+    public int px2dp(Context context, float pxValue) {
+        float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (pxValue / scale + 0.5f);
+    }
+
+    public int dp2px(Context context, float dpValue) {
+        float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+
+    public int px2sp(Context context, float pxValue) {
+        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
+        return (int) (pxValue / fontScale + 0.5f);
+    }
+
+    public int sp2px(Context context, float spValue) {
+        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
+        return (int) (spValue * fontScale + 0.5f);
+    }
+
+
+    protected String documentPath;
+    protected String download_query;
+    protected void export(final String download_url) {
+
+        if (download_query != null) {
+            documentPath = download_query;
+            openFile(new File(download_query));
+            return;
+        }
+
+        showProgressDialog(null,"Please wait");
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                String cacheDir = ApexTrackingApplication.getInstance().getDocumentDir();
+                // download & get path
+                final File downloadFile = Network.download_query(download_url,cacheDir);
+                final String path = downloadFile != null && downloadFile.exists() ? downloadFile.getPath() : null;
+
+
+
+                documentPath = path;
+                download_query = path;
+
+
+                if (path != null) {
+                    runOnUiThread(new Runnable() {
+                        @Override
+                        public void run() {
+                            progressDialog.dismiss();
+                            openFile(downloadFile);
+                        }
+                    });
+                }
+
+            }
+        }).start();
+
+    }
+
+    public void showAlert(final String msg) {
+        if (msg == null || msg.isEmpty()) {
+            return;
+        }
+
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                new AlertDialog.Builder(mContext)
+                        .setMessage(msg)
+                        .show();
+            }
+        });
+    }
+
+    public void showOrderDetail() {
+//        Intent intent = OrderDetailActivity.build(mContext,OrderDetailActivity.class,null,URL_REMOTE,null,new Bundle());
+//
+//        startActivity(intent);
+    }
+
+    public void showKVDetail(final JSONObject param) {
+//        showProgressDialog("Please wait","Loading...");
+//
+//        new Thread(new Runnable() {
+//            @Override
+//            public void run() {
+//
+//                final JSONObject json = Network.kv_detail(RAUtil.Json2Bundle(param));
+////                final JSONObject json = readRawFile(R.raw.kv);
+//
+//                runOnUiThread(new Runnable() {
+//                    @Override
+//                    public void run() {
+//                        progressDialog.dismiss();
+//
+//                        int result = 0;
+//                        if (json != null) {
+//                            result = json.optInt("result",0);
+//                        }
+//                        if (result == 2) {
+//
+//                            Intent intent = KVDetailActivity.build(mContext,json.toString());
+//
+//                            startActivity(intent);
+//
+//                        } else {
+//                            String msg = json.optString("msg");
+//                            if (msg == null) {
+//                                msg = "Sorry,some error occurred";
+//                            }
+//                            showAlert(msg);
+//                        }
+//
+//                    }
+//                });
+//
+//            }
+//        }).start();
+
+    }
+
+    public void showQuickLook(final JSONObject param, final String url) {
+
+        showProgressDialog("Please wait","Downloading...");
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+
+                String cacheDir = ApexTrackingApplication.getInstance().getDocumentDir();
+                // 下载文件
+                final File downloadFile = Network.downloadFile(RAUtil.Json2Bundle(param),url,cacheDir);
+
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        progressDialog.dismiss();
+                        if (downloadFile != null && downloadFile.exists()) {
+//                            try {
+//                                //此处需要新增保存文档的本地表
+//                                param;
+////                                String email=param.getString("email");
+////                                String email_subject=param.getString("email_subject");
+////                                String email_content=param.getString("email_content");
+//                            } catch (JSONException e) {
+//                                e.printStackTrace();
+//                            }
+                            openFile(downloadFile);
+                        } else {
+                            showAlert("Sorry,there is a wrong.");
+                        }
+                    }
+                });
+
+            }
+        }).start();
+
+
+    }
+
+    protected void openFile(File file) {
+
+        if (file == null || !file.exists()) {
+            return;
+        }
+
+        Uri uri = null;
+        String type = RAUtil.getMimeType(file.getPath());
+
+        // type "application/pdf"
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+
+            // "com.usai.apex.fileprovider"即是在Manifest文件中配置的authorities
+            uri = FileProvider.getUriForFile(mContext, RAUtil.getProviderAuthorities(), file);
+            // 给目标应用一个临时授权
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        } else {
+            uri = Uri.fromFile(file);
+        }
+
+        intent.setDataAndType(uri, type);
+
+        if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
+            // someone knows how to handle this mime type with this scheme, don't download.
+            try {
+                startActivity(intent);
+                return;
+            } catch (Exception ex) {
+                Log.d("Open File", "activity not found for " + type + " over " + uri, ex);
+            }
+
+        } else {
+            Log.d("Open File", "openFileAtPath: " + "No App " + uri);
+            try {
+                shareFile(uri,type);
+            } catch (Exception e) {
+                Log.e("Show Dialog Error", "openFileAtPath: ", e);
+            }
+        }
+
+    }
+
+    protected void shareFile(Uri uri, String type) {
+
+        Intent shareIntent = new Intent();
+        shareIntent.setAction(Intent.ACTION_SEND);
+        shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
+        shareIntent.setType(type);
+        startActivity(Intent.createChooser(shareIntent, "Share"));
+    }
+
+
+}

+ 0 - 2
ApexDrivers/apexmobile/src/main/java/com/usai/apex/saved/AMListFragment.java

@@ -3,7 +3,6 @@ package com.usai.apex.saved;
 import android.content.Context;
 import android.os.Bundle;
 import android.support.v4.app.ListFragment;
-import android.support.v4.widget.SwipeRefreshLayout;
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -14,7 +13,6 @@ import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import com.usai.apex.Result.PullRefreshListView;
 import com.usai.apex.swipemenulistview.SwipeMenuListView;
 
 /**

+ 735 - 0
ApexDrivers/apexmobile/src/main/java/com/usai/apex/shipmap/ShipMap.java

@@ -0,0 +1,735 @@
+package com.usai.apex.shipmap;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.CallSuper;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.baidu.mapapi.SDKInitializer;
+import com.baidu.mapapi.map.BaiduMap;
+import com.baidu.mapapi.map.BitmapDescriptor;
+import com.baidu.mapapi.map.BitmapDescriptorFactory;
+import com.baidu.mapapi.map.InfoWindow;
+import com.baidu.mapapi.map.MapStatus;
+import com.baidu.mapapi.map.MapStatusUpdate;
+import com.baidu.mapapi.map.MapStatusUpdateFactory;
+import com.baidu.mapapi.map.MapView;
+import com.baidu.mapapi.map.Marker;
+import com.baidu.mapapi.map.MarkerOptions;
+import com.baidu.mapapi.model.LatLng;
+import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.MapFragment;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.model.CameraPosition;
+import com.usai.apex.ApexTrackingApplication;
+import com.usai.apex.R;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.ref.WeakReference;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class ShipMap extends RelativeLayout implements GoogleMap.OnMarkerClickListener, BaiduMap.OnMarkerClickListener, GoogleMap.OnInfoWindowClickListener, OnMapReadyCallback, InfoWindow.OnInfoWindowClickListener {
+
+    private MapFragment mGoogleMapView;
+    private GoogleMap mGoogleMap;
+    private com.google.android.gms.maps.MapView mMap;
+
+    private MapView mBaiduMap;
+    private Context mContext;
+    private Boolean mUseGoogleMap;
+
+    private ShipMapListener mListener;
+    private ShipMap self = this;
+
+    private ImageButton mResizeBtn;
+
+    public ShipMap(Context context) {
+        super(context);
+        init(context);
+    }
+
+    public ShipMap(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public ShipMap(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context);
+    }
+
+
+    @CallSuper
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        destroy();
+    }
+    /**
+     * 防止恢复时报错Duplicate id 0x7f0b00d6, tag null, or parent id 0xffffffff with another fragment
+     * 需要在父fragment销毁时调用
+     * */
+    public void destroy() {
+        //
+        if (mUseGoogleMap && mGoogleMapView != null && mContext != null) {
+            ((Activity)mContext).getFragmentManager().beginTransaction().remove(mGoogleMapView).commit();
+        }
+
+        stopTwinkle();
+    }
+
+    private void init(Context ctx) {
+        mContext = ctx;
+
+        PackageInfo packageInfo;
+        try {
+            packageInfo = mContext.getPackageManager().getPackageInfo("com.google.android.gms", 0);
+
+        } catch (PackageManager.NameNotFoundException e) {
+            packageInfo = null;
+            e.printStackTrace();
+        }
+        if (packageInfo == null) {
+            mUseGoogleMap = false;
+            System.out.println("没有安装");
+        } else {
+            mUseGoogleMap = true;
+            System.out.println("已经安装");
+        }
+//        mUseGoogleMap = false;
+
+//        GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext.getApplicationContext());
+
+        if (mUseGoogleMap) {
+
+//            googleMap = ((MapFragment)((Activity)mContext).getFragmentManager().findFragmentById(R.id.ship_google_map));
+
+            View relativeLayout = LayoutInflater.from(mContext).inflate(R.layout.ship_google_map,null);
+//            mGoogleMapView = relativeLayout.findViewById(R.id.ship_google_map);
+//            mGoogleMapView = ((MapFragment)((Activity)mContext).getFragmentManager().findFragmentById(R.id.ship_google_map));
+//            mGoogleMapView.getMapAsync(this);
+
+            mMap = relativeLayout.findViewById(R.id.ship_google_map);
+            mMap.onCreate(null);
+            mMap.onResume();
+            mMap.getMapAsync(this);
+
+            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
+            relativeLayout.setBackgroundColor(Color.parseColor("#EFEFF4"));
+            addView(relativeLayout,layoutParams);
+
+        } else {
+
+            SDKInitializer.initialize(ApexTrackingApplication.get_instance());
+            mBaiduMap = new MapView(mContext);
+            mBaiduMap.getMap().setOnMarkerClickListener(this);
+
+            // 设置当前缩放
+            MapStatusUpdate u = MapStatusUpdateFactory.zoomTo(mBaiduMap.getMap().getMinZoomLevel());
+            mBaiduMap.getMap().setMapStatus(u);
+            mBaiduMap.showZoomControls(false); // false不显示缩放按钮
+            mBaiduMap.getMap().getUiSettings().setRotateGesturesEnabled(false); // 禁止旋转
+            mBaiduMap.getMap().getUiSettings().setOverlookingGesturesEnabled(false); // 禁止俯视调整
+
+
+            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
+            mBaiduMap.setBackgroundColor(Color.parseColor("#EFEFF4"));
+            addView(mBaiduMap,layoutParams);
+        }
+
+        ImageButton resizeBtn = new ImageButton(mContext);
+        resizeBtn.setImageResource(R.drawable.resize_max);
+        resizeBtn.setBackgroundResource(R.drawable.clear_background);
+        resizeBtn.setTag(false);
+
+        LayoutParams layoutParams = new LayoutParams(dp2px(mContext,30.0f),dp2px(mContext,30.0f));
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+        layoutParams.setMargins(0,dp2px(mContext,10.0f),dp2px(mContext,10.0f),0);
+
+        addView(resizeBtn,layoutParams);
+        mResizeBtn = resizeBtn;
+
+        resizeBtn.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                ImageButton zoomBtn = (ImageButton)v;
+                boolean selected = (boolean) zoomBtn.getTag();
+                selected = !selected;
+
+                setZoomIn(selected);
+
+            }
+        });
+
+    }
+
+    public void setZoomIn(boolean zoomIn) {
+
+        mResizeBtn.setTag(zoomIn);
+
+        if (zoomIn) {
+            mResizeBtn.setImageResource(R.drawable.resize_min);
+        } else {
+            mResizeBtn.setImageResource(R.drawable.resize_max);
+        }
+
+        if (mListener != null) {
+            mListener.shipMapTryToZoomIn(self,zoomIn);
+        }
+
+    }
+
+
+    public static int dp2px(Context context, float dpValue) {
+        float scale = context.getResources().getDisplayMetrics().density;
+        return (int) (dpValue * scale + 0.5f);
+    }
+
+    private static int AnnotationDisplayPriorityRequired = 2;
+    private static int AnnotationDisplayPriorityHigh= 1;
+    private static int AnnotationDisplayPriorityLow = 0;
+
+    private JSONObject mAnnotation;
+
+    private Marker mCurrentBaiduMarker;
+    private com.google.android.gms.maps.model.Marker mCurrentGoogleMarker;
+    public void showShipAnnotation(JSONObject annotation) {
+        if (annotation == null) {
+            return;
+        }
+
+        mCurrentGoogleMarker = null;
+        mCurrentBaiduMarker = null;
+
+        if (mUseGoogleMap) {
+           if (mGoogleMap != null) {
+               mGoogleMap.clear();
+           } else {
+               mAnnotation = annotation;
+               return;
+           }
+        } else {
+            mBaiduMap.getMap().clear();
+        }
+        mAnnotation = null;
+
+        JSONObject pol = annotation.optJSONObject("pol");
+        if (showPol()) {
+
+            if (pol != null) {
+                try {
+                    pol.put("port","Port Of Load");
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+                handleLocation(pol,AnnotationDisplayPriorityHigh,R.drawable.new_location_pol);
+            }
+        }
+
+        JSONObject pod = annotation.optJSONObject("pod");
+        if (showPod()) {
+
+            if (pod != null) {
+                try {
+                    pod.put("port","Port Of Discharge");
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+                handleLocation(pod,AnnotationDisplayPriorityHigh,R.drawable.new_location_pod);
+            }
+        }
+
+        JSONObject poe = annotation.optJSONObject("poe");
+        if (showPoe()) {
+
+            if (poe != null) {
+                try {
+                    poe.put("port","Place Of Deliver");
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+                handleLocation(poe,AnnotationDisplayPriorityLow,R.drawable.new_location_poe);
+            }
+        }
+
+        JSONObject por = annotation.optJSONObject("por");
+        if (showPor()) {
+
+            if (por != null) {
+                try {
+                    por.put("port","Place Of Receipt");
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+                handleLocation(por,AnnotationDisplayPriorityLow,R.drawable.new_location_por);
+            }
+        }
+
+        JSONObject origin = annotation.optJSONObject("origin");
+        if (showOrigin()) {
+
+            if (origin != null) {
+                try {
+                    origin.put("port","Origin");
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+                handleLocation(origin,AnnotationDisplayPriorityLow,R.drawable.new_location_origin);
+            }
+        }
+
+        JSONObject destination = annotation.optJSONObject("destination");
+        if (showDestination()) {
+
+            if (destination != null) {
+                try {
+                    destination.put("port","Destination");
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+                handleLocation(destination,AnnotationDisplayPriorityLow,R.drawable.new_location_destination);
+            }
+        }
+
+        JSONObject current = annotation.optJSONObject("current");
+        if (showCurrent()) {
+            if (current != null) {
+                try {
+                    current.put("port","Vessel");
+                } catch (JSONException e) {
+                    e.printStackTrace();
+                }
+                handleLocation(current,AnnotationDisplayPriorityRequired,R.drawable.ic_marker);
+            }
+        }
+
+
+        if (current != null && showCurrent()) {
+            moveToLocation(current);
+            if (mTwinkleCurrent) {
+                startTwinkle();
+            }
+        } else if (pol != null && showPol()) {
+            moveToLocation(pol);
+        } else if (pod != null && showPod()) {
+            moveToLocation(pod);
+        }
+
+
+    }
+
+    private Timer mTimer;
+    private TimerHandler mTimerHandler = new TimerHandler(this);
+    private TimerTask mTimerTask;
+    private void startTwinkle() {
+
+        if (mCurrentGoogleMarker == null && mCurrentBaiduMarker == null) {
+            return;
+        }
+
+        if (mTimer != null && mTimerTask != null) {
+            return;
+        }
+
+        mTimer = new Timer();
+        mTimerTask = new TimerTask() {
+            @Override
+            public void run() {
+                Message msg = new Message();
+                mTimerHandler.sendMessage(msg);
+            }
+        };
+        mTimer.schedule(mTimerTask,100,100);
+    }
+
+    private void stopTwinkle() {
+        if (mTimer != null) {
+            mTimer.cancel();
+        }
+        if (mTimerTask != null) {
+            mTimerTask.cancel();
+        }
+    }
+
+    private void twinkleCurrentAlpha(double alpha) {
+
+        if (mUseGoogleMap) {
+            if (mCurrentGoogleMarker != null) {
+                mCurrentGoogleMarker.setAlpha((float) alpha);
+            }
+
+        } else {
+            if (mCurrentBaiduMarker != null) {
+                mCurrentBaiduMarker.setAlpha((float) alpha);
+            }
+        }
+    }
+
+
+
+    private void moveToLocation(JSONObject location) {
+
+        if (location == null) {
+            return;
+        }
+
+        String lonStr = location.optString("lon");
+        String latStr = location.optString("lat");
+
+        if (lonStr != null && lonStr.length() > 0 && latStr != null && latStr.length() > 0) {
+
+            if (mUseGoogleMap) {
+
+                CameraPosition newLocation = new CameraPosition.Builder()
+                        .target(new com.google.android.gms.maps.model.LatLng(Float.valueOf(latStr), Float.valueOf(lonStr)))
+                        .zoom(2.5f)
+                        .bearing(0)
+                        .tilt(0)
+                        .build();
+                mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(newLocation));
+            } else {
+
+                LatLng center = new LatLng(Float.valueOf(latStr),Float.valueOf(lonStr)); //设定中心点坐标
+                MapStatus mMapStatus = new MapStatus.Builder()//定义地图状态
+                                                    .target(center)
+                                                    .zoom(2.5f)
+                                                    .build();  //定义MapStatusUpdate对象,以便描述地图状态将要发生的变化
+                MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mMapStatus);
+                mBaiduMap.getMap().setMapStatus(mMapStatusUpdate);//改变地图状态
+            }
+        }
+
+    }
+
+    private void handleLocation(JSONObject location,int priority, int imageId) {
+
+        if (location == null) {
+            return;
+        }
+
+        if (mUseGoogleMap) {
+            handleGoogleLocation(location,priority,imageId);
+        } else {
+            handleBaiduLocation(location,priority,imageId);
+        }
+
+    }
+
+    private void handleGoogleLocation(JSONObject location,int priority, int imageId) {
+
+        String port = location.optString("port");
+        String name = location.optString("name");
+        String addr = location.optString("addr");
+        String lonStr = location.optString("lon");
+        String latStr = location.optString("lat");
+
+        if (lonStr != null && lonStr.length() > 0 && latStr != null && latStr.length() > 0) {
+
+            if (port == null) {
+                port = "";
+            }
+            if (addr == null) {
+                addr = "";
+            }
+
+            com.google.android.gms.maps.model.MarkerOptions options = new com.google.android.gms.maps.model.MarkerOptions();
+            options.icon(com.google.android.gms.maps.model.BitmapDescriptorFactory.fromResource(imageId))
+                    .position(new com.google.android.gms.maps.model.LatLng(Double.parseDouble(latStr), Double.parseDouble(lonStr)))
+                    .title(name)
+                    .snippet(port + " " + addr);
+            options.zIndex(priority);
+
+            com.google.android.gms.maps.model.Marker marker = mGoogleMap.addMarker(options);
+
+            if (port.equals("Vessel")) {
+                mCurrentGoogleMarker = marker;
+            }
+
+        } else {
+            return;
+        }
+
+    }
+
+    private void handleBaiduLocation(JSONObject location,int priority, int imageId) {
+
+        String port = location.optString("port");
+        String name = location.optString("name");
+        String addr = location.optString("addr");
+        String lonStr = location.optString("lon");
+        String latStr = location.optString("lat");
+
+        if (lonStr != null && lonStr.length() > 0 && latStr != null && latStr.length() > 0) {
+
+            if (port == null) {
+                port = "";
+            }
+            if (addr == null) {
+                addr = "";
+            }
+
+            LatLng llA = new LatLng(Double.parseDouble(latStr), Double.parseDouble(lonStr));
+            BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(imageId);
+
+            Bundle extrainfo = new Bundle();
+            extrainfo.putString("detail",port + " " + addr);
+
+            MarkerOptions markeroption = new MarkerOptions().position(llA).icon(icon).zIndex(9).title(name).extraInfo(extrainfo).draggable(true);
+            markeroption.zIndex(priority);
+
+            Marker marker = (Marker) mBaiduMap.getMap().addOverlay(markeroption);
+
+            if (port.equals("Vessel")) {
+                mCurrentBaiduMarker = marker;
+            }
+
+        } else {
+            return;
+        }
+
+    }
+
+    private boolean mShowPol = true,mShowPoe,mShowPod = true,mShowPor,mShowOrigin,mShowDestination,mShowCurrent = true,mTwinkleCurrent = true;
+
+    public void setShowPol(boolean show) {
+        mShowPol = show;
+    }
+
+    public boolean showPol() {
+        return mShowPol;
+    }
+
+    public void setShowPoe(boolean show) {
+        mShowPoe = show;
+    }
+
+    public boolean showPoe() {
+        return mShowPoe;
+    }
+
+    public void setShowPod(boolean show) {
+        mShowPod = show;
+    }
+
+    public boolean showPod() {
+        return mShowPod;
+    }
+
+    public void setShowPor(boolean show) {
+        mShowPor = show;
+    }
+
+    public boolean showPor() {
+        return mShowPor;
+    }
+
+    public void setShowOrigin(boolean show) {
+        mShowOrigin = show;
+    }
+
+    public boolean showOrigin() {
+        return mShowOrigin;
+    }
+
+    public void setShowDestination(boolean show) {
+        mShowDestination = show;
+    }
+
+    public boolean showDestination() {
+        return mShowDestination;
+    }
+
+    public void setShowCurrent(boolean show) {
+        mShowCurrent = show;
+    }
+
+    public boolean showCurrent() {
+        return mShowCurrent;
+    }
+
+    public void setShipMapListener(ShipMapListener listener) {
+        mListener = listener;
+    }
+
+    public void setTwinkleCurrent(boolean twinkleCurrent) {
+        mTwinkleCurrent = twinkleCurrent;
+    }
+
+    public boolean twinkleCurrent() {
+        return mTwinkleCurrent;
+    }
+
+    public ShipMapListener getShipMapListener() {
+        return mListener;
+    }
+
+    /**
+     * Google
+     * */
+
+    @Override
+    public boolean onMarkerClick(com.google.android.gms.maps.model.Marker marker) {
+        return false;
+    }
+
+    @Override
+    public void onInfoWindowClick(com.google.android.gms.maps.model.Marker marker) {
+
+    }
+
+    @Override
+    public void onMapReady(GoogleMap googleMap) {
+
+        mGoogleMap = googleMap;
+        if (mGoogleMap != null) {
+            mGoogleMap.setInfoWindowAdapter(new ShipMapWindowInfoAdapter());
+//            mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(US));
+            mGoogleMap.setOnMarkerClickListener(this);
+            mGoogleMap.setOnInfoWindowClickListener(this);
+            if (mAnnotation != null) {
+                showShipAnnotation(mAnnotation);
+            }
+            mGoogleMap.getUiSettings().setMapToolbarEnabled(false); // 隐藏底部ToolBar 导航按钮
+            mGoogleMap.getUiSettings().setRotateGesturesEnabled(false); // 禁止旋转
+
+            // 设置缩放级别
+            CameraUpdate zoom = CameraUpdateFactory.zoomTo(mGoogleMap.getMinZoomLevel());
+            mGoogleMap.animateCamera(zoom);
+        }
+    }
+
+    /**
+     * Baidu
+     * */
+
+    @Override
+    public boolean onMarkerClick(Marker marker) {
+
+//        View viewCache = LayoutInflater.from(mContext).inflate(R.layout.ship_map_bubble, null);
+//
+//        TextView tv_title = (TextView) viewCache.findViewById(R.id.bubble_title);
+//        TextView tv_info = (TextView) viewCache.findViewById(R.id.bubble_detail);
+
+        View viewCache = ((Activity)mContext)
+                .getLayoutInflater().inflate(
+                        R.layout.marker_view, null);
+
+        TextView tv_title = (TextView) viewCache
+                .findViewById(R.id.tv_title);
+        TextView tv_info = (TextView) viewCache
+                .findViewById(R.id.tv_info);
+
+        tv_title.setText(marker.getTitle());
+        tv_info.setText(marker.getExtraInfo().getString("detail"));
+
+        LatLng ll = marker.getPosition();
+        InfoWindow mInfoWindow = new InfoWindow(BitmapDescriptorFactory.fromView(viewCache), ll, -100, this);
+        mBaiduMap.getMap().showInfoWindow(mInfoWindow);
+
+        return true;
+    }
+
+    @Override
+    public void onInfoWindowClick() {
+        mBaiduMap.getMap().hideInfoWindow();
+    }
+
+    /**
+     *
+     * */
+
+    class ShipMapWindowInfoAdapter implements GoogleMap.InfoWindowAdapter
+    {
+
+        View	mContents;
+
+        ShipMapWindowInfoAdapter() {
+            mContents = LayoutInflater.from(mContext).inflate(R.layout.ship_map_bubble, null);
+        }
+
+        @Override
+        public View getInfoContents(com.google.android.gms.maps.model.Marker marker)
+        {
+
+            String title = marker.getTitle();
+            TextView titleUi = ((TextView) mContents.findViewById(R.id.bubble_title));
+
+            if (title != null)
+            {
+                titleUi.setText(title);
+            }
+            else
+            {
+                titleUi.setText("");
+            }
+
+            String snippet = marker.getSnippet();
+            TextView snippetUi = ((TextView) mContents.findViewById(R.id.bubble_detail));
+            if (snippet != null)
+            {
+                snippetUi.setText(snippet);
+            }
+            else
+            {
+                snippetUi.setText("");
+            }
+            return mContents;
+        }
+
+        @Override
+        public View getInfoWindow(com.google.android.gms.maps.model.Marker marker)
+        {
+
+            return null;
+        }
+
+    }
+
+    public interface ShipMapListener {
+
+        void shipMapTryToZoomIn(ShipMap shipMap,boolean zoomIn);
+
+    }
+
+    private static final class TimerHandler extends Handler {
+
+        double angle = 0;
+        WeakReference<ShipMap> weakMap;
+
+        TimerHandler(ShipMap map) {
+            if (map == null) {
+                return;
+            }
+            weakMap = new WeakReference<>(map);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+
+            angle += 0.1;
+            if (angle == 3.1) {
+                angle = 0;
+            }
+            double alpha = Math.abs(Math.cos(angle));
+            ShipMap shipMap = weakMap.get();
+            shipMap.twinkleCurrentAlpha(alpha);
+        }
+    }
+}

+ 3 - 3
ApexDrivers/apexmobile/src/main/res/layout/activity_search_result.xml

@@ -5,7 +5,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="#ffffff"
-    tools:context="com.usai.apex.Result.SearchResultActivity">
+    tools:context="com.usai.apex.result.SearchResultActivity">
 
 
     <!--<View-->
@@ -29,14 +29,14 @@
             >
 
 
-            <com.usai.apex.Result.PullRefreshListView
+            <com.usai.apex.result.PullRefreshListView
                 android:id="@+id/result_table_list"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:background="#ffffff"
                 >
 
-            </com.usai.apex.Result.PullRefreshListView>
+            </com.usai.apex.result.PullRefreshListView>
 
 
         </HorizontalScrollView>

+ 1 - 1
ApexDrivers/apexmobile/src/main/res/layout/activity_test.xml

@@ -7,7 +7,7 @@
     android:layout_height="match_parent"
     tools:context=".TestActivity">
 
-    <com.usai.apex.ShipMap.ShipMap
+    <com.usai.apex.shipmap.ShipMap
         android:id="@+id/ship_map"
         android:layout_width="match_parent"
         android:layout_height="200dp"

+ 2 - 2
ApexDrivers/apexmobile/src/main/res/layout/detail_fragment_withmap.xml

@@ -12,7 +12,7 @@
         android:background="#EFEFF4"
         android:orientation="vertical">
 
-        <com.usai.apex.ShipMap.ShipMap
+        <com.usai.apex.shipmap.ShipMap
             android:id="@+id/tracking_map"
             android:layout_width="match_parent"
             android:layout_height="0dp"
@@ -22,7 +22,7 @@
             android:layout_marginTop="2dp"
             android:layout_weight="1">
 
-        </com.usai.apex.ShipMap.ShipMap>
+        </com.usai.apex.shipmap.ShipMap>
 
 
         <RelativeLayout

+ 4 - 4
ApexDrivers/apexmobile/src/main/res/layout/fragment_kpi.xml

@@ -6,19 +6,19 @@
     tools:context=".mainframe.KPIFragment">
 
     <!-- TODO: Update blank fragment layout -->
-    <com.usai.apex.KPI.KPISwipeRefresh
+    <com.usai.apex.kpi.KPISwipeRefresh
         android:id="@+id/kpi_swipe_refresh"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
          >
 
-    <com.usai.apex.KPI.KPIViewPager
+    <com.usai.apex.kpi.KPIViewPager
         android:id="@+id/kpi_pager"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-    </com.usai.apex.KPI.KPIViewPager>
+    </com.usai.apex.kpi.KPIViewPager>
 
-    </com.usai.apex.KPI.KPISwipeRefresh>
+    </com.usai.apex.kpi.KPISwipeRefresh>
 
     <ProgressBar
         style="?android:attr/progressBarStyleLarge"

+ 8 - 8
ApexDrivers/apexmobile/src/main/res/layout/kpi_cell.xml

@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
-<com.usai.apex.KPI.KPICell xmlns:android="http://schemas.android.com/apk/res/android"
-                                      android:layout_width="match_parent"
-                                      android:layout_height="match_parent"
-    android:background="#ffffff">
+<com.usai.apex.kpi.KPICell xmlns:android="http://schemas.android.com/apk/res/android"
+                           android:layout_width="match_parent"
+                           android:layout_height="match_parent"
+                           android:background="#ffffff">
 
 
     <TextView
@@ -54,7 +54,7 @@
         android:textColor="@android:color/black"
         android:text="Today 1232 15.06%"/>
 
-    <com.usai.apex.KPI.PieChartView
+    <com.usai.apex.kpi.PieChartView
         android:id="@+id/chart_view"
         android:layout_width="match_parent"
         android:layout_height="300dp"
@@ -94,7 +94,7 @@
         android:layout_marginTop="2.5dp"
         />
 
-    <com.usai.apex.KPI.KPIListView
+    <com.usai.apex.kpi.KPIListView
         android:id="@+id/item_list"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -115,7 +115,7 @@
 
         <!--</ListView>-->
 
-    </com.usai.apex.KPI.KPIListView>
+    </com.usai.apex.kpi.KPIListView>
 
 
-</com.usai.apex.KPI.KPICell>
+</com.usai.apex.kpi.KPICell>

+ 3 - 3
ApexDrivers/apexmobile/src/main/res/layout/kpi_item_button.xml

@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
-<com.usai.apex.KPI.KPIItemButton
+<com.usai.apex.kpi.KPIItemButton
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <com.usai.apex.KPI.KPIDot
+    <com.usai.apex.kpi.KPIDot
         android:id="@+id/icon_view"
         android:layout_width="10dp"
         android:layout_height="10dp"
@@ -22,4 +22,4 @@
         android:layout_marginLeft="3dp"
         />
 
-</com.usai.apex.KPI.KPIItemButton>
+</com.usai.apex.kpi.KPIItemButton>